08-08.pdf

(367 KB) Pobierz
JDOM
8
Nasza podróż po krainie języka XML dobiegła półmetka. Czytelnik powinien już mieć ogólne po-
jęcie o przydatności opisywanych narzędzi — niektóre z nich są bardzo użyteczne, inne nieco sier-
miężne. Powinien również umieć korzystać z tych interfejsów i koncepcji w swoich aplikacjach,
a przede wszystkim doceniać, jak bardzo może się mu przydać XML. W tym rozdziale — zanim
zagłębimy się w specyficzne tematy związane z XML-em — zostaną omówione dodatkowe inter-
fejsy programistyczne łączące Javę i XML. Najpierw omówimy pomocniczy interfejs programis-
tyczny, Java API for XML Parsing (JAXP). Interfejs ten, opracowany przez firmę Sun, udostępnia
abstrakcyjną warstwę w procesie uzyskiwania egzemplarza parsera SAX lub DOM; Czytelnik za-
pewne spostrzegł we wcześniejszych rozdziałach, że zadanie to nie wszędzie zostało ustandaryzowane
(szczególnie chodzi tu o DOM) i nie przekłada się na niezależność XML-a względem konkretnego
producenta.
Po omówieniu interfejsu JAXP zostanie przedstawiony nowy interfejs programistyczny, JDOM.
Interfejs ten nie jest spokrewniony z DOM-em w obszarze struktury czy implementacji, ale
— podobnie jak DOM — oferuje kompletną reprezentację dokumentu XML. Został jednak stwo-
rzony z myślą o konkretnym celu — rozwiązaniu szeregu opisanych już problemów związanych
z SAX-em i DOM-em (patrz podrozdziały
Uwaga! Pułapka!)
i zwiększeniu przydatności i wydaj-
ności względem istniejących interfejsów API dla Javy. Czytelnik pozna cel utworzenia, oferowane
funkcje i przyszłość tego interfejsu jako alternatywy dla SAX-a, DOM-a i JAXP-a. Najpierw jed-
nak do naszego zestawu narzędzi dodajmy interfejs JAXP.
Parsery i JAXP
Czytelnik zainteresowany tematem XML-a i Javy prawdopodobnie natknął się na produkt firmy
Sun o nazwie Java API for XML Parsing, najczęściej określanego skrótem JAXP. Wspomnieliśmy
o nim również skrótowo w rozdziale 1. Jeśli wziąć pod uwagę, że JAXP jest często wymieniany
jednym tchem z SAX-em i DOM-em, może nieco zaskakiwać fakt, że zajmujemy się nim dopiero
teraz. Jednakże cały pakiet JAXP, wchodzący w skład
javax.xml.parsers,
to ledwie sześć klas,
z których cztery są abstrakcyjne. Pozostałe dwie opisują wyjątki zgłaszane przez pierwsze cztery.
Czytelnik zapewne pamięta, że podczas korzystania z interfejsu DOM (i SAX bez klasy
XMLRe-
aderFactory)
trzeba jawnie zaimportować i wpisać odwołanie do klasy parsera danego producenta.
W Apache Xerces odpowiednie klasy to
org.apache.xerces.parsers.SAXParser
oraz
C:\Users\a_czajka\Dropbox\Informatyka\książki
informatyczne\Java i XML\08-08.DOC
strona
177
178
Rozdział 8. JDOM
org.apache.xerces.parsers.DOMParser.
Problem polega na tym, że zmiana parsera
wymaga zmiany kodu aplikacji i rekompilacji. To istotna wada — dobrze byłoby, gdyby parsery
można było dołączać na zasadzie „wtyczek”. Do tego właśnie służy interfejs JAXP.
Kiedy korzystamy z interfejsu JAXP, to zamiast bezpośrednio importować klasę parsera określo-
nego producenta, definiujemy ją za pomocą właściwości systemowej. JAXP odczytuje tę właś-
ciwość i zajmuje się załadowaniem danego parsera. W ten sposób zmiana implementacji parsera
wymaga tylko zmiany właściwości systemowej — kod aplikacji wykorzystuje dostarczoną przez
firmę Sun warstwę abstrakcyjną.
Współpraca JAXP-SAX
Kiedy korzystamy z interfejsu SAX, powinniśmy skorzystać z klas JAXP
SAXParser
i
SAXPar-
serFactory.
Pierwsza przejmuje rolę implementacji parsera SAX, a druga obsługuje dynamicz-
ne ładowanie implementacji. Przed omówieniem tych zmian zobaczymy, w jaki sposób można
stworzyć abstrakcję konkretnej implementacji parsera XML (przykład 8.1).
Przykład 8.1. Pobieranie implementacji parsera SAX za pomocą JAXP
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.HandlerBase;
public class JAXPSAXTest {
public void doSomeParsing() {
SAXParser parser;
SAXParserFactory factory = SAXParserFactory.newInstance();
HandlerBase myHandler = new MyHandlerBase();
factory.setValidating(true);
factory.setNamespaceAware(true);
try {
parser = factory.newSAXParser();
parser.parse(myURI, myHandler);
} catch (SAXException e) {
// Obsługa błędów SAX
} catch (IOException e) {
// Obsługa błędów związanych z wczytywaniem URI
} catch (ParserConfigurationException e) {
// Obsługa błędów związanych z niemożnością
// załadowania określonej implementacji parsera
}
}
}
Przykład nie różni się specjalnie od tych, które widzieliśmy w poprzednich rozdziałach, z tym że
nie ma tutaj kodu specyficznego dla Apache Xerces czy jakiegokolwiek innego konkretnego par-
sera. Klasa
SAXParser
przechwytuje egzemplarz wykorzystywanej implementacji parsera i po-
biera ten egzemplarz z egzemplarza klasy
SAXParserFactory.
Jedyne, czym powyższy kod
się różni od omawianych wcześniej, to fakt, że sprawdzanie poprawności i „świadomość” prze-
strzeni nazw włączana jest poprzez
SAXParserFactory,
a nie przez sam egzemplarz parsera.
C:\Users\a_czajka\Dropbox\Informatyka\książki
informatyczne\Java i XML\08-08.DOC
strona
178
Parsery i JAXP
179
Różnica polega na tym, że tutaj wszystkie egzemplarze uzyskują podane właściwości; należy więc
pamiętać, aby funkcji nie włączać zbyt wcześnie, i zapomnieć, że jest włączona przy pobieraniu
implementacji parsera w dalszej części kodu.
Inne odstępstwo od kodu, w którym bezpośrednio korzystaliśmy z implementacji parsera SAX,
polega na tym, że do metody
parser()
klasy
SAXParser
konieczne jest przekazanie egzem-
plarza klasy pomocniczej
HandlerBase.
Tak więc wszystkie programy obsługi zawartości, błędów
i inne gromadzone są w jednej podklasie
HandlerBase.
Należy uważać, aby nie implemento-
wać bezpośrednio interfejsów SAX i próbować korzystać z nich indywidualnie (poprzez metody
setXXXHandler()
dostępne w interfejsie SAX
Parser).
Jeśli klasa
HandlerBase
z niczym
się Czytelnikowi nie kojarzy, to prawdopodobnie Czytelnik nie zna interfejsu SAX 1.0. Niestety, JAXP
obsługuje tylko SAX 1.0 — w SAX-ie 2.0 klasę
HandlerBase
zastąpiono klasą
Default-
Handler.
W klasie tej zaimplementowano najważniejsze interfejsy SAX 1.0, udostępniając puste
implementacje wszystkich metod zdefiniowanych w
ErrorHandler, DTDHandler, Entity-
Resolver
i
DocumentHandler
(który w SAX-ie 2.0 zarzucono na rzecz
Content-
Handler).
W podklasie
HandlerBase
nadpisujemy wszystkie wywołania, w których ma na-
stąpić jakieś działanie. Po utworzeniu programu obsługi metoda
parse()
może zostać wywołana
na egzemplarzu
SAXParser
— jako parametry podaje się identyfikator URI dokumentu do prze-
tworzenia oraz egzemplarz
DefaultHandler.
Współpraca JAXP-DOM
Podstawy współpracy JAXP-a z DOM-em są takie same jak w przypadku współpracy JAXP — SAX.
Klasami analogicznymi do
SAXParser
i
SAXParserFactory
DocumentBuilder
i
Do-
cumentBuilderFactory,
służące do tworzenia drzewa modelu DOM (także w pakiecie
javax.xml.parsers).
Faktycznie obie te klasy wykorzystują do komunikacji z resztą apli-
kacji interfejsy API SAX — zgłaszają również te same wyjątki co klasy SAX (w tym
SAXEx-
ception).
Specyfikacja JAXP nie wymaga, aby implementacje
DOMBuilder
używały SAX-a do
tworzenia drzewa DOM; wymaga za to wykorzystania interfejsu API w komunikacji z aplikacją.
Kod wykorzystujący klasy JAXP DOM (przykład 8.2) jest niemal identyczny z kodem poprzed-
niego przykładu.
Przykład 8.2. Pobieranie implementacji parsera DOM za pomocą JAXP
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.HandlerBase;
public class JAXPDOMTest {
public void doSomeParsing() {
DocumentBuilder parser;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
factory.setNamespaceAware(true);
try {
parser = factory.newDocumentBuilder();
Document doc = parser.parse(myURI);
C:\Users\a_czajka\Dropbox\Informatyka\książki
informatyczne\Java i XML\08-08.DOC
strona
179
180
} catch (SAXException e) {
// Obsługa błędów SAX
} catch (IOException e) {
// Obsługa błędów związanych z wczytywaniem URI.
} catch (ParserConfigurationException e) {
// Obsługa błędów związanych z niemożnością
// załadowania określonej implementacji parsera.
}
}
}
Rozdział 8. JDOM
Klasa
DocumentBuilderFactory
umożliwia włączenie sprawdzania poprawności i „świado-
mości” przestrzeni nazw; ustawienia te zostaną utrzymane dla wszystkich egzemplarzy
Document-
Builder
uzyskanych w wyniku działania metody
newDocumentBuilder().
Po określeniu
położenia dokumentu do przetwarzania można wywołać metodę
parse(),
zwracającą obiekt
DOM
Document,
będący wynikiem przetwarzania. Po przetworzeniu można wykorzystać stan-
dardowe obiekty i metody DOM — aplikacja jest zupełnie oddzielona od detali związanych z par-
serem określonego producenta.
Wybór parsera
Nie powiedzieliśmy jeszcze o sposobie ustalenia, jaki parser ma być zastosowany. Jak wspo-
mnieliśmy, JAXP ma uprościć zmianę implementacji parsera. Jednakże nie jest to czynność tak
prosta, jak mogłoby się wydawać.
Ponieważ JAXP zawiera cztery klasy abstrakcyjne, każdy parser obsługujący ten interfejs musi
udostępniać implementacje klas JAXP. Na przykład Apache Xerces posiada wymagane klasy
w
org.apache.xerces.jaxp.
Specyfikacja JAXP mówi, że każda implementacja może do-
myślnie udostępniać dowolny parser; innymi słowy, implementacja Apache Xerces udostępnia
jako domyślny parser Apache Xerces, a Oracle — najprawdopodobniej parser Oracle. Zmiana do-
myślnej klasy parsera na inną może zostać wykonana poprzez ustawienie właściwości systemowej
javax.xml.parsers.SAXParserFactory
tak, by wskazywała na nowego producenta
SAX, lub przez ustawienie
javax.xml.parsers.DocumentBuilderFactory
tak, by
wskazywała na nowego producenta DOM. Właściwości systemowe można ustawiać za pomocą
opcji
-D
w programach uruchamianych z wiersza poleceń lub poprzez
System.setPro-
perty()
w kodzie Javy. Klasy JAXP odczytują właściwości systemowe i odpowiednio reagują
na wywołania
newSAXParser()
i
newDocumentBuilder()
— udostępniają egzemplarze
klas danego producenta. Jednakże większość współczesnych aplikacji nie jest obsługiwana z wiersza
poleceń, ale poprzez interfejs WWW; czasem stanowią one część większego pakietu. Co więcej,
użycie
System.setProperty()
w zwyczajny sposób spowodowałoby odczytanie informacji
przekazanych do
setProperty()
(takich jak nazwa własności i klasa sterownika SAX) z pliku
właściwości. Plik taki nie może być plikiem XML (o tym więcej w rozdziale 11.), ponieważ nie
istnieje jeszcze odpowiedni parser. Pakiet Java
Development Kit (JDK) 1.3 udostępnia
możliwość określania właściwości we wdrażanym pliku
jar;
jednak w czasie pisania tej książki
wiele popularnych platform (np. Linux) nie obsługiwało jeszcze JDK 1.3. Innymi słowy, duże
możliwości konfiguracyjne w ramach JAXP dopiero powstają.
Mimo tych niedogodności, koncepcje przyświecające utworzeniu interfejsu JAXP są niezwykle
wartościowe; ponadto firma Sun przekazała niedawno kody JAXP i parsera Project X opiekunom
projektu Apache Xerces (kod nosi nazwę „Crimson”), co oznacza, że Sun zamierza przyspieszyć
rozwój swojego API i że sprzyja otwartym standardom. Pod koniec roku 2000 można oczekiwać
C:\Users\a_czajka\Dropbox\Informatyka\książki
informatyczne\Java i XML\08-08.DOC
strona
180
JDOM
kolejny API?
181
wersji JAXP 1.1, obsługującej DOM Level 2, SAX 2.0 i umożliwiającej bardziej ogólny sposób
wyboru parsera. (Wersja robocza specyfikacji JAXP 1.1 została udostępniona w grudniu 2000 r.
przyp. tłum.).
JDOM
kolejny API?
Czytelnik poznał już interfejsy API służące do korzystania z XML-a z poziomu Javy; zostały
omówione ich największe wady i zalety. Jednak trudno zafascynować się tym, co mają nam do
zaoferowania SAX, DOM i JAXP. O ile społeczność XML-a ma już konieczne do pracy na-
rzędzia, o tyle programiści Javy są nieco zdezorientowani niestandardowymi sposobami zachowa-
nia SAX-a i DOM-a oraz ogólną trudnością manipulacji dokumentami XML, a nawet po prostu
problemami z uzyskaniem parsera! Dlatego, zgodnie z tradycją oprogramowania open source,
projektów związanych z językiem Java i wydawnictwa O'Reilly & Associates, postanowiliśmy
naprawić ten błąd i zaprezentować nowe rozwiązanie — interfejs JDOM.
Skąd nazwa?
Pierwsi testerzy JDOM byli nieco zaskoczeni nazwą — zbliżoną do DOM, który to inter-
fejs jest z natury bardziej pojemny. Ponieważ jednak JDOM po prostu reprezentuje doku-
ment w Javie, nazwa wydaje się odpowiednia. Innymi słowy, została wybrana ze względu
na precyzyjne odwzorowanie przeznaczenia interfejsu mimo podobieństwa do nazwy
innego API. Co więcej, JDOM jest tylko luźno związany z XML-em. Obsługuje dowolny
hierarchiczny format danych i może równie łatwo podlegać serializacji, jak zwracać
w wyniku dane XML — za pomocą obiektów
OutputStream
lub
File
oraz klas
wyjściowych JDOM. Implementacja JDOM
org.jdom.input.Builder
udostępnia
również sprawny sposób tworzenia obiektu JDOM
Document;
obiekt ten może zostać
utworzony z pliku właściwości w niestandardowym formacie lub w formacie XML.
JDOM faktycznie reprezentuje dowolny zbiór danych w Javie.
Na interfejs JDOM składa się specyfikacja autorstwa Bretta McLaughlina i Jasona Huntera (K&A
Software), utworzona przy współpracy Jamesa Duncana Davidsona (autor specyfikacji JAXP). JDOM
jest mało wymagającym mechanizmem do analizowania i przeglądania dokumentu XML. Opisano
dane wejściowe i wyjściowe służące do stworzenia obiektu JDOM
Document
z istniejących da-
nych XML i zwrócenia go w określonym celu. Stworzono działającą implementację w postaci pa-
kietu org.jdom (wersja 1.0) — można go pobrać ze strony pod adresem
http://www.jdom.org.
Celem stworzenia JDOM było rozwiązanie problemów związanych z interfejsami SAX, DOM
i JAXP. Zobaczymy, co oferuje nowy interfejs i czy w ogóle był potrzebny (mało jeszcze tych
skrótów?).
Twórcy JDOM mieli na celu stworzenie skupionego wokół Javy, wysoko wydajnego zamiennika
interfejsów SAX i DOM w większości zastosowań
1
. Nie jest oparty na DOM-ie czy SAX-ie.
Pozwala użytkownikowi pracować na dokumencie XML w postaci drzewiastej bez konieczności
1
Oczywiście, w niektórych przypadkach JDOM nie jest dobrym zamiennikiem większego interfejsu DOM; nie jest ob-
sługiwany przez różne języki programowania i nie udostępnia ściśle określonej reprezentacji drzewiastej oferowanej
przez DOM. Jednak przynajmniej w 80% przypadków JDOM potrafi rozwiązać problemy programistów związane z ob-
róbką XML-a.
C:\Users\a_czajka\Dropbox\Informatyka\książki
informatyczne\Java i XML\08-08.DOC
strona
181
Zgłoś jeśli naruszono regulamin