>
<!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.
Классы SAX2XMLReader, DOMBuilder, DOMWriter и XercesDOMParser поддерживают ряд дополнительных функций. В SAX2XMLReader и DOMBuilder вы можете включать эти функции, используя методы setFeature() и setProperty(). Первый метод принимает строку и булево значение: второй метод принимает строку и void*. Запросить включенные функции можно с помощью методов getFeature() и getProperty(). Для удобства в Xerces предусмотрены константы с именами фикций и свойств. Класс DOMWriter поддерживает setFeature(), но не поддерживает setProperty(). Класс XercesDOMParser поддерживает оба метода, в нем предусмотрены отдельные методы по установке и получению каждой функции. В документации Xerces вы найдете полный список поддерживаемых дополнительных функций.
Смотри также
Рецепт 14.6.
14.6. Проверка документа XML на соответствие схеме
Проблема
Требуется подтвердить соответствие документа XML схеме, представленной в рекомендациях XML Schema 1.0.
Решение
Используйте библиотеку Xerces совместно с программным интерфейсом SAX2 или с парсером DOM.
Подтверждение соответствия документа XML схеме с использованием программного интерфейса SAX2 осуществляется точно так же, как подтверждение достоверности документа, содержащего DTD, когда схема содержится внутри целевого документа или когда на нее делается ссылка в этом документе. Если требуется проверить документ XML на соответствие внешней схеме, вы должны вызвать метод парсера setProperty() для включения режима подтверждения внешней схемы. В качестве первого аргумента setProperty() необходимо использовать XMLUni::fgXercesSchemaExternalSchemaLocation или XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation в зависимости оттого, используется или нет в схеме целевое пространство имен. Второй аргумент должен определять место расположения схемы, представленное значением типа const XMLCh*. Не забудьте привести тип второго аргумента к void*, как это сделано в рецепте 14.5.
Подтверждение соответствия документа XML схеме на основе использования XercesDOMParser выполняется аналогично подтверждению достоверности документа DTD, когда схема содержится внутри целевого документа или когда на нее делается ссылка в этом документе. Единственное отличие заключается в явном подключении средств поддержки схемы и пространства имен, как показано в примере 14.15.
Пример 14.15. Включение режима подтверждения схемы при использовании XercesDOMParser
XercesDOMParser parser;
parser.setValidationScheme(XercesDOMParser::Val_Always);
parser.setDoSchema(true);
parser setDoNamespaces(true);
Если требуется проверить документ XML на соответствие внешней схеме, имеющей целевое пространство имен, вызовите метод парсера setExternalSchemaLocation(), передавая в качестве аргумента место расположения вашей схемы. Если требуется проверить документ XML на соответствие внешней схеме, не имеющей целевого пространства имен, вызовите метод парсера setExternalNoNamespaceSchemaLocation().