05-08.doc

(120 KB) Pobierz
Wstęp

Uwaga! Pułapka!              129

 

5

 

Sprawdzanie poprawności składni XML-a

 

 

 

 

Po lekturze poprzednich rozdziałów Czytelnik potrafi już stworzyć dokument XML, przetworzyć go za pomocą klas SAX oraz zawęzić. W tym rozdziale zostanie omówione kolejne zagadnienie — spraw­dzanie poprawności dokumentu XML za pomocą Javy. Bez takiej możliwości tworzenie aplikacji firma-firma oraz komunikacji międzyaplikacyjnej staje się o wiele trudniejsze. Zawężenie zwię­ksza przenośność danych; natomiast sprawdzanie poprawności — spójność. Innymi słowy, moż­liwość zawężenia dokumentu nie zda się na wiele, jeśli stworzonych zawężeń nie przeforsujemy w aplikacji XML.

W tym rozdziale przedstawione zostaną klasy i interfejsy SAX służące do sprawdzania po­praw­ności dokumentów XML względem ich zawężeń. Czytelnik dowie się, jak ustawić cechy i właś­ci­wości parsera zgodnego z SAX, aby możliwe było proste sprawdzanie poprawności, obsługa prze­strzeni nazw i wykonywanie innych czynności. Ponadto szczegółowo omówione zostaną błędy i ostrze­że­nia zgłaszane przez parsery sprawdzające poprawność.

Konfiguracja parsera

W obliczu bogactwa specyfikacji i technologii autorstwa konsorcjum W3C związanych z językiem XML, dodanie obsługi nowej cechy lub właściwości nie jest proste. W wielu implementacjach par­serów dodano własne rozszerzenia lub metody kosztem przenośności kodu. W pakietach tych mógł zostać zaimplementowany interfejs XMLReader, ale metody do ustawiania sprawdzania po­praw­ności, obsługi przestrzeni nazw i innych kluczowych cech są odmienne w różnych imple­men­ta­cjach parserów. W związku z tym w interfejsie SAX 2.0 zdefiniowano standardowy mechanizm do ustawiania istotnych właściwości i cech parsera. Umożliwia on dodawanie nowych właściwości i cech w miarę przyjmowania ich przez W3C, bez konieczności stosowania własnych metod lub rozszerzeń.

Ustawianie właściwości i cech

Na szczęście dla nas, interfejs SAX 2.0 wyposażono w metody służące do ustawiania właściwości i cech interfejsu XMLReader. Oznacza to, że w celu zażądania sprawdzania poprawności, usta­wienia separatora przestrzeni nazw czy obsługi innych cech nie trzeba zmieniać zbyt wiele w istnie­jącym kodzie. Odpowiednie metody przedstawione są w tabeli 5.1.

Tabela 5.1. Metody do obsługi właściwości i cech parsera

Metoda

Zwraca

Parametry

Składnia

setProperty()

void

String IDwlasciwosci, Object wartosc

parser.setProperty(„[URI wlasciwosci]”, „[Parametr obiektu]”);

setFeature()

void

String IDcechy, boolean stan

parser.setFeature(„[URI cechy]”, true);

getProperty()

Object

String IDwlasciwosci

String separator = (Stringparser.getProperty(„[URI wlasciwosci]”);

getFeature()

boolean

String IDcechy

if (parser.getFeature(„[URI cechy]”)) {robiCos();}

W każdej z powyższych metod identyfikatorem ID określonej właściwości lub cechy jest iden­ty­fi­ka­tor URI. Lista najważniejszych właściwości i cech jest zamieszczona w dodatku B. Producent par­sera XML powinien udostępnić dodatkową dokumentację informujacą o obsługiwanych ce­chach i właś­ciwościach. Pamiętajmy jednak, że identyfikatory te, podobnie jak identyfikatory URI prze­strzeni nazw, służą wyłącznie do kojarzenia odpowiednich cech. Dobry parser umożliwi ko­rzys­ta­nie z nich bez posiadania połączenia z siecią. W tym sensie identyfikatory URI można postrzegać jako proste stałe, które akurat mają format URI. Po skorzystaniu z takiej metody następuje lokalne prze­­two­rze­nie identyfikatora, często jako stałej reprezentującej odpowiednią czynność, którą na­leży podjąć.

W kontekście konfiguracji parsera właściwość wymaga obecności obiektu, z którego można sko­rzystać. Na przykład w celu obsługi leksykalnej jako wartość właściwości można dostarczyć klasę LexicalHandler. Cecha natomiast ma postać znacznika wykorzystywanego przez parser w ce­lu określenia, czy ma nastąpić przetwarzanie określonego typu. Typowe cechy to sprawdzanie poprawności, obsługa przestrzeni nazw i dołączanie encji zewnętrznych.

Najwygodniejsza własność powyższych metod polega na tym, że umożliwiają one łatwe dodawa­nie i zmia­nę różnych cech. Nowe lub zaktualizowane właściwości wymagają obsługi ze strony par­se­ra, ale dostęp do nich uzyskuje się wciąż za pomocą tych samych metod — konieczne jest tylko zde­­fi­nio­wanie nowego identyfikatora URI. Bez względu na złożoność nowych koncepcji związanych z XML, ich implementacja w parserach przebiega bezproblemowo, właśnie dzięki tym metodom.

Włączanie sprawdzania poprawności

Czytelnik dowiedział się już, jak ustawiać cechy i właściwości, ale nie poznał jeszcze samych cech i właściwości. W tym rozdziale interesujemy się przede wszystkim sprawdzaniem poprawności w czasie przetwarzania. Aby zilustrować, jak ważne są wspomniane wyżej metody, trzeba od­wo­łać się do historii. W interfejsie SAX 1.0 implementacje parserów musiały udostępniać własne roz­wiązania do obsługi przetwarzania ze sprawdzaniem poprawności lub bez. Nie było możliwości włączenia lub wyłączenia sprawdzania poprawności w sposób standardowy, więc najprostszy spo­sób polegał na dostarczeniu dwóch niezależnych klas przetwarzających. Na przykład, aby wyko­nać przetwarzanie bez sprawdzania poprawności we wczesnych wersjach parsera Project X firmy Sun, trzeba było skorzystać z przedstawionego poniżej fragmentu kodu.

Przykład 5.1. Uruchamianie parsera nie sprawdzającego poprawności w interfejsie SAX 1.0

try {

    // Rejestrujemy parser w SAX

    Parser parser =

        ParserFactory.makeParser(

            "com.sun.xml.parser.Parser");

 

    // Przetwarzamy dokument

    parser.parse(uri);

 

} catch (Exception e) {

    e.printStackTrace();

}

Ponieważ nie istniał standardowy mechanizm włączania sprawdzania poprawności, trzeba było załadować inną klasę; ta nowa klasa jest niemal identyczną implementacją interfejsu Parser w SAX 1.0, ale wykonującą sprawdzanie poprawności. Kod pozwalający na użycie parsera jest niemal identyczny (przykład 5.2), różnica jest tylko w klasie załadowanej w celu przetwarzania.

Przykład 5.2. Uruchamianie parsera sprawdzającego poprawność w interfejsie SAX 1.0

try {

    // Rejestrujemy parser w SAX

    Parser parser =

        ParserFactory.makeParser(

            "com.sun.xml.parser.ValidatingParser");

 

    // Przetwarzamy dokument

    parser.parse(uri);

 

} catch (Exception e) {

    e.printStackTrace();

}

Włączając lub wyłączając sprawdzanie poprawności trzeba więc było zmieniać i kompilować kod. Ponadto wynikał z tego dodatkowy problem z przetwarzaniem. Standardowe środowisko pro­gramistyczne wykorzystuje kod, który sprawdza poprawność danych XML wytwarzanych przez aplikację. To sprawdzanie poprawności, choć obniża wydajność, zapewnia, że aplikacja tworzy za­wsze poprawny kod XML albo że otrzymuje poprawne dokumenty XML na wejściu. Często takie za­­­żenia po intensywnym testowaniu można usunąć, dzięki czemu odzyskuje się wysoką wy­daj­ność działania aplikacji. Pozbawienie parsera możliwości sprawdzania poprawności jest uzasad­nio­ne, ponieważ dogłębne testy potwierdziły poprawność tworzonego dokumentu XML; ale zmia­na ta wy­­maga modyfikacji i rekompilacji kodu. Wydaje się to być sprawą banalną, ale wiele firm nie poz­wala na wdrożenie do produkcji kodu, który był modyfikowany później niż przed jakimś okre­ś­lo­nym czasem — często kilka dni, a nawet tygodni. Taka niewielka zmiana może więc spo­wo­do­wać dodatkowy cykl testowy — niejednokrotnie niepotrzebny, a dodatkowo wydłużający czas wdro­żenie aplikacji.

Ale przecież nazwę parsera można pobrać z pliku właściwości (zostało to już powiedziane w roz­dziale 2. przy okazji opisywania aspektów przenośności aplikacji XML). Tak, ale zmiana całej im­ple­mentacji parsera tuż przed wdrażaniem aplikacji do produkcji to zmiana poważna, która po­winna być należycie przetestowana. Jeśli porównamy to ze zmianą wartości zestawu cech (za­kła­da­jąc, że wartość do ustawiania tej cechy także pobierana jest z pliku właściwości), to łatwo zga­dnąć, które rozwiązanie jest lepsze.

Z tych wszystkich powodów w interfejsie SAX 2.0 do XMLReader dodano omawiane metody. Dzięki nim włączenie sprawdzania poprawności polega na wykorzystaniu odpowiedniego identy­fi­ka­tora URI: http://xml.org/sax/features/validation. Moglibyśmy zażądać również przetwarzania en­cji zewnętrznych i przestrzeni nazw, ale tymczasem „włączymy” tylko sprawdzanie popraw­ności (przykład 5.3).

Przykład 5.3. Włączanie sprawdzania poprawności

        // Stwórz egzemplarze procedur obsługi

        ContentHandler contentHandler = new MyContentHandler();

        ErrorHandler errorHandler = new MyErrorHandler();       

       

        try {

            // Stwórz egzemplarz parsera

            XMLReader parser =

                XMLReaderFactory.createXMLReader(

                    "org.apache.xerces.parsers.SAXParser");

               

            // Zarejestruj procedurę obsługi zawartości

            parser.setContentHandler(contentHandler);

           

            // Zarejestruj procedurę obsługi błędów

            parser.setErrorHandler(errorHandler);                                

 

            parser.setFeature("http://xml.org/sax/features/validation",

                              true);          

               

            // Przetwórz dokument

            parser.parse(uri);

           

        } catch (IOException e) {

            System.out.println("Błąd przy wczytywaniu URI: " + e.getMessage());

        } catch (SAXException e) {

            System.out.println("Błąd w przetwarzaniu: " + e.getMessage());

        }

Po tych prostych zmianach możemy już zmodyfikować nasz przykładowy plik XML tak, by znów zawierał odwołanie do definicji DTD i zewnętrzną encję (zostały one opatrzone komentarzami w po­przednim rozdziale).

<?xml version="1.0" encoding="ISO-8859-2"?>

 

<!-- Tego jeszcze nie potrzebujemy

<?xml-stylesheet href="XSL\JavaXML.html.xsl" type="text/xsl"?>

<?xml-stylesheet href="XSL\JavaXML.wml.xsl" type="text/xsl"

                 media="wap"?>

<?cocoon-process type="xslt"?>

-->

 

<!DOCTYPE JavaXML:Ksiazka SYSTEM "DTD\JavaXML.dtd">

 

 

<!-- Java i XML -->

<JavaXML:Ksiazka xmlns:JavaXML="http://www.oreilly.com/catalog/javaxml/">

<JavaXML:Tytul>Java i XML</JavaXML:Tytul>

<JavaXML:Spis>

 

...

 

...

Zgłoś jeśli naruszono regulamin