Ten post jest krótką, ale praktyczną demonstracją sprawdzania poprawności dokumentu XML względem plików „Definicja typu dokumentu” (DTD) i „Definicja schematu XML” (XSD). Taka weryfikacja jest konieczna, aby mieć pewność, że kod XML przesyłany pomiędzy klientem a serwerem obsługującym usługę sieci Web opartą na formacie XML zostanie odebrany zgodnie z oczekiwaniami. Zarówno DTD, jak i XSD umożliwiają zdefiniowanie elementów i atrybutów, jakie powinien zawierać dokument XML. XSD ma tę zaletę, że jest napisany w formacie XML, co ułatwia jego czytanie. XSD umożliwia także zdefiniowanie większej ilości informacji o elemencie — takich jak typ danych, przestrzeń nazw i ograniczenia dotyczące wartości. Istnieje kilka modułów do sprawdzania poprawności XML w Perlu 5, ale ja użyję dwóch z przestrzeni nazw Lib::XML.

Konfiguracja projektu

Pliki projektu

Będę używać następujących plików znajdujących się w katalogu o nazwie perl5-xml-validation, aby zademonstrować walidację zarówno DTD, jak i XSD.

perl5-xml-validation/
.
├── bin
│   ├── dtd_validation.pl
│   └── xsd_validation.pl
├── cpanfile
└── xml
    ├── book.xml
    └── schemas
        ├── book.dtd
        └── book.xsd

Po utworzeniu katalogu pamiętaj o wprowadzeniu go za pomocą cd perl5-xml-validation.

Zależności

Otwórz plik cpanfile i wypisz następujące moduły:

requires 'XML::LibXML';
requires 'Try::Tiny';

Uruchom cpanm -L local --installdeps ., aby zainstalować moduły. Pozostałe pliki wyjaśnię, gdy zaczniemy z nich korzystać.

XML-a

Dokument XML użyty w tej demonstracji zawiera po prostu szczegóły książki w pliku ./xml/book.xml w następujący sposób:

<?xml version="1.0" encoding="utf-8" ?>
<book>
    <title>XML Validation</title>
    <numPages>-200</numPages>
</book>

Wartość „-200” dla elementu numPages została ustawiona celowo. Powód powinien być jasny później.

Walidacja XML za pomocą DTD

Plik DTD

W pliku ./xml/schemas/book.dtd znajdują się następujące definicje:

<!ELEMENT book (title,author,numPages?)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT numPages (#PCDATA)>

Aby jakikolwiek dokument XML powiązany z tym DTD był ważny, musi zawierać elementy book, title, author i opcjonalnie numPages . Jak zauważysz, w zdefiniowanym wcześniej kodzie XML brakuje elementu author — poprawimy to później.

Teraz zweryfikujmy kod XML. Plik ./bin/dtd_validation.pl zawiera następujący kod, który wyjaśnię poniżej.

Kodeks

#!/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';

Jeśli chodzi o walidację, powyższy kod wykonuje następujące czynności:

  • Ładuje plik XML za pomocą load_xml, co zwraca obiekt XML::LibXML::Document przypisany do $xml_doc.
  • Następnie ładowany jest plik DTD book.dtd jako część konstrukcji instancji XML::LibXML::Dtd.
  • Na koniec sama walidacja odbywa się przy użyciu metody validate.

Aby wykonać trójskładnikowe wyrażenie na dole kodu, używamy funkcji try i catch, które są eksportowane przez Try::Tiny. Te dwie funkcje obsłużą wszelkie błędy zgłoszone przez metodę validate. Brak obsługi błędów, które wystąpią podczas wywołania validate spowoduje zatrzymanie wykonywania skryptu, w związku z czym operacja trójskładnikowa nie zostanie wykonana.

Błędy walidacyjne

Teraz, jeśli uruchomisz perl ./bin/dtd_validation.pl i nie poprawiłeś wcześniej kodu XML, zauważysz podobne wyniki w powłoce, jak pokazano poniżej:

==> ./xml/book.xml:0: validity error : Element book content does not follow the DTD, expecting (title , author , numPages?), got (title numPages )
Invalid

Komunikat wyjściowy wskazuje, że elementy podrzędne elementu book nie są zgodne z oczekiwaniami. Podczas walidacji oczekiwano title, author i opcjonalnie numPages (w tej kolejności), ale zamiast tego otrzymano title i numPages.

Naprawianie błędu

Samo dodanie elementu author tuż po elemencie title i przypisanie mu wartości, na przykład: <author>Johny Bravo</author>, zapewni pomyślne sprawdzenie poprawności przy następnym uruchomieniu skryptu. W związku z tym zostanie wydrukowane Valid.

Walidacja XML za pomocą XSD

Plik XSD

Plik ./xml/schemas/book.xsd określa strukturę, jakiej powinien przestrzegać dokument ./xml/book.xml w następujący sposób:

<?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>

Podobnie jak w zdefiniowanym wcześniej DTD, elementy title i author są obowiązkowe, a drugi numPages jest opcjonalny (oznaczany przez minOccurs="0"). Należy również zauważyć, że oczekuje się, że wartość numPages będzie typu positiveInteger. XSD umożliwia definiowanie wielu różnych typów danych przy użyciu bogatszej składni, podczas gdy DTD tego nie robi.

Kodeks

Plik ./bin/xsd_validation.pl zawiera następujący kod, który wyjaśniam poniżej:

#!/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';

Powyższy kod jest tym samym ogólnym procesem, co kod weryfikacyjny DTD przedstawiony wcześniej. Jedyne dwie różnice w implementacji to:

1) Moduł XML::LibXML::Schema służy zarówno do ładowania, jak i sprawdzania poprawności pliku XML.

2) Metoda XML::LibXML::Schema validate faktycznie zwraca 0, gdy walidacja zakończy się pomyślnie. W związku z tym poprzedzam wywołanie ...validate($xml) słowem kluczowym not, aby jego fałszywa wartość zwracana była prawdziwa.

Błędy walidacyjne

Uruchom weryfikację XSD za pomocą 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

Uruchomienie skryptu powinno dać wynik widoczny powyżej. Błąd wskazuje, że XSD oczekuje dodatniej wartości całkowitej dla numPages, ale w rzeczywistości XML zawiera ujemną liczbę całkowitą, w tym przypadku „-200”.

Naprawianie błędu

Prawdopodobnie mnie ubiegłeś, ale sama zmiana wartości numPages z -200 na 200 i ponowne uruchomienie skryptu powinna dać wynik Valid.

Wniosek

Walidacja dokumentu XML przy użyciu dwóch omawianych modułów XML::LibXML wymagała jedynie dwóch obiektów, wywołania metody validate i użycia funkcji try i catch, aby obsłużyć wszelkie błędy, które mogą zostać zgłoszone.

Jeśli chcesz zobaczyć, jak weryfikacja została przeprowadzona przy użyciu testów Perla, kliknij tutaj, aby wyświetlić repozytorium Github zawierające kod tego artykułu.

Dziękujemy za przeczytanie tego artykułu! Możesz zostawić poklask👏 i polecić ten artykuł innym.