Консалтинг и автоматизация в области управления
эффективностью банковского бизнеса

Журнал ВРМ World

Проверка допустимости с помощью Schematron

Schematron - это язык описания схемы, который можно использовать для проверки допустимости XML-документа. Предполагая, что читатель знаком с XML 1.0, DTDs, XSLT и XPath, я остановлюсь на вопросах проверки допустимости с помощью Schematron.

Зачем нужны схемы

Схемы XML требуются для того, чтобы передавать в компьютер структуру типа XML-документа. Рассмотрим следующие два фрагмента XML-кода:

<vehicle name='Harley Davidson' type='motorcycle'>
   <wheel name='Front Tire'/>
   <wheel name='Rear Tire'/>
   <HeadLight name='Front Lamp' />
   <kickstand/>
</vehicle>

<vehicle name='Mitsubishi 3000 GT' type='motorcycle'>
   <wheel name='Front Right Tire'>
   <wheel name='Front Left Tire'>
   <wheel name='Rear Right Tire'>
   <wheel name='Rear Left Tire'>
   <HeadLight name='Front Right lamp'>
   <HeadLight name='Front Left lamp'>
   <SunRoof/>
</vehicle>

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

<vehicle name='Harley Davidson' type='motorcycle'>
   <wheel name='Front Tire'/>
   <SunRoof/>
</vehicle>

Совершенно понятно, что у обычного мотоцикла (motorcycle) - два колеса и нет крыши с люком (sunroof). Тем не менее, для части программной логики необходима схема XML, по которой проверяется допустимость конкретного XML-документа.

Проверка допустимости - ключевой этап предполагаемой и эффективной обработки реальных XML-документов. Знание структуры XML-документа избавляет разработчика от необходимости вводить в приложение дополнительную логику. Как только становится известно, что документ принадлежит определенному классу, можно сделать ряд предположений о его структуре.

Описания типа документа (DTDs)

Описания типа документа (DTDs, Document Type Definitions) были первым стандартным механизмом, используемым для проверки допустимости, и, по большому счету, остаются им по сей день. Они определяют роли и структуру XML-элементов и описываются с помощью синтаксиса, отличающегося от применяемого в XML. В отношении проверки допустимости они полагаются на пост-обработку. Для простых схем XML - DTDs вполне достаточно. Однако, DTDs - это шаг назад, если говорить о направлении развития XML-технологий: DTDs не поддерживают пространства имен и используют синтаксис, отличный от принятого в XML.

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

Большинство XML-технологий (RDF, XSLT и Xlink), а также языки описания схем (RELAX, XML Schema, SOX) представляются как XML. Это единообразие способствует легкости в изучении этих подходов. Это значит, что разработчики могут применять существующие инструментальные средства XML. Таким образом, DTDs - это помеха для программистов, поскольку для того, чтобы определять свои схемы XML, они должны изучить дополнительный синтаксис. Но этим дело не заканчивается - использование DTDs имеет более серьезные ограничения.

DTDs в некоторой степени ограничены в выразительности; следовательно, их невозможно использовать для проверки допустимости некоторых структур XML-документа. Например, для следующего XML-документа:

<TennisMatch tournament='US Open'>
 <Competition type='Doubles' gender='Female'>
   <Player name='Venus Williams'/>
   <Player name='Serena Williams'/> ....
   <Player name='Martina Hingis'/>
   <Player name='Lindsey Davinport'/>
 </Competition>
</TennisMatch>


с DTD было бы невозможно объявить, что элемент Competition может иметь только четное число элементов Player. Рассмотрим еще один пример:

<shortStory author='AUTHOR1'>
  <character name='CHARACTER1'/>
  <character name='CHARACTER2'>
</shortStory>

<anthology author='AUTHOR1'>
  <shortStory>
    <character name='CHARACTER1'/>
    <character name='CHARACTER2'>
  </shortStory>
</anthology>

Для подобного документа в DTD невозможно задание следующего ограничения: элемент shortStory может содержать атрибут author, только если он не является наследником элемента antholog.

Эти недостатки DTD не остались незамеченными: сейчас специалисты консорциума W3C разрабатывают язык XML Schema (в настоящий момент он имеет статус рабочей Рекомендации W3C), который обладает большей выразительностью и мощью по сравнению с DTDs. Язык XML Schema является XML-приложением и, очевидно, станет стандартным способом формального объявления схем XML. Тем не менее, стоит обратить внимание на RELAX (REgular LAnguage description for XML, Регулярный язык описания XML), альтернативный язык описания схемы, разработанный Мурата Макото (Murata Makoto). Технический отчет об этом языке был представлен на рассмотрение Международной организации стандартизации (International Standardization Organization). В предыдущих статьях XML.com уже рассказывалось о RELAX. Пока XML Schema не будет одобрен как стандарт описания схемы, используются другие альтернативы, такие как RELAX и Schematron (они будут применяться и после того, как это произойдет). По моему мнению, Schematron - наиболее обещающий из них.

Введение в Schematron

Созданный Риком Джелиффом (Rick Jelliffe), Schematron определяет правила и проверки, которые применяются к конкретному XML-документу. В Schematron реализован уникальный подход в отношении схем в том смысле, что он сосредотачивается на проверке допустимости конкретных документов, а не на объявлении схемы (в отличие от других языков описания схем).

Для описания этих правил и проверок Schematron практически целиком полагается на модели запросов XPath. Для обработки очень сложных XML-документов с помощью всего лишь подмножества XPath можно создавать мощные таблицы стилей XSLT.

Прежде чем углубиться в изучение Schematron, давайте посмотрим, как легко использовать XSLT для проверки XML-документов. Вернемся к предыдущему примеру:

<shortStory author='AUTHOR1'>
  <character name='CHARACTER1'/>
  <character name='CHARACTER2'>
</shortStory>

<anthology author='AUTHOR1'>
  <shortStory>
    <character name='CHARACTER1'/>
    <character name='CHARACTER2'>
  </shortStory>
</anthology>


Можно создать шаблон, который будет возвращать "Invalid XML" ("Недопустимый XML"), если элемент shortStory имеет атрибут author, когда он содержится в элементе anthology.

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl=
 "http://www.w3.org/1999/XSL/Transform">
  <xsl:template match='shortStory'>
    <xsl:if test='../anthology and @author'>
      Invalid XML
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

Нетрудно придумать другие комбинации шаблонов, которые будут проверять более сложные структуры XML. В сущности, именно так и работает Schematron. Он берет описание схемы Schematron (на XML), которое определяет ограничения. Таблица стилей Schematron XSLT превращает это в другую таблицу стилей, преобразуя с помощью этой результирующей таблицей стилей конкретный документ, а затем выполняет проверку допустимости этого документа.

Структура документа Schematron

XML-документ Schematron состоит из элемента schema в пространстве имен Schematron: http://www.ascc.net/xml/schematron. Элемент schema содержит один или более элементов pattern. Элементы pattern позволяют пользователю логически группировать ограничения схемы. Вот несколько примеров логической группировки: Text Only Elements (Только текстовые элементы), Valid Root Element (Допустимый корневой элемент), Check for ID Attribute (Атрибут проверки ID).

Элементы pattern имеют атрибут name. Они также имеют атрибут see, который обращается к URL за пользовательской документацией по этой схеме.

Правила (Rules)

Элементы rule определяют совокупность ограничений, накладываемых на частный контекст конкретного документа (например, на элемент или совокупность элементов). Это очень похоже на шаблоны XSLT, которые инициируются по отношению к узлу или группе узлов, возвращенных выражением XPath. В таблице стилей XSLT, которую мы определили выше:

<xsl:template match='shortStory'>

атрибут match заставляет XSLT-процессор оценивать выражение XPath shortStory, а затем подвергать обработке шаблон, относящийся к элементу shortStory. Содержимое элемента проверки (rule) функционирует в пределах контекста элементов, сопоставленных по его атрибуту context.

Элементы проверки могут содержать элементы assert и report. Эти элементы обрабатываются в зависимости от оценки XPath их атрибута test. Единственное различие между ними заключается в том, что элементы assert подвергаются обработке, если выражение XPath выдает ложь (false), а элементы report - если получено значение истина (true) (В общем, элемент assert задуман для определения ошибок; элемент report можно использовать для сообщения о положительных свойствах конкретного документа).

Механизм assert/report подобен элементу XSLT xsl:if из рассмотренной выше таблицы стилей, - он также имеет атрибут test, который определяет, обрабатывается ли в результирующем XML-дереве содержимое элемента xsl:if.

Обратите внимание на то, что узел может быть только контекстом одного правила (первое правило сопоставления, с которым сталкивается процессор) в пределах модели. Однако, узел может много раз сопоставляться в пределах различных моделей. Таким образом, группировки моделей имеют огромное значение. Каждое сопоставление контекстного узла может считаться отдельным ограничением.

С помощью этих элементов авторы схем Schematron могут обеспечивать функциональную (и понятную человеку) обратную связь в отношении недопустимых XML-документов. Благодаря обратной связи, определяемой пользователем, уникальный подход Schematron является более мощным механизмом объявления схем по сравнению с другими языками описания схем.

Наконец, элементы assert и report имеют элемент name, который применяется для подстановки в выходной поток имени элемента. Этот элемент name имеет факультативный атрибут path, который возвращает узел, имя тега которого будет вставлено на место элемента name. Если атрибут path не указан, вместо него используется имя текущего контекстного узла. Этот элемент часто используется элементами assert и report для идентификации имени тега элемента-нарушителя (offending element) в пределах верификационного сообщения.

Усиленный XPath

Мощь Schematron - в использовании выражений XPath. В результате, к XML-документам можно обращаться с запросами по мощным моделям, обеспечивая проверку допустимости ограничений, которые невозможно объявить в DTDs. Давайте рассмотрим выделенные блоки модели "Структурная проверка допустимости" (Structural Validation) в RSS Schematron (которую можно скачать).

<?xml version="1.0"?>
<schema xmlns="http://www.ascc.net/xml/schematron">
 <pattern name="Structural Validation">
  <rule context="rss">
    <assert test="@version">
      An RSS version identifier should be supplied
    </assert>

Здесь контекст правила (rule context) - элемент rss. Элемент assert с помощью выражения XPath @version проверяет присутствие атрибута version. В случае, если сопоставляемый элемент rss не имеет атрибута version, обрабатывается содержимое элемента assert, то есть, в выходной таблице стилей создается текстовое сообщение, уведомляющее пользователя о необходимости идентификатора version.

<report test="@version != 0.91">
  This Schematron validator is for RSS 0.91 only
</report>

В этом примере содержимое элемента report обрабатывается только тогда, когда выражение test выдает значение истина. В этом случае, Schematron проверяет номер версии отличный от 0.91.

<assert test="count(channel) = 1">
  An RSS element can only contain a single channel element
</assert>

А это более сложное ограничение. Оно проверяет, имеет ли контекстный узел (в данном случае /rss) только один элемент channel. Выражение test использует функцию XPath count, одну из многих мощных функций XPath, доступных в Schematron.

<rule context="title|description|link">
  <assert test="parent::channel or parent::image
      or parent::item or parent::textinput">
    A <name/> element can only be contained with a
    channel, image, item or textinput element.
  </assert>
  <report test="child::*">
    A <name/> element cannot contain sub-elements,
    remove any additional markup
  </report>
</rule>

Контекстный узел элемента rule в этом примере - элемент title, description, либо link. Элемент assert контролирует, что родитель контекстного узла - channel, image, item, либо textinput. Для проверки используется осевой спецификатор (axis specifier) parent.

Элемент report обеспечивает, что ни элемент title, description, ни link не содержат дочернего элемента. Для этого используется осевой спецификатор child.

rule context="image">
 ...
  <assert test="count(width) = count(height)">
    Width and Height elements should be balanced
  </assert>
</rule>

Вот еще один пример использования функции count для установки ограничения. И еще один случай, когда DTD не смог бы выразить это ограничение для проверки допустимости.

<rule context="width">
  <assert test="preceding::height or following::height">
    A width should be accompanied by a height
  </assert>
</rule>

Наконец, из этого примера просто видно, что Schematron может проверять. Элемент assert использует осевые спецификаторы XPath preceding и following для того, чтобы установить, сопровождает ли элемент height элемент width в случае появления последнего. И снова Schematron прибегает к мощным функциям XPath для описания ограничений, накладываемых на схему.

Запуская схему Schematron

После того как схема Schematron определена, таблица стилей Schematron XSLT используется для преобразования этой схемы в верифицирующую таблицу стилей. Затем в целях проверки допустимости эта таблица стилей может применяться к XML-документам. Существует ряд таких таблиц Schematron, каждая из которых обладает определенной функциональностью. Вы можете познакомиться с этими таблицами стилей, заглянув на web-сайт Schematron.

Schematron-basics генерирует таблицу стилей, которая просто возвращает текстовый выход Schematron (текст состоящий из элементов assert и report). Как видно из названия, это самая простая таблица стилей.

Schematron-message генерирует верифицирующую таблицу стилей, которую можно использовать XSLT-процессором, который знает, как обрабатывать элементы xml:message и посылать их в стандартный вывод. Эта таблица используется главным образом совместно с интерактивными редакторами, такими как Emacs и XED, для проверки допустимости конкретного XML-документа во время его редактирования.

Schematron-report и schematron-pretty генерируют верифицирующие таблицы стилей, которые формируют форматированные сообщения HTML. Schematron-report создает выход в виде двух кадров. Первый кадр содержит связанные гиперссылкой сообщения об ошибке, организованные моделью. Нижний кадр отображает фрагменты-нарушители в исходном XML, соответствующие выбранному сообщению об ошибке. Эта таблица стилей позволяет интерактивно анализировать ошибки проверки допустимости конкретного XML-документа, она особенно удобна, когда исходный XML велик для того, чтобы его просматривать отдельно.

Наконец, schematron-xml генерирует XML-сообщения о проверке допустимости. Эти элементы имеют атрибут location, содержащий выражения XPath, которые оценивают элементы-нарушители. Эта таблица стилей Schematron позволяет пользователям включать проверку допустимости Schematron в существующую логику XML-приложений.

Кроме примера RSS Schematron имеется еще несколько широко используемых схем XML, написанных на Schematron, например, схема представленная на ресурсе Дэна Коннолли (Dan Connolly) Web Content Accessibility Checking Service. Это сервис, который, используя пример WAI (который можно скачать с Web-страницы Рика Джелиффа), проверяет Web-страницы в соответствие с Инструкциями по доступности Web-содержимого (Web Content Accessibility Guidelines).

Ресурсы: