07-08.doc

(219 KB) Pobierz
Wstęp

Uwaga! Pułapka!              175

 

7

 

Czerpanie z XML-a

 

 

 

 

W poprzednim rozdziale Czytelnik nauczył się tworzyć arkusze stylów XSL dla posiadanych do­ku­mentów XML. W niniejszym rozdziale temat ten będzie kontynuowany. Czytelnik dowie się, jak dokument i arkusz stylów są przetwarzane i przekształcane na dane wyjściowe. Podobnie jak w poprzednich rozdziałach, tym razem przyjrzymy się poznanym strukturom języka XML z pun­ktu widzenia Javy. Omówimy procesory XSLT, interfejsy API Javy do obsługi wejścia XML w formacie drzewiastym oraz powiemy, czym różnią się te interfejsy od opisywanego już SAX-a.

Najpierw przeanalizujemy sposób, w jaki wykonywane są w komputerze transformacje. Stwo­rzy­my w ten sposób „wirtualny plac zabaw”, gdzie będziemy mogli eksperymentować z własnymi kon­­strukcjami XSL i XSLT. Spróbujemy również dodać nieco bardziej złożone formatowanie do ar­ku­sza stylów, który stworzyliśmy w ostatnim rozdziale. Ponadto zaczniemy dokładniej ana­li­zo­wać sposób działania pro­cesora XSLT; na końcu szczegółowo omówimy, jakiego rodzaju i for­ma­tu danych wejścio­wych oczekuje taki procesor. Tym samym rozpoczniemy dyskusję o obiek­to­wym mo­delu doku­mentu (DOM) — alternatywnym względem SAX-a sposobie uzyskiwania dostępu do danych XML. Na koniec odejdziemy od tematu parserów, procesorów i interfejsów API, spró­bu­je­my natomiast po­składać wszystkie elementy „układanki XML” w jedną całość. Będzie to wstęp do po­zostałej częś­ci książki — spróbujemy bardziej przekrojowo opisać różne typy aplikacji XML i spo­soby wyko­rzy­s­tania wzorców projektowych i struktur XML do własnych potrzeb.

Przed lekturą dalszej części książki Czytelnik powinien zrozumieć nie tylko tematykę niniejszego rozdziału, ale także to, jakich tematów ten rozdział nie porusza. Czytelnik nie znajdzie tutaj opisu tworzenia procesora XSLT (podobnie jak wcześniej nie znalazł receptury tworzenia parsera XML). Opisywane tutaj zagadnienia są bardzo ważne — w zasadzie kluczowe — do korzystania z pro­ce­sora XSLT; to także świetny wstęp do ewentualnego zaangażowania się w rozbudowę istniejących procesorów XSLT, takich jak Xalan grupy Apache. Jednakże parsery i procesory to programy nie­zwy­kle złożone i próba wyjaśnienia ich wewnętrznych mechanizmów zajęłaby resztę książki, a może i całą następną! My natomiast zajmiemy punkt widzenia programisty aplikacji lub ar­chitekta programów w Javie; postaramy się wykorzystać istniejące już narzędzia i w razie konie­cz­ności rozbudować je do własnych potrzeb. Innymi słowy, zanim zabierzemy się za programowanie procesorów, powinniśmy nauczyć się ich używać!

Uzyskiwanie danych wyjściowych

Jeśli Czytelnik śledził przykłady z ostatniego rozdziału, powinien być już przygotowany na prze­ka­zanie arkusza i dokumentu XML do procesora. W przypadku większości procesorów jest to dość prosta czynność. Zgodnie z przyjętą taktyką korzystania z najlepszych w branży produktów typu open source, użyjemy procesora Apache Xalan (można go pobrać i uzyskać o nim informacje pod adresem http://xml.apache.org). Nad Xalanem pracują najtęższe umysły — programiści firm Lotus, IBM, Sun, Oracle i innych. Ponadto procesor ten świetnie współpracuje z opisywanym we wcześniejszych rozdziałach parserem Apache Xerces. Jeśli jednak Czytelnik posiada już inny pro­ce­sor, to także nie powinien mieć problemów ze znalezieniem informacji, dotyczących urucha­mia­nia przy­kładów opisywanych w tym rozdziale, a wynik działania programu powinien być iden­tyczny lub bardzo podobny do uzyskiwanego w książce.

Najpierw spróbujemy uruchomić procesor XSLT z wiersza poleceń. Często robi się to na potrzeby testowania, usuwania błędów i tworzenia zawartości dokumentów w trybie offline. Warto pa­mię­tać, że w wielu „poważnych” witrynach WWW zawartość tworzona jest właśnie offline, często w godzinach nocnych lub raz w tygodniu, dzięki czemu w czasie żądania pobrania strony nie ma spad­ku wydajności związanego z dynamicznym przetwarzaniem XML-a na HTML lub inny język znaczników. Uruchamiany w ten sposób procesor pomoże nam również w przeanalizowaniu róż­nych warstw transformacji XML. Dokumentacja używanego procesora powinna zawierać in­stru­kcje dotyczące sposobu uruchamiania go z wiersza poleceń. W przypadku procesora Apache Xalan polecenie ma następującą postać 

D:\prod\JavaXML> java org.apache.xalan.xslt.Process

                          -IN [Dokument XML]

                         -XSL [Arkusz stylu XSL]

                          -OUT [Plik wyjściowy]

Xalan, jak każdy inny procesor, umożliwia podanie także wielu innych opcji w wierszu poleceń, ale my będziemy korzystali głównie z tych trzech powyższych. Xalan domyślnie korzysta z par­sera Xerces, a więc w ścieżce dostępu do klas będą musiały się znaleźć zarówno klasy parsera, jak i procesora. W wierszu poleceń można zażądać zmiany parsera XML, ale w Xalanie obsługa par­sera Xerces jest najbardziej zaawansowana. Jeśli przekształcanie odbywa się w powyższy sposób, nie trzeba odwoływać się do arkusza stylu z poziomu dokumentu; procesor XSLT sam zastosuje arkusz stylu podany w wierszu poleceń. Wewnętrzne deklaracje arkuszy stylów zostaną użyte do­piero w rozdziale 9., Struktury publikacji WWW. Tak więc do zbudowania polecenia urucha­mia­jącego nasz procesor potrzebujemy nazwy dokumentu XML i arkusza XSL (w tym przypadku znaj­dującego się w podkatalogu). Ponieważ w wyniku mamy uzyskać plik HTML, jako plik wyjś­ciowy podajemy contents.html:

D:\prod\JavaXML> java org.apache.xalan.xslt.Process

                          -IN contents.xml

                          -XSL XSL/JavaXML.html.xsl

                          -OUT contents.html

Uruchomienie takiego polecenia w odpowiednim katalogu spowoduje, że Xalan rozpocznie proces transformacji. Uzyskamy wynik podobny do tego przedstawionego w przykładzie 7.1.

Przykład 7.1. Przekształcanie pliku XML za pomocą procesora Apache Xalan

D:\prod\JavaXML> java org.apache.xalan.xslt.Process

                          -IN contents.xml

                          -XSL XSL/JavaXML.html.xsl

                          -OUT contents.html

========== Parsing file:D:/prod/JavaXML/XSL/JavaXML.html.xsl =========

 

Parse of file:D:/prod/JavaXML/XSL/JavaXML.html.xsl took 1161 milliseconds

========= Parsing contents.xml ==========

Parse of contents.xml took 311 milliseconds

=============================

Transforming...

transform took 300 milliseconds

XSLProcessor: done

Po ukończeniu przetwarzania powinno być możliwe otworzenie uzyskanego pliku contents.html w edytorze lub przeglądarce WWW. Jeśli Czytelnik postępował zgodnie z instrukcjami w ostatnim rozdziale, to w przeglądarce powinna zostać wyświetlona strona widoczna na rysunku 7.1.

Rysunek 7.1. Strona HTML uzyskana po transformacji danych XML

Teraz Czytelnik wie już, jak wprowadzać zmiany i testować dane wynikowe plików XML i ar­ku­szy XSL. Procesor Xalan uruchomiony z wiersza poleceń posiada także pożyteczną funkcję odnaj­dy­wania błędów w plikach XML lub XSL i podawania numerów wierszy, w których one wystąpiły — to jeszcze bardziej upraszcza usuwanie błędów i testowanie plików.

Pobieranie danych wejściowych

Poza powodami, o których już wspomnieliśmy, jest jeszcze jedna istotna przyczyna, dla której nie będziemy zajmować się omawianiem wewnętrznych mechanizmów procesora — dane wejściowe i wyjściowe procesora są o wiele bardziej zajmujące! Widzieliśmy już, jak można przetwarzać do­kument przyrostowo za pomocą interfejsów i klas SAX. W procesie tym w prosty sposób decy­dujemy, co zrobić z napotkanymi elementami, jak obsłużyć określone atrybuty i jakie czynności powinny zostać podjęte w przypadku napotkania błędów. Jednakże korzystanie z takiego modelu w pewnych sytuacjach rodzi również problemy. Jedną z takich sytuacji jest przekazywanie danych wejściowych dla procesora XSLT.

SAX działa sekwencyjnie

Model sekwencyjny oferowany przez interfejs SAX nie umożliwia uzyskania swobodnego dostępu do dokumentu XML. Innymi słowy, korzystając z SAX-a pobieramy informacje o dokumencie XML wtedy, kiedy robi to parser — i podobnie jak parser informacje te tracimy. Kiedy pojawia się ele­ment 2., to nie można uzyskać dostępu do informacji w elemencie 4., ponieważ nie został on jeszcze przetworzony. Natomiast kiedy pojawi się element 4., to nie możemy powrócić do ele­men­tu 2. Oczywiście, mamy prawo zachować informacje napotkane w procesie przetwarzania, ale za­kodowanie tego typu przypadków specjalnych może być bardzo trudne. Przeciwną skrajnością jest stworzenie reprezentacji dokumentu XML w pamięci. Wkrótce okaże się, że parser DOM po­stę­pu­je właśnie w ten sposób; tak więc wykonywanie tego w interfejsie SAX byłoby bezcelowe, a praw­dopodobnie także wolniejsze i bardziej kłopotliwe.

SAX a elementy siostrzane

Innym zadaniem trudnym do wykonania w interfejsie SAX jest przechodzenie z elementu na ele­ment „w poziomie”. Dostęp do elementów poprzez SAX jest w dużym stopniu hierarchiczny i se­kwencyjny. Uzyskujemy dostęp do krańcowego elementu węzła, potem przechodzimy z powrotem „w górę” drzewa i znów schodzimy do innego elementu na dole hierarchii. Nie ma przejrzystego odniesienia do „poziomu” hierarchii, na którym aktualnie się znajdujemy. Identyfikację poziomów można co prawda wdrożyć poprzez wprowadzenie wyszukanych liczników, ale ogólnie SAX nie jest do tego typu operacji przystosowany. Nie ma zaimplementowanego pojęcia elementu siostrza­nego, następnego elementu na tym samym poziomie; nie ma też możliwości sprawdzenia, które ele­menty są zagnieżdżone w których.

Procesor XSLT musi znać elementy siostrzane danego elementu; co ważniejsze, musi znać jego elementy potomne. Spójrzmy na taki fragment szablonu XSL:

<xsl:template match:"elementMacierzysty">

  <!-- Tutaj zawartość drzewa wynikowego -->

    <xsl:apply-templates select="elementPotomny1|elementPotomny2" />

  <!-- Tutaj dalsza zawartość drzewa wynikowego -->

</xsl:template>

Szablony nakładane są poprzez konstrukcję xsl:apply-templates, ale to nakładanie odby­wa się na konkretnym zestawie węzłów, pasującym do podanego wyrażenia XPath. W powyższym przykładzie szablon powinien być nałożony jedynie na elementPotomny1 lub element­Po­tomny2 (są one rozdzielone operatorem LUB wyrażeń XPath, czyli kreską poziomą). Ponadto, ponieważ wykorzystujemy ścieżkę względną, wspomniane elementy muszą być bezpośrednio potomne względem elementu elementMacierzysty. Określenie i zlokalizowanie tych węz­łów w reprezentacji dokumentu XML oferowanej przez SAX byłoby niezwykle trudne. Dzięki hie­rarchicznej reprezentacji dokumentu w pamięci czynność ta jest bardzo łatwa — i jest to kolejny powód, dla którego tak często korzysta się z modelu DOM jako wejścia dla procesorów XSLT.

Przyczyny korzystania z SAX-a

Wszystkie te „wady” SAX-a skłaniają zapewne Czytelnika do zastanawiania się, dlaczego w ogóle korzysta się z interfejsu SAX. Warto więc tutaj przypomnieć, że powyższe problemy odnoszą się do konkretnego zastosowania danych XML, w tym przypadku przetwarzania poprzez XSL. Otóż „wady” te są jednocześnie... zaletami SAX-a! Czy to nie wydaje się zagmatwane? Wkrótce okaże się, że nie tak bardzo.

Wyobraźmy sobie, że przetwarzamy spis treści czasopisma National Geographic w postaci danych XML. Dokument taki często osiąga 500 wierszy długości, czasem więcej. Teraz wyobraźmy sobie indeks książki O'Reilly w postaci pliku XML. Setki słów z numerami stron, odsyłaczami itd. Wszy­stko to przykłady w miarę małych, spójnych aplikacji XML. W miarę wzrostu dokumentu XML rośnie obszar zajmowanej przez niego pamięci, jeśli korzystamy z drzewa DOM. Weźmy teraz pod uwagę sytuację, w której dokument XML staje się tak wielki, że jego reprezentacja w modelu DOM zaczyna wpływać na wydajność aplikacji. I wyobraźmy jeszcze sobie, że te same wyniki można uzyskać poprzez przetworzenie dokumentu wejściowego sekwencyjnie, za pomocą SAX-a — przy wykorzystaniu jednej dziesiątej lub jednej setnej zasobów systemowych.

Powyższy przykład obrazuje, że podobnie jak w Javie istnieje wiele sposobów wykonania tego samego zadania, tak i w różny sposób można uzyskać dane dokumentu XML. W wielu scena­riu­szach SAX stanowi lepszy wybór — oferuje szybkie przetwarzanie i przekształcanie. W innych przy­padkach zwycięża DOM — zapewnia prosty, przejrzysty interfejs danych określonego forma­tu. To my, programiści, musimy zastanowić się nad celem budowania aplikacji i wybrać odpo­wie­dnią metodę (albo opracować sposób współdziałania obydwu metod). Jak zwykle umiejętność pod­jęcia właściwej decyzji wynika ze znajomości dostępnych rozwiązań. Mając to na uwadze, przyj­rzyjmy się takiemu właśnie nowemu rozwiązaniu.

Obiektowy model dokumentu (DOM)

W przeciwieństwie do interfejsu SAX, obiektowy model dokumentu wywodzi się z kręgów kon­sorcjum W3C. SAX to oprogramowanie będące własnością publiczną, stanowiące owoc długich dyskusji na liście adresowej XML-dev. Natomiast DOM jest samym w sobie standardem, tak jak XML. DOM nie został również opracowany wyłącznie dla Javy; jego zadaniem jest reprezentacja zawartości i modeli dokumentów we wszystkich językach i narzędziach programistycznych. Ist­nie­ją interfejsy DOM dla JavaScriptu, Javy, CORBA i innych języków. Jest to więc specyfikacja neutralna językowo i platformowo.

Kolejna różnica polega na tym, że DOM jest dostarczany jako „poziomy”, a nie wersje. DOM Level One (DOM poziomu pierwszego) ma status przyjętego zalecenia W3C, a pełną specyfikację możemy przejrzeć pod adresem http://www.w3.org/TR/REC-DOM-Level-1/. Level One opisuje fun­kcje i sposób nawigacji po zawartości dokumentu. Dokument w modelu DOM nie musi być dokumentem XML — może to być HTML bądź dowolny inny rodzaj zawartości! Level Two (DOM poziomu drugiego), ukończony w roku 2000, uzupełnia Level One o moduły i opcje dla poszczególnych modeli zawartości, takich jak XML, XSL czy CSS (kaskadowe arkusze stylów). W ten sposób „uzupełniane są luki” pozostawiane przez bardziej ogólne narzędzia Level One. Bie­żący dokument kandydujący do oficjalnego zalecenia W3C znajduje się pod adresem http://www.­w3.­org/TR/DOM-Level-2/. Trwają już prace nad modelem Level Three (DOM poziomu trzeciego), udo­stępniającym kolejne narzędzia dla specyficznych typów dokumentów — np. pro­cedury obsłu­gi sprawdzania poprawności dla XML-a.

DOM a Java

Aby móc korzystać z modelu DOM w określonym języku programowania, należy zastosować interfejsy i klasy oraz zaimplementować sam model DOM. Ponieważ wykorzystywane metody nie są określone w samej specyfikacji DOM (specyfikacja ta charakteryzuje jedynie model doku­men­tu), konieczne było opracowanie interfejsów języka reprezentujących konceptualną strukturę mo­delu DOM — zarówno dla Javy, jak i innych języków. Interfejsy te umożliwiają manipulację dokumentami w sposób określony właśnie w specyfikacji DOM.

Oczywiście, w tej książce najbardziej interesuje nas interfejs dla Javy. Dowiązania dla tego języka (ang. bindings), określane nazwą DOM Level Two Java bindings, można pobrać ze strony http://www.w3.org/TR/DOM-Level-2/java-binding.html. Klasy, które powinniśmy dodać do ścieżki dostępu do klas, znajdują się w pakiecie org.w3c.dom (i podpakietach). Jednakże zanim je po­bie­rzemy z sieci, warto zerknąć do posiadanego parsera XML i procesora XSLT. Podobnie jak pakiet SAX, DOM jest często dostarczany wraz z tymi narzędziami. W ten sposób mamy również za­gwa­rantowane, że parser, procesor i posiadana wersja DOM poprawnie współpracują ze sobą.

Większość procesorów nie generuje samodzielnie danych wejściowych DOM. Korzystają w tym celu z parsera XML, któremu powierza się zadanie wygenerowania drzewa DOM. Dlatego często to parser XML, a nie procesor XSLT będzie posiadał wymagane klasy DOM. Ponadto w ten spo­sób zapewnia się niezależność obu narzędzi — zawsze można zamienić parser albo procesor na pro­dukt innego producenta. Ponieważ domyślnie Apache Xalan wykorzystuje parser Xerces do przetwa­rzania i generowania modelu DOM, zajmiemy się tutaj obsługą DOM z poziomu tego narzędzia.

Uzyskanie parsera DOM

Aby zorientować się w sposobie działania modelu DOM, powiemy teraz, w jaki sposób procesor Apache Xalan i inne programy wymagające danych wejściowych w formacie DOM otrzymują do­kument XML w strukturze drzewiastej DOM. W ten sposób poznamy pierwsze dowiązania języka Java do modelu DOM i wyjaśnimy koncepcje leżące u podstaw obsługi dokumentów XML po­przez model DOM.

Model DOM nie określa, w jaki sposób tworzone jest drzewo DOM. Autorzy specyfikacji skon­cen­...

Zgłoś jeśli naruszono regulamin