Этот пост представляет собой краткую, но практическую демонстрацию проверки XML-документа на соответствие файлам Document Type Definition (DTD) и XML Schema Definition (XSD). Такая проверка необходима, чтобы гарантировать, что XML, отправленный между клиентом и сервером, на котором размещена веб-служба на основе XML, получен должным образом. И DTD, и XSD позволяют определять элементы и атрибуты, которые должен содержать XML-документ. XSD имеет то преимущество, что он сам написан на XML, что упрощает чтение. XSD также позволяет определять больше информации об элементе, например их тип данных, пространство имен и ограничения для значений. В Perl 5 есть несколько модулей для проверки XML, но я буду использовать два из пространства имен Lib :: XML.
Настройка проекта
Файлы проекта
Я буду использовать следующие файлы, содержащиеся в каталоге с именем perl5-xml-validation
, для демонстрации проверки DTD и XSD.
perl5-xml-validation/ . ├── bin │ ├── dtd_validation.pl │ └── xsd_validation.pl ├── cpanfile └── xml ├── book.xml └── schemas ├── book.dtd └── book.xsd
Создав каталог, обязательно войдите в него с помощью cd perl5-xml-validation
.
Зависимости
Откройте файл cpanfile
и перечислите следующие модули:
requires 'XML::LibXML'; requires 'Try::Tiny';
Запустите cpanm -L local --installdeps .
, чтобы установить модули. Я объясню другие файлы, когда мы начнем их использовать.
XML
XML-документ, используемый для этой демонстрации, просто содержит сведения о книге в файле ./xml/book.xml
следующим образом:
<?xml version="1.0" encoding="utf-8" ?> <book> <title>XML Validation</title> <numPages>-200</numPages> </book>
Значение «-200» для элемента numPages установлено намеренно. Причина станет ясна позже.
Проверка XML с помощью DTD
Файл DTD
Файл ./xml/schemas/book.dtd
содержит следующие определения:
<!ELEMENT book (title,author,numPages?)> <!ELEMENT title (#PCDATA)> <!ELEMENT author (#PCDATA)> <!ELEMENT numPages (#PCDATA)>
Чтобы любой XML-документ, связанный с этим DTD, был действительным, он должен содержать элементы book, title, author и, возможно, numPages . Как вы заметили, элемент author отсутствует в XML, который мы определили ранее - мы исправим это позже.
Теперь давайте проверим XML. Файл ./bin/dtd_validation.pl
содержит следующий код, который я объясню ниже.
Код
#!/usr/bin/env perl use v5.18; use warnings; use XML::LibXML; use Try::Tiny qw(try catch); my $xml_doc = XML::LibXML->load_xml(location => './xml/book.xml'); my $dtd_doc = XML::LibXML::Dtd->new('', './xml/schemas/book.dtd'); my $is_xml_valid = try { $xml_doc->validate($dtd_doc) } catch { say '==> ' . $_; return 0; }; say $is_xml_valid ? 'Valid' : 'Invalid';
Что касается проверки, приведенный выше код делает следующее:
- Загружает XML-файл с использованием
load_xml
, который возвращает объектXML::LibXML::Document
, назначенный$xml_doc
. - Затем файл DTD
book.dtd
загружается как часть построения экземпляра XML :: LibXML :: Dtd. - Наконец, сама проверка выполняется с помощью метода
validate
.
Чтобы троичное выражение в нижней части кода было выполнено, мы используем функции try
и catch
, которые экспортируются Try :: Tiny. Эти две функции будут обрабатывать любые ошибки, вызванные методом validate
. Отсутствие обработки ошибок, возникающих во время вызова validate
, приведет к остановке выполнения сценария, поэтому тернарная операция не будет выполнена.
Ошибки проверки
Теперь, если вы запустите perl ./bin/dtd_validation.pl
и не исправили XML до этого момента, вы заметите аналогичный вывод в своей оболочке, как показано ниже:
==> ./xml/book.xml:0: validity error : Element book content does not follow the DTD, expecting (title , author , numPages?), got (title numPages ) Invalid
Выходное сообщение указывает, что дочерние элементы элемента book
не соответствуют ожидаемым. Ожидается проверка title
, author
и, возможно, numPages
(в указанном порядке), но вместо этого она получила только title
и numPages
.
Исправление ошибки
Просто добавив элемент author
сразу после элемента title и присвоив ему значение, например: <author>Johny Bravo</author>
, проверка будет успешной при следующем запуске скрипта. Таким образом, будет напечатано Valid
.
Проверка XML с помощью XSD
Файл XSD
Файл ./xml/schemas/book.xsd
определяет структуру, которой должен придерживаться ./xml/book.xml
документ, а именно:
<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:element name="book"> <xs:complexType> <xs:sequence> <xs:element name = "title" type = "xs:string"/> <xs:element name = "author" type = "xs:string"/> <xs:element name = "numPages" type = "xs:positiveInteger" minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
Подобно DTD, определенному ранее, элементы title и author являются обязательными, а другие, numPages - необязательными (обозначены minOccurs="0"
). Также следует отметить, что значение numPages
должно иметь тип positiveInteger
. XSD позволяет определять множество различных типов данных, используя более богатый синтаксис, в то время как DTD этого не делает.
Код
Файл ./bin/xsd_validation.pl
содержит следующий код, который я объясню ниже:
#!/usr/bin/env perl use v5.18; use warnings; use XML::LibXML; use Try::Tiny qw(try catch); my $xml_doc = XML::LibXML->load_xml(location => './xml/book.xml'); my $xsd_doc = XML::LibXML::Schema->new(location => './xml/schemas/book.xsd'); my $is_xml_valid = try { not $xsd_doc->validate($xml_doc); } catch { say '==> ' . $_; return 0; }; say $is_xml_valid ? 'Valid' : 'Invalid';
Приведенный выше код представляет собой тот же общий процесс, что и код проверки DTD, рассмотренный ранее. Единственные два отличия реализации:
1) Модуль XML :: LibXML :: Schema используется как для загрузки, так и для проверки XML-файла.
2) Метод XML::LibXML::Schema
validate
фактически возвращает 0
, если проверка прошла успешно. Таким образом, я перед вызовом ...validate($xml)
ключевое слово not
, чтобы вернуть значение false.
Ошибки проверки
Запустите проверку XSD, используя perl ./bin/xsd_validation.pl
.
==> ./xml/book.xml:0: Schemas validity error : Element 'numPages': '-200' is not a valid value of the atomic type 'xs:positiveInteger'. Invalid
Запуск сценария должен дать результат, показанный выше. Ошибка указывает на то, что XSD ожидает положительное целочисленное значение для numPages, но на самом деле XML содержит отрицательное целое число, в данном случае «-200».
Исправление ошибки
Вы, наверное, меня опередили, но просто изменив значение numPages
с -200 на 200 и снова запустив скрипт, вы получите Valid
.
Заключение
Для проверки XML-документа с помощью двух обсуждаемых модулей XML :: LibXML потребовались только два объекта: вызов метода validate и использование try и catch для обработки любых возможных ошибок.
Если вас интересует проверка, выполненная с помощью тестов Perl, нажмите здесь, чтобы увидеть репозиторий Github, содержащий код для этой статьи.
Спасибо, что прочитали эту статью! Не стесняйтесь оставлять аплодисменты👏, а также рекомендовать эту статью другим.