14.6. Проверка документа XML на соответствие схеме

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().

Аналогично для проверки документа XML на соответствие схемы с использованием DOMBuilder включите функцию подтверждения достоверности следующим образом.

DOMBuilder* parser = ...;

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

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

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

Для подтверждения соответствия документа внешней схеме с использованием DOMBuilder установите свойство XMLUni::fgXercesSchemaExternalSchemaLocation или XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation в значение места расположения схемы.

Например, пусть требуется проверить документ animals.xml из примера 14.1, используя схему из примера 14.16. Один из способов заключается в добавлении ссылки на схему в документ animals.xml, как показано в примере 14.17. После этого вы можете проверить документ, используя программный интерфейс SAX2, как показано в примере 14.13, или используя DOM, как показано в примере 14.14 с учетом модификаций, выполненных в примере 14.15.

Пример 14.16. Схема animals.xsd для файла animals.xml

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

<!- Схема для животных цирка Feldman Family Circus -->

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"

 elementFormDefault="qualified">

 <xsd:element name="animalList">

  <xsd:complexType>

   <xsd:sequence>

    <xsd:element name="animal" minOccurs="0" maxOccurs="unbounded">

     <xsd:complexType>

       <xsd:sequence>

        <xsd:element name="name" type="xsd:string" />

        <xsd:element name="species" type="xsd:string"/>

        <xsd:element name="dateOfBirth" type="xsd:date"/>

        <xsd:element name="veterinarian" type="contact"/>

        <xsd:element name="trainer" type="contact"/>

       </xsd:sequence>

      </xsd:complexType>

     </xsd:element>

    </xsd:sequence>

   </xsd:complexType>

  </xsd:element>

 <xsd:complexType name="contact">

  <xsd:attribute name="name" type="xsd:string"/>

  <xsd:attribute name="phone" type="phone"/>

 </xsd:complexType>

 <xsd:simpleType name="phone">

  <xsd:restriction base="xsd:string">

   <xsd:pattern value="(d{3})d{3}-d{4}"/>

  </xsd:restriction>

 </xsd:simpleType>

</xsd:schema>

Пример 14.17. Модифицированный файл animals.xml, содержащий ссылку на схему

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

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

<animalList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 xsi:noNamespaceSchemalocation="animals.xsd">

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

</animalList>

Можно поступить по-другому: опустить ссылку на схему и включить режим подтверждения соответствия документа внешней схеме. Пример 14.18 показывает, как это можно сделать при использовании парсера DOM.

Пример 14.18. Подтверждение соответствия документа XML внешней схеме, используя DOM

/*

 * Те же самые операторы #include, которые использовались в примере 14.14

 */

using namespace std;

using namespace xercesc;

/*

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

 * и CircusErorHandler, как в примере 14.7

 */

int main() {

 try {

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

  XercesInitializer init;

  XercesDOMParser parser;

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

  parser.setValidationScheme(XercesDOMParser::Val_Always);

  parser.setDoSchema(true); parser.setDoNamespaces(true);

  parser.setExternalNoNamespaceSchemaLocation(

   fromNative("animals.xsd").c_str());

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

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

  CircusErrorHandler handler;

  parser.setErrorHandler(&handler);

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

  // схеме.

  parser parse("animals.xml");

 } catch (const SAXException& e) {

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

  return EXIT_FAILURE;

 } catch (const XMLException& e) {

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

  return EXIT_FAILURE;

 } catch (const exception& e) {

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

  return EXIT_FAILURE;

 }

}

Обсуждение

Подобно определениям DTD, рассмотренным в предыдущем рецепте, схемы накладывают ограничения на документы XML. Схема предназначена для определения подмножества правильно сформированных документов, характерных для определенной прикладной области. Однако схемы имеют три отличия от определений DTD. Во-первых, концепция DTD и связанное с ней понятие подтверждения достоверности (validity) определены в самой спецификации XML, в то время как схемы описаны в другой спецификации — в рекомендациях XML Schema. Во-вторых, сами схемы являются правильно сформированными документами XML, в то время как для описания определений DTD используется специальный синтаксис, продемонстрированный в примере 14.11. В-третьих, схемы существенно более выразительны, чем определения DTD. Из-за двух последних отличий считается, что схемы превосходят определения DTD.

Например, в DTD из примера 14.11 можно было лишь потребовать, чтобы элементы veterinarian имели ровно два атрибута, name и phone, значения которых состоят из символов. Напротив, схема в примере 14.16 требует, чтобы значение атрибута phone, кроме того, соответствовало регулярному выражению (d{3})d{3}-d{4}, т.е. чтобы оно имело вид (ddd)xxx-dddd, где d может быть любой цифрой. Аналогично обстоит дело с элементом dateOfBirth: если в DTD можно было только потребовать, чтобы этот элемент имел текстовое значение, то схема требует, чтобы текстовое значение имело вид yyyy-mm-dd, где yyyy задается в диапазоне от 0001 до 9999, mm — от 01 до 12, a dd — от 01 до 31.

Способность накладывать эти дополнительные ограничения создает большое преимущество, поскольку позволяет часть программистской работы переложить на парсер.

Смотри также

Рецепт 14.5.