Выбрать главу

<!ELEMENT animal (name, species, dateOfBirth,

                  veterinarian, trainer) >

<!ELEMENT name (#PCDATA)>

<!ELEMENT species (#PCDATA)>

<!ELEMENT dateOfBirth (#PCDATA)>

<!ELEMENT veterinarian EMPTY>

<!ELEMENT trainer EMPTY>

<!ATTLIST veterinarian

 name  CDATA #REQUIRED

 phone CDATA #REQUIRED

>

<!ATTLIST trainer

 name  CDATA #REQUIRED

 phone CDATA #REQUIRED

>

Пример 14.12. Модифицированный файл animals.xml, содержащий DTD

<?xml version="1.0" encodings "UTF-8"?>

<!-- Животные цирка Feldman Family Circus с DTD. -->

<!DOCTYPE animalList SYSTEM "animals.dtd">

 <!- так же, как в примере 14.1 -->

</animalList>

Пример 14.13. Проверка документа animals.xml на соответствие DTD с использованием программного интерфейса SAX2

/*

* Операторы #include из примера 14.8, кроме включения вектора <vector> который

здесь не нужен

*/

#include <stdexcept> // runtime_error

#include <xercesc/sax2/DefaultHandler.hpp>

using namespace std;

using namespace xercesc;

/*

 * Определить XercesInitializer, как это сделано в примере 14.8, и

 * CircusErrorHandler, как это сделано в примере 14.7

 */

int main() {

 try {

  // Инициализировать Xerces и получить парсер

  SAX2 XercesInitializer init;

  auto_ptr<SAX2XMLReader>

   parser(XMLReaderFactory::createXMLReader());

  // Включить режим проверки

  parser->setFeature(XMLUni::fgSAX2CoreValidation, true);

  // Зарегистрировать обработчик ошибок для получения уведомлений о

  // нарушениях DTD

  CircusErrorHandler error;

  parser->setErrorHandler(&error);

  parser->parse("animals.xml");

 } catch (const SAXException& e) {

  cout << "xml error " << toNative(e.getMessage()) << "\n";

  return EXIT_FAILURE;

 } catch (const XMLException& e) {

  cout << "xml error " << toNative(e.getMessage()) << "\n";

  return EXIT_FAILURE;

 } catch (const exception& e) {

  cout << e.what() << "\n";

  return EXIT_FAILURE;

 }

}

Пример 14.14. Проверка документа animals.xml на соответствие DTD animals.dtd с использованием парсера XercesDOMParser

#include <exception>

#include <iostream>  // cout

#include <stdexcept> // runtime_error

#include <xercesc/dom/DOM.hpp>

#include <xercesc/parsers/XercesDOMParser.hpp>

#include <xercesc/sax/HandlerBase.hpp>

#include <xercesc/util/PlatformUtils.hpp>

#include "xerces_strings.hpp" // Пример 14.4

using namespace std;

using namespace xercesc;

/*

 * Определить XercesInitializer, как это сделано в примере 14.8

 * и CircusErrorHandler, как это сделано в примере 14.7

 */

int main() {

 try {

  // Инициализировать Xerces и сконструировать DOM-парсер.

  XercesInitializer init;

  XercesDOMParser parser;

  // Включить режим проверки DTD

  parser.setValidationScheme(XercesDOMParser::Val_Always);

  // Зарегистрировать обработчик ошибок для получения уведомлений о

  // нарушениях схемы

  CircusErrorHandler handler;

  parser.setErrorHandler(&handler);

  // Выполнить синтаксический анализ вместе с проверкой.

  parser.parse("animals.xml");

 } catch (const SAXException& e) {

  cout << "xml error: " << toNative(e.getMessage()) << "\n";

  return EXIT_FAILURE;

 } catch (const XMLException& e) {

  cout << "xml error: " << toNative(e.getMessage()) << "\n";

  return EXIT_FAILURE;

 } catch (const exception& e) {

  cout << e.what() << "\n";

  return EXIT_FAILURE;

 }

}

Обсуждение

Определения DTD обеспечивают простой способ наложения ограничений на документ XML. Например, в DTD можно указать, какие элементы допускаются в документе, какие атрибуты может иметь элемент и может ли конкретный элемент содержать дочерние элементы, текст или и то и другое. Можно также накладывать ограничения на тип, порядок следования и количество дочерних элементов, а также на значения атрибутов.

DTD предназначены для определения подмножества правильно сформированных документов XML, которые характерны для определенной прикладной области. Например, в примере 14.1 важно то, что каждый элемент animal имеет дочерние элементы name, species, dateOfBirth, veterinarian и trainer, а элементы name, species и dateOfBirth содержат только текст в то время, как элементы veterinarian и trainer имеют атрибуты name и phone. Более того, элемент animal не должен иметь атрибут phone, а элемент veterinarian не должен иметь дочерний элемент species.

DTD в примере 14.11 накладывает ограничения различного типа. Например, приведенное ниже объявление элемента устанавливает необходимость наличия в элементе животного дочерних элементов name, species, dateOfBirth, veterinarian и trainer, задаваемых именно в этом порядке.

<!ELEMENT animal (name, species, dateOfBirth,

                  veterinarian, trainer) >

Аналогично приведенное ниже объявление атрибута указывает на то, что элемент trainer должен иметь атрибуты name и phone, а отсутствие в DTD объявлений других атрибутов для элемента дрессировщика говорит о том, что этот элемент может иметь только два атрибута.

<!ATTLIST trainer

 name  CDATA #REQUIRED

 phone CDATA #REQUIRED

>

Документ XML, который содержит DTD и удовлетворяет его требованиям, называют достоверным (valid). XML-парсер, который обнаруживает не только синтаксические ошибки, но и проверяет достоверность документа XML. называется подтверждающим парсером (validating parser). Хотя парсеры SAX2XMLReader и XercesDOMParser не являются по умолчанию подтверждающими парсерами, в каждом из них предусмотрена функция подтверждения достоверности, которая может подключаться так, как это сделано в примерах 14.13 и 14.14. Аналогично парсер DOMBuilder, описанный в рецепте 14 4, может проверять достоверность документа XML, вызывая свой метод setFeaturе() с аргументами fgXMLUni::fgDOMValidation и true.