
Этот пост представляет собой краткую, но практическую демонстрацию проверки 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, содержащий код для этой статьи.
Спасибо, что прочитали эту статью! Не стесняйтесь оставлять аплодисменты👏, а также рекомендовать эту статью другим.