Улучшенная валидация XML

Валидация совокупности ограничений в XML документе, используя XSLT и Java расширения

Таблицы стилей XSLT разработаны для преобразования XML документов. В совокупности с расширениями Java таблицы стилей так же могут быть мощным дополнением к схеме XML, в то время как основанная на грамматике валидация не может предусмотреть все необходимые ограничения. В этой статье Питер Хенбек демонстрирует возможность валидации документов, используя XSLT с расширениями Java и дает практические рекомендации и примеры кодов.

Питер Хенбек, консультант, IBM

Photo of Peter HenebackПетер Хенебэк (Peter Heneback) недавно получил степень магистра по компьютерным технологиям и работает в отделении IBM United Kingdom Limited в качестве консультанта по интеграции технологий Java и XML. Он также работал над реализацией веб-сервисов и grid технологий и прежде опубликовал статью по безопасности grid.



09.05.2006

Объяснение

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

Во многих случаях, логика валидации, которую вы не можете внедрить в XML схему или DTD, встроена в код приложения. Данное решение относительно легко для внедрения, но зачастую результаты негибки в реализации. Эта статья - первое исследование Schematron как возможности решения описанных выше проблем, и затем освещаются некоторые недостатки в данном подходе. Также данная статья исследует альтернативное решение, использующее хорошо обоснованные компоненты W3C стандарта в совокупности с Java расширениями и общедоступными XSLT процессорами.


Schematron

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

Рисунок 1 описывает логические ступени обработки довольно общего сценария приложений. Сначала XSLT валидирует отдельный исходный XML документ и затем трансформирует его, перед там как данный документ либо будет обработан данным приложением, либо послан внешнему приложению. Как видно на диаграмме, это становится сложной операцией при использовании комбинации XML Schema и Schematron: сначала выполнение валидации и затем преобразование заверенного документа, используя таблицу стилей XSLT. Вы можете сократить процесс путем разделения схем и преобразования схемы Schematron заранее, но это все еще требует два прохода через XSLT процессор для грамматической проверки и изучения отчета о валидации, предоставленным извлеченным преобразованием Schematron.

Рисунок 1. Валидация с помощью Schematron
Валидация с помощью Schematron

Недостатки Schematron

  • Вам нужно преобразовать схему Schematron как минимум один раз, используя основную таблицу стилей, перед тем как вы сможете использовать ее для валидации XML документа.
  • Schematron на данный момент не может предоставить отчет обратно приложению. Вам нужно запустить после валидации этап подготовки отчета либо вручную, либо автоматически.

XSLT и Java расширения

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

На рисунке 2 изображен тот же сценарий что и на рисунке 1, но с использованием XSLT с Java расширениями для выполнения валидациии преобразования на одном этапе. Вместо предоставления отчета, который вам нужно сделать отдельно, ошибка при валидации передается непосредственно в управляющее приложение в качестве объекта класса ValidationException, который является расширением класса Exception. Кроме того уменьшение количества XSLT обработчиков документа должно походить сквозь, преобразование останавливается в случае первой ошибки при валидации, что в результате препятствует нежелательной обработке недопустимых данных.

Рисунок 2. Валидация с помощью XSLT и Java расширения
Валидация с помощью XSLT и Java расширения

Простое преобразование XML документа

Для демонстрации использования XSLT и Java при валидации, я просто преобразую реестр, содержащий информацию о сотруднике, такую как имя, номер телефона, социальный статус и пол в качестве примера. Как вы позже увидите данные о социальном статусе и поле являются центром в примере ограничений. Листинг 1 содержит часть входного XML документа.

Листинг 1. Входящий XML документ
<input:staff xmlns:input="cross-field-validation-namespace">

...

  <input:employee id="1234A">
    <input:first_name>Julia</input:first_name>
    <input:last_name>Smith</input:last_name>
    <input:title>Mrs</input:title>
    <input:gender>F</input:gender>
    <input:telephones>
      <input:mobile preferred="false">0770-555 1231</input:mobile>
      <input:mobile preferred="true">0771-555 1232</input:mobile>
      <input:home preferred="false">0207-555 1233</input:home>
    </input:telephones>
  </input:employee>

...

</input:staff>

Простым преобразованием в данном примере является последовательность из имени и фамилии, содержащаяся в реестре сотрудника. Преобразование так же извлекает номер телефона, с присвоением атрибуту preferred значения true, как показано в листинге 2 .

Листинг 2. Пример преобразования данных сотрудника
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0" xmlns:xalan="http://xml.apache.org/xslt"
  xmlns:input="cross-field-validation-namespace">

  <xsl:template match="/input:staff">
    <phones>
        <xsl:apply-templates select="input:employee" />
    </phones>
  </xsl:template>

  <xsl:template match="input:employee">
    <employee>
      <name>
        <xsl:value-of select="concat(input:first_name,' ',input:last_name)" />
      </name>
      <tel>
        <xsl:value-of select="input:telephones/*[@preferred = 'true']" />
      </tel>
    </employee>
  </xsl:template>

</xsl:stylesheet>

Листинг 3 демонстрирует выходной документ, созданный путем преобразования исходного документа с помощью XSLT из листинга 2 .

Листинг 3. Выходной документ
<phones xmlns:input="cross-field-validation-namespace"
  xmlns:exception="xfield.exception.ValidationExceptionThrower"
  xmlns:xalan="http://xml.apache.org/xslt">
  <employee>
    <name>Julia Smith</name>
    <tel>0771-555 1232</tel>
  </employee>
  <employee>
    <name>John Smith</name>
    <tel>0207-555 1236</tel>
  </employee>
  <employee>
    <name>Jenny Smith</name>
    <tel>0770-555 1237</tel>
  </employee>
</phones>

Реализация простой валидации на наложенные ограничения

Два очень простых класса Java - все, что вам нужно для передачи ошибок при валидации непосредственно управляющему приложению через XSLT процессор. Для этого вам нужно создать классы ValidationException и ValidationExceptionThrower. Класс ValidationException является простым расширением стандартного класса Exception и позволяет контролировать приложение для различения между ошибок при валидации и других несоответствиях, сообщенных обработчиком. Класс ValidationExceptionThrower просто выбрасывает ValidationException, когда вызывается его метод throwException. Отделение класса обязательно из следующих соображений. Когда вы используете в XSLT расширения Java, не представляется возможным использовать обычный Java синтаксис throw для выбрасывания исключения. Вы можете только использовать Java расширения для XSLT при создании объектов и вызове методов. В листингах 4 и 5 приведен весь исходный код двух классов, необходимых для реализации Java расширений.

Листинг 4. Класс ValidationException
package xfield.exception;

public class ValidationException extends Exception{

  public ValidationException(String sMsg)
  {
    super(sMsg);
  } // конец конструктора

} // конец класса
Листинг 5. Класс ValidationExceptionThrower
package xfield.exception;

public class ValidationExceptionThrower {

  public ValidationExceptionThrower()
  {
    // Пустой
  } // конец конструктора

  public void throwException(String sMessage) throws Exception
  {
    throw new ValidationException(sMessage);
  } // конец throwException

} // конец класса

Проверка нескольких ограничений

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

Для проведения валидации поместите код преобразования в элемент <otherwise/> блок элементов <choose/> и проверяйте выполнение условия test в блоке <when/>. Если в случае валидации получится значение false, это означает, что валидация завершилась успешно и тогда исполняется код преобразования. В случае возвращения значения true, используется Java расширение для вызова метода throwException() объекта, класса ValidationExceptionThrower. Обратите внимание на добавление пространства имен с префиксом exception, в котором содержится имя класса и пакетов, содержащиеся в корневом элементе XSLT. Префикс, затем используется в качестве имени объекта для вызова метода throwException(), содержащего строку в качестве аргумента. Возвращаясь к коду Java для класса ValidationExceptionThrower, легко проследить, как выбрасывается исключение ValidationException, которое содержит строку с ошибкой, пришедшей из XSLT

Для проверки дальнейших исключений добавьте необходимые условия в элементе <when/>, которые содержат необходимые сообщения об ошибках, передаваемые в качестве аргументов методов.

Листинг 6. Простое преобразование с несколькими ограничениями
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0" xmlns:xalan="http://xml.apache.org/xslt"
  xmlns:exception="xfield.exception.ValidationExceptionThrower"
  xmlns:input="cross-field-validation-namespace">

...

<xsl:template match="input:employee">
  <xsl:choose>
    <xsl:when test="input:gender = 'M' and input:title != 'Mr' 
                 or input:gender = 'F' and input:title = 'Mr'">
      <xsl:value-of
        select="exception:throwException('Gender and title do not match')"/>
    </xsl:when>
    <xsl:otherwise>
       <employee>
         <name>
           <xsl:value-of select="concat(input:first_name,' ',input:last_name)"/>
         </name>
         <tel>
           <xsl:value-of select="input:telephones/*[@preferred = 'true']"/>
         </tel>
       </employee>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

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

Листинг 7. Подробное сообщение об ошибке
<xsl:when test="input:gender = 'M' and input:title != 'Mr' 
          or input:gender = 'F' and input:title = 'Mr'">
  <xsl:value-of select="exception:throwException(
                  concat('Gender and title do not match for employee ',
                          input:first_name,' ',input:last_name))" />
</xsl:when>

Разделение валидации и преобразования

Если необходимо разделение логики валидации и преобразования, то вы можете использовать стандартную директиву <include/> для ссылки на проведение валидации и выполнения данных проверок совместно с преобразованием. В листинге 8 показан код преобразования, где в теге <include/> содержится ссылка на файл validate.xsl. Обратите внимание на вызов шаблона validate; важно, что вызов совпадает с именем шаблона, содержащего проверки во включаемом файле, показанном в листинге 9.

Листинг 8. Логика преобразования
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0" xmlns:xalan="http://xml.apache.org/xslt"
  xmlns:input="cross-field-validation-namespace">

  <xsl:include href="validate.xsl" />

  <xsl:template match="/">
    <xsl:call-template name="validate" />
    <phones>
      <xsl:apply-templates />
    </phones>
  </xsl:template>

  <xsl:template match="input:staff/input:employee">
    <employee>
      <name>
        <xsl:value-of
          select="concat(input:first_name,' ',input:last_name)" />
      </name>
      <tel>
        <xsl:value-of
          select="input:telephones/*[@preferred = 'true']" />
      </tel>
    </employee>
  </xsl:template>

</xsl:stylesheet>
Listing 9. Логика валидации
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0" xmlns:xalan="http://xml.apache.org/xslt"
  xmlns:exception="xfield.exception.ValidationExceptionThrower"
  xmlns:input="cross-field-validation-namespace">

  <xsl:template name="validate">
    <xsl:for-each select="/input:staff/input:employee">
      <xsl:if
        test="input:gender = 'M' and input:title != 'Mr' 
               or input:gender = 'F' and input:title = 'Mr'">
        <xsl:value-of
          select="exception:throwException('Gender and title do not match')" />
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Валидация по внешним данным

XML Schema может использовать перечисления для сравнения входящих данных с предопределенным набором допустимых значений, однако ссылочные данные являются переменной, содержащей отношения, и в XML Schema не существует способа проверки этих данных. В данном примере показано решение, использующее XSLT и Java расширения для проверки переменных и внешних наборов XML данных. Заметьте, что Schematron также предоставляет данную функциональность, так как преобразуемые данные используют XSLT для осуществления валидации.

Листинг 10. Ссылочные данные
<roles>
...
  <employee id="1234A" role="A"/>
  <employee id="1234D" role="A"/>
  <employee id="1234C" role="X"/>
  <employee id="1234B" role="Z"/>
  <employee id="1234X" role="Z"/>
...    
</roles>

Внешние данные в этом примере представляют собой набор работников с соответствующими ролями. Проверяется, что все идентификаторы работников в приходящем XML существуют в ссылочном наборе данных. Для выполнения данной операции используйте функцию document() для загрузки внешних XML данных в переменную. Проверьте, что хотя бы один работник с данным идентификатором имеетсяв переменной reference, чтобы убедится в валидности данного идентификатора.

Листинг 11. Валидация внешних данных
<xsl:variable name="reference" select="document('reference.xml')" />

<xsl:template name="validate">
  <xsl:for-each select="/input:staff/input:employee">

    <xsl:if test="input:gender = 'M' and input:title != 'Mr' 
           or input:gender = 'F' and input:title = 'Mr'">
      <xsl:value-of
        select="exception:throwException(concat('Gender and title do not match 
               for employee ',input:first_name,' ',input:last_name))" />
    </xsl:if>

    <xsl:variable name="current_id" select="@id" />

    <xsl:if
      test="count($reference/roles/employee[@id = $current_id]) = 0">
      <xsl:value-of
        select="exception:throwException(concat('Invalid employee ID: ',$current_id))" />
    </xsl:if>

  </xsl:for-each>

</xsl:template>

Заключение

В заключение, Schematron является хорошим дополнением к XML Schema в случае, если вам необходимо проводить проверку по нескольким ограничениям, например, применяя XML в качестве средства подготовки отчетов. В случае необходимости высокой производительности и особенно, если после валидации необходимо использовать преобразования, то XSLT с Java расширениями является более подходящим решением.


Загрузка

ОписаниеИмяРазмер
Java и XSLT код, используемый в статьеadvanced_xml_validation.zip18KB

Ресурсы

Научиться

Получить продукты и технологии

  • Saxon: Загрузите XSLT процессор Saxon.
  • Xalan-J: Загрузите XSLT процессор Xalan-J.
  • Xerces: Загрузите XML процессор Xerces.

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=XML, Технология Java
ArticleID=164010
ArticleTitle=Улучшенная валидация XML
publish-date=05092006