C:\WINDOWS\Pulpit\Szymon\Java i XML\02-08.doc — strona 41
2
Tworzenie
dokumentów XML
Teraz, gdy już wiemy, czym jest XML, do jakich celów może służyć oraz przez jakie interfejsy
programowe Javy jest obsługiwany, pora przenieść tę wiedzę na grunt praktyczny. Niniejsza książ-
ka nie jest w żadnym razie pełnym podręcznikiem składni języka — nie może nawet służyć jako
leksykon — nie można jednak omawiać przetwarzania dokumentów XML nie posiadając
umiejętności tworzenia. Ponadto stosowanie interfejsów Javy do obsługi XML-a wymaga dość
dobrej znajomości składni i struktury tego języka, a także sposobów tworzenia dokumentów, ich
zawężania i przekształcania. Zanim więc zajmiemy się interfejsami Javy służącymi do obsługi ję-
zyka XML, zapoznamy się z tymi czynnościami.
W niniejszym rozdziale przyjrzymy się składni dokumentów XML. Rozpoczniemy od najbardziej
podstawowych konstrukcji i powiemy, co to jest „poprawnie skonstruowany” dokument XML.
Opiszemy różne zasady tworzenia dokumentów XML oraz pułapki składni. Po lekturze rozdziału
Czytelnik będzie potrafił stworzyć dokument nie tylko poprawny, ale także nadający się do prakty-
cznego zastosowania. Wszystko to będzie stanowiło wstęp do napisania pierwszego programu
w Javie (w następnym rozdziale) i zrozumienia, na czym polega przetwarzanie kodu XML oraz jak
Java odwołuje się do tego procesu.
Ci, którzy mieli już kiedyś do czynienia z książkami opisującymi składnię języka programowania,
zdają sobie sprawę, że takie opisy bywają dość nudne. My spróbujemy podejść do sprawy nieco
inaczej. Zamiast rozpoczynać od jedno- czy dwuwierszowego pliku XML i dodawać do niego
kolejne elementy (co kończy się stworzeniem długiego, ale bezużytecznego przykładu), rozpocz-
niemy od pełnego, dość złożonego dokumentu XML. Plik, którego użyjemy jako przykładu, to
fragment rzeczywistego dokumentu XML reprezentującego spis treści tej książki. Przyjrzymy mu
się wiersz po wierszu i opiszemy poszczególne konstrukcje. Przy omawianiu składni w oparciu
o proste przykłady rzadko pamięta się o tym, że rozwiązania proste stosowane są w rzeczywistych
aplikacjach bardzo rzadko. Zamiast tego najczęściej trafiają się złożone pliki, niezrozumiałe dla
osób „wychowanych” na prostych przykładach. Trzeba zatem przyzwyczaić się do plików XML
zawierających wszelkie możliwe konstrukcje — i zaczniemy właśnie od takich praktycznych przy-
kładów. Można mieć nadzieję, że dzięki temu nasze wprowadzenie będzie bliższe rzeczywistości.
Zanim zaczniemy, jeszcze jedna uwaga. Rozdział ten nie pretenduje do miana materiału referen-
cyjnego. Innymi słowy, nie przedstawiamy poszczególnych pojęć wraz z ich definicjami, nie jest
42
Rozdział 2. Tworzenie dokumentów XML
C:\WINDOWS\Pulpit\Szymon\Java i XML\02-08.doc — strona 42
to też skrótowe wprowadzenie do standardu XML. Będziemy posuwać się kolejnymi krokami na-
przód — definicje podawane będą w kontekście przykładów oraz przedstawionych konstrukcji.
Warto natomiast podczas lektury mieć pod ręką dobry leksykon XML-a, co pozwoli uniknąć po-
wtarzania przedstawionych tu wiadomości w dalszej części książki, omawiającej sprawy bardziej
skomplikowane. Dobrym przykładem takiej pozycji jest książka Roberta Ecksteina XML. Leksy-
kon kieszonkowy (Helion, Gliwice 2000).
Dokument XML
Zgodnie z obietnicą zaczniemy od praktycznego dokumentu XML, stanowiącego fragment spisu
treści tej książki. Spójrzmy na przykład 2.1.
Przykład 2.1. Plik XML
<?xml version="1.0" encoding="ISO-8859-2"?>
<?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>
<JavaXML:Rozdzial tematyka="XML">
<JavaXML:Naglowek>Wprowadzenie</JavaXML:Naglowek>
<JavaXML:Temat podrozdzialy="7">Co to jest?</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="3">Jak z tego korzystać?</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="4">Dlaczego z tego korzystać?</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="0">Co dalej?</JavaXML:Temat>
</JavaXML:Rozdzial>
<JavaXML:Rozdzial tematyka="XML">
<JavaXML:Naglowek>Tworzenie dokumentów XML</JavaXML:Naglowek>
<JavaXML:Temat podrozdzialy="0">Dokument XML</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="2">Nagłówek</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="6">Zawartość</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="1">Co dalej?</JavaXML:Temat>
</JavaXML:Rozdzial>
<JavaXML:Rozdzial tematyka="Java">
<JavaXML:Naglowek>Przetwarzanie kodu XML</JavaXML:Naglowek>
<JavaXML:Temat podrozdzialy="3">Przygotowujemy się</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="3">Czytniki SAX</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="9">Procedury obsługi
zawartości</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="4">Procedury obsługi błędów</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="0">
Lepszy sposób ładowania parsera
</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="4">"Pułapka!"</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="0">Co dalej?</JavaXML:Temat>
</JavaXML:Rozdzial>
<JavaXML:PodzialSekcji/>
<JavaXML:Rozdzial tematyka="Java">
Nagłówek
43
C:\WINDOWS\Pulpit\Szymon\Java i XML\02-08.doc — strona 43
<JavaXML:Naglowek>Struktury publikacji WWW</JavaXML:Naglowek>
<JavaXML:Temat podrozdzialy="4">Wybór struktury</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="4">Instalacja</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="3">
Korzystanie ze struktury publikacji
</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="2">XSP</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="3">Cocoon 2.0 i dalej</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="0">Co dalej?</JavaXML:Temat>
</JavaXML:Rozdzial>
</JavaXML:Spis>
<JavaXML:Copyright>&HelionCopyright;</JavaXML:Copyright>
</JavaXML:Ksiazka>
Nagłówek
Pierwszy element dokumentu dotyczy samego języka XML. Dokument stworzony w tym języku
można podzielić na dwie podstawowe części: nagłówek, który przekazuje parserowi i aplikacjom
XML informacje o tym, jak dany dokument ma być obsługiwany, oraz zawartość, czyli same dane
XML. Pozwoli nam to odróżnić treść dokumentu XML od instrukcji przekazywanych aplikacjom
z jego wnętrza. Zaczniemy od pierwszych kilku linijek przykładu, do miejsca
JavaXML:
Ksiazka
(bez niego). Te początkowe wiersze to właśnie nagłówek dokumentu. Termin „nagłó-
wek” nie jest formalnym pojęciem zdefiniowanym w specyfikacji XML, ale jest szeroko stoso-
wany. W tej książce również będziemy z niego korzystać.
Instrukcje XML
Pierwszym elementem każdego dokumentu XML jest instrukcja XML. Instrukcje języka XML
stanowią określony podzbiór instrukcji przetwarzania (PI), o których mówiliśmy w poprzednim
rozdziale. Powiedziano tam, że instrukcje PI są zazwyczaj przekazywane przez parser do aplikacji
wywołującej i dopiero tam obsługiwane. Ale instrukcje przetwarzające, w których jako element
docelowy podano
xml
, są przeznaczone dla samego parsera. Określają one rodzaj używanej wersji
XML-a, arkusz stylów lub inne informacje potrzebne parserowi do poprawnego przetworzenia
danych XML. Oto instrukcja XML:
<?xml version="1.0" standalone="no" encoding="ISO-8859-2"?>
Podobnie jak wszystkie inne instrukcje PI, ma ona postać
<?cel instrukcja?>
i w tym
przypadku określa, że używana wersja standardu XML to 1.0, a dokument nie jest samodzielnym
dokumentem XML. Zauważmy, że
instrukcja
to niekoniecznie jedna para
klucz=war-
to••
; w tym przypadku określamy zarówno wersję dokumentu, jak i to, czy wymaga on jeszcze
obecności jakiegoś innego dokumentu lub dokumentów. Kiedy parser „dowiaduje się”, że dany
dokument nie jest samodzielny (ang. standalone), wie, że do określenia jego poprawności będzie
konieczne wykorzystanie zewnętrznej definicji DTD. Gdyby atrybut
standalone
miał wartość
yes
, parser nie musiałby odwoływać się do zewnętrznej definicji DTD. W początkowej instrukcji
może też znaleźć się deklaracja sposobu kodowania dokumentu. Tutaj, jak również w przedstawio-
nym powyżej przykładowym dokumencie XML, tłumacz dodał informację o kodowaniu (
enco-
ding="ISO-8859-2"
) — bez niej w czasie późniejszego przetwarzania dokumentu parser
zgłaszałby błędy po napotkaniu znaków spoza standardowego zestawu ASCII (czyli np. polskich
liter ą, ć, ś itp.).
44
Rozdział 2. Tworzenie dokumentów XML
C:\WINDOWS\Pulpit\Szymon\Java i XML\02-08.doc — strona 44
Kolejną grupę stanowią instrukcje XML odwołujące się do arkuszy stylów. W naszym przykładzie
mamy dwie takie instrukcje:
<?xml-stylesheet href="XSL\JavaXML.html.xsl" type="text/xsl"?>
<?xml-stylesheet href="XSL\JavaXML.wml.xsl" type="text/xsl" media="wap"?>
Zazwyczaj instrukcja PI rozpoczynająca się od
xml-[nazwa]
odwołuje się do technologii zwią-
zanej z XML-em i określonej w części
[nazwa]
. W tym przypadku chodzi o arkusz stylów, toteż
instrukcja przekazywana jest do mechanizmu XSLT, a nie do parsera XML-a. W pierwszym
wierszu odwołujemy się do domyślnego arkusza stylów, podając jego położenie i typ. W wierszu
drugim widzimy odwołanie do alternatywnego arkusza stylów. W tym przypadku podano także
atrybut
media
, który informuje procesor, dla jakiego rodzaju klientów jest przeznaczony dany ar-
kusz. Mechanizmy publikacji omówimy w rozdziale 9., Systemy publikacji WWW.
Deklaracje typu dokumentu
Po początkowych instrukcjach XML następuje deklaracja
DOCTYPE
. Deklaracja ta dysponuje
własną, odrębną składnią, ponieważ jest wykorzystywana tylko do jednego celu — określenia de-
finicji DTD wykorzystywanej w danym dokumencie XML. Spójrzmy jeszcze raz na deklarację
DOCTYPE
w naszym przykładzie:
<!DOCTYPE JavaXML:Ksiazka SYSTEM "DTD\JavaXML.dtd">
W tym przykładzie definicją DTD dla dokumentu jest plik JavaXML.dtd, znajdujący się w lokal-
nym systemie plików. Parsery XML zazwyczaj dopuszczają stosowanie zwykłego lub lewego
ukośnika (odpowiednio, dla systemów Unix i Windows), co pozwala uzyskać przenośność ścieżek
dostępu pomiędzy różnymi platformami. Pierwszym parametrem deklaracji
DOCTYPE
jest ele-
ment główny dokumentu, o którym powiemy za chwilę — tymczasem wystarczy informacja, że
określa on bieżący dokument XML. Następnym argumentem jest albo słowo
SYSTEM
, albo
PU-
BLIC
. Ponieważ wpisaliśmy
SYSTEM
, parser XML będzie oczekiwał, że w następnym argumen-
cie znajdzie się położenie pliku DTD, określone za pomocą jednolitego identyfikatora zasobów
(URI). Słowo
SYSTEM
nie oznacza jednak, że plik DTD musi się koniecznie znajdować w syste-
mie lokalnym. Można też użyć następującego zapisu:
<!DOCTYPE JavaXML:Ksiazka SYSTEM
"http://www.oreilly.com/catalog/javaxml/DTD/JavaXML.dtd">
Specyfikacja XML pozwala umieścić w tym miejscu dowolny poprawny identyfikator URI, a więc
adres URL jest do przyjęcia. Użycie słowa
PUBLIC
oznacza, że definicja DTD, do której się od-
wołujemy, jest upubliczniona i mogą z niej korzystać wszyscy. W tym przypadku przed podaniem
URI konieczne jest określenie nazwy publicznej. Poniższą deklarację można znaleźć na początku
niektórych plików HTML, takich jak strona główna konsorcjum W3C, dostępna pod adresem
http://www.w3c.org/:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
Po słowie kluczowym
PUBLIC
następuje nazwa określająca publiczną definicję DTD wykorzys-
tywaną w danym dokumencie. Parser XML najpierw stara się zlokalizować definicję DTD za
pomocą jej nazwy, a dopiero kiedy to się nie uda — za pomocą dodatkowo podanego identyfikato-
ra URI. Składnia nazwy publicznej definicji DTD jest szczegółowo opisana w specyfikacji XML,
ale to na razie nie będzie nas interesować. Definicjom DTD i ich formatowi przyjrzymy się
w rozdziale 4., Zawężanie XML.
Zawartość dokumentu
45
C:\WINDOWS\Pulpit\Szymon\Java i XML\02-08.doc — strona 45
Zawartość dokumentu
Skoro nagłówek mamy już za sobą, możemy przejść do zawartości dokumentu XML. Składają się
na nią elementy, atrybuty i opisywane przez nie dane tekstowe.
Element główny
Element główny (ang. root element) to najwyższy w hierarchii element dokumentu XML. Je-
go definicję stanowią zawsze pierwszy znacznik otwierający i ostatni znacznik zamykający w do-
kumencie. Element ten stanowi punkt wyjścia dla parsera lub aplikacji XML, umożliwiając im
rozpoznanie początku i końca dokumentu. W naszym przykładzie elementem głównym jest
<Ja-
vaXML:Ksiazka>
:
<JavaXML:Ksiazka xmlns:JavaXML="http://www.oreilly.com/catalog/javaxml/">
<!-- tutaj zawartość dokumentu XML -->
</JavaXML:Ksiazka>
Znacznik ten, w połączeniu z odpowiadającym mu znacznikiem zamykającym, otacza całą pozo-
stałą zawartość dokumentu XML. Specyfikacja XML zezwala na obecność tylko jednego ele-
mentu głównego w dokumencie. Innymi słowy, element taki musi „obejmować” wszystkie inne
elementy. Poza tym jednym wymogiem element główny nie różni się od innych elementów XML.
Warto o tym pamiętać, ponieważ dokumenty XML mogą zawierać inne dokumenty XML lub
odwoływać się do nich. W takich przypadkach element główny dokumentu, do którego się odwo-
łujemy, staje się elementem wewnętrznym dokumentu, z którego nastąpiło odwołanie i musi
zostać normalnie obsłużony przez parser XML. Dzięki temu, że elementy główne zdefiniowano jako
standardowe elementy XML (nie posiadające specjalnych właściwości czy zachowań), dołączanie
innych dokumentów XML przebiega bezproblemowo.
Identyfikacja elementów za pomocą przestrzeni nazw
Nie będziemy tutaj zbytnio zagłębiać się w temat przestrzeni nazw, ale wypada zdawać sobie spra-
wę ze sposobu ich użycia w elemencie głównym. Jak można było zauważyć, wszystkie nazwy
elementów XML mają przedrostek
JavaXML
. Być może później zajdzie potrzeba dołączenia do
przykładowego dokumentu fragmentów innych książek wydawnictwa O’Reilly. Ponieważ każda
z nich może także posiadać znaczniki
<Rozdzial>
,
<Naglowek>
lub
<Temat>
, dokument
musi zostać skonstruowany tak, aby wyeliminować możliwość kolizji przestrzeni nazw z innymi
dokumentami. Specyfikacja przestrzeni nazw w języku XML rozwiązuje ten problem w bardzo
prosty sposób. Ponieważ nasz dokument odpowiada konkretnej książce, której nie będzie odpo-
wiadał żaden inny dokument XML, można użyć przedrostka w rodzaju
JavaXML
, powodującego
przypisanie elementu do danej przestrzeni nazw. Specyfikacja przestrzeni nazw wymaga przypisa-
nia danemu przedrostkowi niepowtarzalnego identyfikatora URI, tak aby możliwe było odróżnie-
nie elementów w danej przestrzeni nazw od elementów w innych przestrzeniach. Zaleca się użycie
do tego celu adresu URL i tak właśnie robimy w naszym przykładzie (http://www.oreilly.com/
catalog/javaxml — strona WWW tej książki):
<JavaXML:Ksiazka xmlns:JavaXML="http://www.oreilly.com/catalog/javaxml/">
Do zdefiniowanej w ten sposób przestrzeni nazw można odwoływać się z dowolnego elementu
w danym dokumencie XML. W naszym przypadku przestrzeń wykorzystujemy we wszystkich ele-
mentach, wszystkie bowiem do niej należą. Poprawnym sposobem związania elementu z prze-
46
Rozdział 2. Tworzenie dokumentów XML
C:\WINDOWS\Pulpit\Szymon\Java i XML\02-08.doc — strona 46
strzenią nazw jest podanie jej identyfikatora jako przedrostka oddzielonego dwukropkiem od
właściwej nazwy elementu:
<JavaXML:Rozdzial tematyka="XML">
<JavaXML:Naglowek>Wprowadzenie</JavaXML:Naglowek>
<JavaXML:Temat podrozdzialy="7">Co to jest?</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="3">Jak z tego korzystać?</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="4">Dlaczego z tego korzystać?</JavaXML:Temat>
<JavaXML:Temat podrozdzialy="0">Co dalej?</JavaXML:Temat>
</JavaXML:Rozdzial>
Każdy z tych elementów jest traktowany przez parser XML jako część przestrzeni nazw http://
www.oreilly.com/catalog/javaxml/, dzięki czemu nie wystąpią kolizje z innymi elementami o na-
zwach
Rozdzial
,
Naglowek
czy
Temat
, zawartymi w innych przestrzeniach nazw. W tym
samym dokumencie można umieszczać wiele deklaracji przestrzeni nazw — wszystkie za pomocą
jednego elementu:
<JavaXML:Ksiazka xmlns:JavaXML="http://www.oreilly.com/catalog/javaxml/"
xmlns:Cocoon="http://xml.apache.org/cocoon/">
Powyższa deklaracja jest poprawna, jednak przy wykorzystywaniu wielu przestrzeni nazw w jed-
nym dokumencie trzeba zachować dużą ostrożność. Często korzyści z takiego rozwiązania mogą
zostać zniwelowane przez komplikację i konieczność umieszczania dodatkowego tekstu w doku-
mencie. Zazwyczaj pojedyncza przestrzeń nazw umożliwia stworzenie jednego, „czystego” doku-
mentu XML z jednoczesnym uniknięciem kolizji; jedynym istotnym wyjątkiem jest przypadek,
gdy wykorzystywana jest inna specyfikacja XML (np. XML Schema) i gdy trzeba dla niej użyć
osobnej przestrzeni nazw.
Na koniec jeszcze jedno interesujące (i może nieco skomplikowane) zagadnienie. Specyfikacja
XML Schema, dokładniej omówiona w rozdziale 4., wymaga określenia schematu dokumentu
XML w sposób bardzo przypominający zestaw deklaracji przestrzeni nazw (przykład 2.2).
Przykład 2.2. Dokument XML wykorzystujący specyfikację XML Schema
<?xml version="1.0"?>
<ksiazkaAdresowa xmlns:xsi="http://www.w3.org/1999/XMLSchema/instance"
xmlns="http://www.oreilly.com/catalog/javaxml/"
xsi:schemaLocation="http://www.oreilly.com/catalog/javaxml/
mySchema.xsd"
>
<osoba>
<nazwa>
<imie>Brett</imie>
<nazwisko>McLaughlin</nazwisko>
</nazwa>
<email>brettmclaughlin@earthlink.net</email>
</osoba>
<osoba>
<nazwa>
<imie>Maciej</imie>
<nazwisko>Abacki</nazwisko>
</nazwa>
<email>mabacki@poczta.xyz.pl</email>
</osoba>
</ksiazkaAdresowa>
Wystąpiło tutaj kilka zjawisk, które należy dobrze zrozumieć. Po pierwsze, dla danego egzempla-
rza (ang. instance) schematu XML (XML Schema) definiowana jest — i kojarzona z określonym
identyfikatorem URI — przestrzeń nazw. Przestrzeń ta, o skrótowej nazwie
xsi
, służy do poda-
Zawartość dokumentu
47
C:\WINDOWS\Pulpit\Szymon\Java i XML\02-08.doc — strona 47
wania w dokumencie XML informacji o danym schemacie — dokładnie tak, jak robimy to tutaj.
Dlatego w pierwszym wierszu udostępniamy elementy naszego egzemplarza schematu XML do
wykorzystania w całym dokumencie. W następnym wierszu definiujemy przestrzeń nazw samego
dokumentu XML. Ponieważ nie są w nim wykorzystywane żadne jawne przestrzenie nazw (ina-
czej niż w poprzednim przykładzie), deklarujemy domyślną przestrzeń nazw. Specyfikacja
przestrzeni nazw XML mówi, że każdy element dokumentu XML musi należeć do jakiejś prze-
strzeni nazw; domyślna przestrzeń nazw to ta, z którą skojarzony jest element w przypadku, gdy
nie podano żadnej innej przestrzeni. Oznacza to, że wszystkie elementy bez przedrostka prze-
strzeni nazw (czyli w tym przykładzie wszystkie) kojarzone są z tą właśnie przestrzenią domyślną.
Przy takim zdefiniowaniu przestrzeni nazw dokumentu oraz schematu XML możemy już zrobić
to, co chcieliśmy, czyli skojarzyć schemat z dokumentem. Służy do tego atrybut
schemaLoca-
tion
, należący do przestrzeni nazw XML Schema. Przed tym atrybutem stawiamy jego prze-
strzeń nazw (
xsi
), którą przed chwilą zdefiniowaliśmy. Argument atrybutu składa się właściwie
z dwóch identyfikatorów URI: pierwszy określa przestrzeń nazw skojarzoną ze schematem, a drugi
jest identyfikatorem schematu, do którego się odwołujemy. W naszym przykładzie pierwszy iden-
tyfikator to domyślna przestrzeń nazw, którą właśnie zadeklarowaliśmy, a drugi to plik mySche-
ma.xsd w lokalnym systemie plików. Jak każdy inny atrybut XML, para ta umieszczana jest we-
wnątrz cudzysłowów. I oto mamy w dokumencie odwołanie do schematu!
Mówiąc poważniej, zagadnienie to nie jest takie proste i wciąż stanowi jeden z najtrudniejszych
dla użytkowników aspektów używania przestrzeni nazw i schematu XML. Do całego opisanego
wyżej mechanizmu wrócimy wkrótce, na razie zaś wystarczy zrozumieć, że przestrzenie nazw
umożliwiają wykorzystanie elementów z różnych grup, przy czym elementy te cały czas pozostają
nieodłącznym fragmentem grup, z których pochodzą.
Elementy danych
Do tej pory unikaliśmy definiowania pojęcia „element”. Teraz nadeszła pora, aby wyjaśnić je do-
kładnie. Element opatrzony jest dowolną nazwą i musi zawierać się w nawiasach kątowych. W na-
szym przykładowym dokumencie obecne są elementy różnego rodzaju:
<!-- Element standardowy: znacznik otwierający -->
<JavaXML:Spis>
<!-- Element standardowy z atrybutem -->
<JavaXML:Rozdzial tematyka="XML">
<!-- Element z danymi tekstowymi -->
<JavaXML:Naglowek>Struktury publikacji WWW</JavaXML:Naglowek>
<!-- Element pusty -->
<JavaXML:PodzialSekcji/>
<!-- Element standardowy: znacznik zamykający -->
</JavaXML:Spis>
Pierwsza zasada tworzenia elementów mówi, że nazwa elementu musi rozpoczynać się literą lub
podkreśleniem, po którym może wystąpić dowolna liczba liter, cyfr, podkreśleń, łączników lub kro-
pek. Nazwy nie mogą zawierać spacji — poniższy przykład nie jest poprawnym elementem XML:
<!-- Zagnieżdżone spacje nie są dozwolone -->
<niepoprawna nazwa elementu>
48
Rozdział 2. Tworzenie dokumentów XML
C:\WINDOWS\Pulpit\Szymon\Java i XML\02-08.doc — strona 48
W nazwach elementów XML rozróżniana jest wielkość liter. Mówiąc ogólnie, zastosowanie tych
samych zasad, których używa się przy tworzeniu nazw zmiennych Javy, pozwala uzyskać po-
prawne nazwy elementów XML. Nie powinno się skracać nazw typu „Obiekt telekomunikacyjny”
do postaci
<otk>
(bo staną się niezrozumiałe), z drugiej strony nie powinno się też stosować
elementów typu
<poczatekNowegoRozdzialu>
, bo niepotrzebnie zaśmiecają dokument.
Warto pamiętać, że dokumenty XML będą najprawdopodobniej oglądane przez innych programi-
stów, a więc dobrze jest używać znaczących, „samodokumentujących się” nazw.
Każdy otwarty element musi zostać zamknięty. I nie ma tutaj wyjątków, tak jak to jest w innych
językach znaczników, np. w HTML-u. Znacznik końcowy składa się z ukośnika i nazwy elementu,
np.
</JavaXML:Spis>
. Pomiędzy znacznikiem otwierającym a zamykającym może znajdować
się dowolna ilość danych tekstowych lub innych elementów. Nie można jednak zmieniać kolej-
ności zagnieżdżania — pierwszy otwarty element musi zostać zamknięty jako ostatni. Jeśli któraś
z tych zasad nie zostanie spełniona, dokument XML będzie niepoprawnie skonstruowany. Popra-
wnie skonstruowany (ang. well-formed) dokument to taki, w którym przestrzega się zasad składni
języka XML, a wszystkie elementy i atrybuty znajdują się we właściwych miejscach. Jednakże po-
prawnie skonstruowany dokument niekoniecznie musi być poprawny (ang. valid), tzn. nie musi
być zgodny z ograniczeniami narzuconymi przez DTD lub schemat. Pomiędzy dokumentem po-
prawnie skonstruowanym a poprawnym jest duża różnica; w tym rozdziale zajmujemy się tylko
poprawnością konstrukcji, natomiast reguły określające poprawność dokumentu przedstawimy
w rozdziale 4.
Oto przykład dokumentu niepoprawnie skonstruowanego:
<znacznik1>
<znacznik2>
</znacznik1>
</znacznik2>
Kolejność zagnieżdżania nie jest prawidłowa, ponieważ po znaczniku otwierającym
<zna-
cznik2>
nie znajduje się znacznik zamykający
</znacznik2>
. Ale po poprawieniu tego błędu
składniowego nie możemy jeszcze być pewni, że cały dokument jest poprawny. To istotna różnica,
do której wrócimy w rozdziale 4.
Powyższy przykład niepoprawnie sformatowanego dokumentu może się wydawać banalny, ale
z drugiej strony warto zauważyć, że w HTML-u byłby to zapis poprawny — i często pojawia się
w dużych tabelach wewnątrz dokumentów zapisanych w tym języku. Innymi słowy, HTML
i wiele innych języków znaczników nie wymaga tworzenia poprawnie sformatowanych dokumen-
tów w takim sensie, w jakim jest to rozumiane w definicji XML. Ścisłe przestrzeganie zasad za-
gnieżdżania obowiązujących w XML-u umożliwia dużo szybsze przetwarzanie i sprawniejszą
obsługę zapisanych w nim dokumentów.
Ostatnia zasada, jaką omówimy, dotyczy dość oryginalnych elementów pustych. Powiedzieliśmy
już, że znaczniki XML muszą występować parami; na kompletny element XML składają się zna-
czniki otwierający i zamykający. Są jednak przypadki, w których element występuje w dokumencie
samodzielnie, informując np. o tym, że rozdział nie jest ukończony; są też elementy posiadające
atrybuty, ale nie zawierające danych tekstowych — np. obrazek w HTML-u. Elementy takie na-
leżałoby zapisywać w następujący sposób:
<rozdzialNiedokonczony></rozdzialNiedokonczony>
<img src="/images/xml.gif"></img>
Zawartość dokumentu
49
C:\WINDOWS\Pulpit\Szymon\Java i XML\02-08.doc — strona 49
Zapis ten jest niezbyt rozsądny i powoduje zwiększenie bałaganu w dokumencie. Specyfikacja XML
dopuszcza jego uproszczenie poprzez zawarcie znacznika otwierającego i zamykającego w jednym
elemencie:
<rozdzialNiedokonczony/>
<img src="/images/xml.gif"/>
Rozwiązuje to problem elegancji zapisu, a jednocześnie nie narusza zasady, że każdy element
XML musi mieć odpowiednik zamykający — tutaj jeden element jest jednocześnie otwierającym
i zamykającym.
Atrybuty elementów
Oprócz tekstu zawartego pomiędzy znacznikami, element może także posiadać atrybuty. Atrybuty,
wraz z odpowiadającymi im wartościami, zawarte są w deklaracji otwierającej elementu (która
może być także deklaracją zamykającą!). Np. częścią znacznika
JavaXML:Rozdzial
był atry-
but określający tematykę rozdziału:
<JavaXML:Rozdzial tematyka="Java">
<!-- Dane rozdzialu -->
</JavaXML:Rozdzial>
<JavaXML:Rozdzial tematyka="XML">
<!-- Dane rozdzialu -->
</JavaXML:Rozdzial>
W powyższym przykładzie
tematyka
to nazwa atrybutu, a jego wartościami są, odpowiednio,
XML
i
Java
. Nazwy atrybutów podlegają takim samym zasadom jak nazwy elementów XML, a ich
wartości muszą znajdować się w cudzysłowach. Dopuszczalne są tu również apostrofy, ale stan-
dardowo używa się cudzysłowów — odpowiada to zresztą konwencji przyjętej w Javie. Apostrofy
i cudzysłowy można także wykorzystywać wewnątrz wartości atrybutu — jeśli znajduje się ona
w cudzysłowach, to wewnątrz można użyć apostrofów, i odwrotnie. Nie jest to jednak metoda
zalecana, jako że parsery i procesory XML często automatycznie przekształcają wszystkie cudzy-
słowy otaczające wartości atrybutów na apostrofy (lub odwrotnie), co może spowodować nieprze-
widywalne skutki.
Ważne jest nie tylko to, jak należy używać atrybutów, ale także gdzie ich używać. XML umoż-
liwia tak rozmaite formatowanie danych, że rzadko kiedy nie jest możliwe wyrażenie atrybutu
przez element, lub odwrotnie — elementu przez atrybut. Nie istnieje żadna specyfikacja ani ogól-
nie przyjęty standard mówiący o tym, kiedy używać atrybutu, a kiedy elementu, ale można tutaj
podać pewną radę praktyczną: elementów używa się do opisywania danych przeznaczonych do
prezentacji, a atrybutów — do opisywania danych systemowych. Dane, które mają zostać przed-
stawione klientowi albo aplikacji, najprawdopodobniej zostaną opisane za pomocą elementu. Mo-
gą one być później traktowane jako dane aplikacji, które można w prosty sposób przeszukiwać
i wykorzystywać. Jako przykład może tu posłużyć tytuł rozdziału książki, cena mebla czy adres
URL firmowej witryny WWW. Jeśli jednak dane służą do grupowania lub za ich pomocą prze-
kazujemy aplikacji informację o sposobie obsłużenia innej porcji danych, czy też wreszcie nie są
bezpośrednio widziane przez klienta lub aplikację XML-ową, najprawdopodobniej będą miały
postać atrybutu. Przykładami „dobrych kandydatów” na atrybuty mogą być części książki — sama
część może być elementem posiadającym własny tytuł, ale grupowanie znajdujących się w niej
rozdziałów da się w prosty sposób opisać atrybutem
czesc
w elemencie
JavaXML:Rozdzial
.
Atrybut taki umożliwia proste indeksowanie części, ale nie będzie prezentowany bezpośrednio
użytkownikowi. Innym dobrym przykładem jest sytuacja, w której klient zapłacił zadatek za dany
50
Rozdział 2. Tworzenie dokumentów XML
C:\WINDOWS\Pulpit\Szymon\Java i XML\02-08.doc — strona 50
towar (np. krzesło czy stół), „rezerwując” go w ten sposób dla siebie. Poinformowana o tym apli-
kacja XML mogłaby wygenerować broszurę lub ulotkę, w której taki towar nie byłby już zawarty.
I znów — klient nie widziałby bezpośrednio tej informacji, ale dane zostałyby wykorzystane przy
obsłudze i przetwarzaniu dokumentu XML. Jeśli po tym wszystkim nadal jeszcze nie wiadomo,
czego użyć, zawsze można postąpić asekuracyjnie i zastosować element.
Można też wyobrazić sobie inne sposoby reprezentacji przedstawionych przykładów. Zamiast
np. korzystać z atrybutu opisującego część, można zagnieździć elementy
JavaXML:Rozdzial
w elemencie
JavaXML:czesc
; w drugim przykładzie użycie pustego znacznika
<sprze-
dane/>
pozwoliłoby na sprawniejsze oznakowanie „zarezerwowanych” mebli. W języku XML
rzadko mamy do czynienia z jednym tylko sposobem reprezentowania danych. Najczęściej to
aplikacja i sposób wykorzystania danych determinują sposób postępowania. Nie będziemy więc
pisać o tworzeniu zapisów w XML-u (byłoby to trudne), ale o ich używaniu — i właśnie przez
praktyczne używanie Czytelnik będzie mógł poznać sposoby obsługi i użycia różnych reprezenta-
cji danych. Ta wiedza umożliwia Czytelnikowi samodzielne podejmowanie decyzji o sposobie
formatowania dokumentów XML.
„Stałe” języka XML
Nie wspomnieliśmy jeszcze o sekwencjach unikowych i odwoływaniu się do innych, stałych war-
tości. Dla przykładu, typową reprezentacją ścieżki do katalogu instalacyjnego jest za
pis
<sciezka-do-Coc
oon>
lub <katalog-Coc
oon>. W obu przypadkach tekst taki zostałby
zamieniony przez użytkownika na nazwę wybranego katalogu instalacyjnego. W rozdziale opisu-
jącym aplikacje WWW jest przedstawiony przykład, w którym konieczne jest podanie szczegóło-
wych informacji o instalacji i sposobie korzystania z aplikacji Apache Cocoon. Może zatem zajść
potrzeba użycia takiej reprezentacji danych w elemencie:
<JavaXML:Tematat>
<JavaXML:Naglowek>Instalacja Cocoon</JavaXML:Naglowek>
<JavaXML:Zawartosc>
Plik Cocoon.properties znajduje się w katalogu <sciezka-do-Cocoon>/bin.
</JavaXML:Zawartosc>
</JavaXML:Temat>
Kłopot polega na tym, iż parser XML spróbuje obsłużyć takie dane jako znacznik XML i zakomu-
nikuje o błędzie, ponieważ nie znajdzie znacznika zamykającego. Jest to typowy problem związany
z każdą sytuacją, w której konieczne jest zastosowanie nawiasów kątowych. Można go rozwiązać
za pomocą encji (ang. entity reference). Encja to specjalny typ danych XML służący do odwoły-
wania się do innych rodzajów danych. Składa się ona z niepowtarzalnej nazwy poprzedzonej zna-
kiem ampersand (&) i zakończonej średnikiem, tj.
&[nazwa-encji];
. Po napotkaniu encji
parser XML podstawia pod nią odpowiednią wartość i nie przetwarza jej dalej. W języku XML
zdefiniowano pięć encji, które pomogą rozwiązać powyższy problem:
<
to otwierający nawias
kątowy (lub symbol „mniejsze niż”),
>
to zamykający nawias kątowy (lub symbol „większe
niż”),
&
to sam znak ampersand,
"
to cudzysłów, a
'
— apostrof. Za pomocą
tego rodzaju encji możemy przedstawić odwołanie do katalogu instalacyjnego w następujący sposób:
<JavaXML:Temat>
<JavaXML:Naglowek>Instalacja Cocoon</JavaXML:Naglowek>
<JavaXML:Zawartosc>
Plik Cocoon.properties znajduje się w katalogu <sciezka-do-
Cocoon>/bin.
</JavaXML:Zawartosc>
</JavaXML:Temat>
Co dalej?
51
C:\WINDOWS\Pulpit\Szymon\Java i XML\02-08.doc — strona 51
Po przetworzeniu tego dokumentu pogrubiony zapis zostanie zinterpretowany jako
<sciezka-
do-Cocoon>
i dokument zostanie zaakceptowany jako poprawnie sformatowany.
Należy także pamiętać, że encje mogą być definiowane przez użytkownika, co pozwala tworzyć
swoiste zapisy skrótowe. W przedstawionym na początku rozdziału dokumencie XML znajduje się
odwołanie do zewnętrznego, współużytkowanego tekstu noty o prawach autorskich. Ponieważ ten
sam dokument wykorzystywany jest w wielu książkach wydawnictwa, nie chcemy zamieszczać go
w całości w dokumencie XML. Jeśli jednak prawa autorskie ulegną zmianie, nasz dokument powi-
nien te zmiany odzwierciedlić. Być może Czytelnik zauważył, że składnia wykorzystana w przy-
kładowym dokumencie XML wygląda jak predefiniowana encja:
<JavaXML:Copyright>&HelionCopyright;</JavaXML:Copyright>
Co prawda dopiero w części omawiającej definicje DTD wyjaśnimy, w jaki sposób XML ustala,
do czego ma się odwołać po napotkaniu encji
&HelionCopyright;
, ale już teraz należy zau-
ważyć, że encje służą do wielu innych zadań, nie tylko do reprezentowania nietypowych znaków
w danych.
Dane nieprzetwarzane
Ostatnia konstrukcja XML, jaką omówimy, to sekcja
CDATA
. Stosowana jest ona wtedy, gdy do
aplikacji wywołującej trzeba przekazać dużą ilość danych nieprzetworzonych przez parser XML.
Z tego sposobu można skorzystać wtedy, gdy dane zawierają wiele nietypowych znaków, których
znaczenie należałoby znosić za pomocą encji, albo też gdy zależy nam na utrzymaniu układu te-
kstu. W dokumencie XML sekcja
CDATA
wygląda następująco:
<nieprzetwarzane-dane>
<![CDATA[Diagram:
<Krok 1>Zainstaluj Cocoon do "/usr/lib/cocoon"
<Krok 2>Znajdź odpowiedni plik properties.
<Krok 3>Pobierz program Ant z adresu "http://jakarta.apache.org"
-----> skorzystaj z CVS <-----
]]>
</nieprzetwarzane-dane>
W tym przykładzie zawartość sekcji
CDATA
nie musi być kodowana za pomocą encji lub innych
mechanizmów nakazujących parserowi specjalne postępowanie z nietypowymi znakami — prze-
każe on je w niezmienionej postaci do aplikacji.
Poznaliśmy już najważniejsze składniki dokumentów XML. Każdy z nich został omówiony niejako
„przy okazji”, ale już teraz Czytelnik powinien potrafić rozpoznać znaczniki XML i ich przezna-
czenie. W następnych rozdziałach książki poznamy kolejne właściwości tych konstrukcji, wykonując
ćwiczenia praktyczne — ta metoda nauki jest najlepsza.
Co dalej?
Po tym wstępie do tworzenia dokumentów XML możemy rozpocząć pisanie pierwszego programu
w Javie. W następnym rozdziale przyjrzymy się prostemu interfejsowi Simple API for XML (SAX).
Zaczniemy od przetworzenia naszego dokumentu za pomocą prostego programu, a następnie po-
znamy sposoby obsługi instrukcji przetwarzania, elementów, atrybutów i innych konstrukcji
języka XML w procesie przetwarzania dokumentu. Autor zaprezentuje kod napisany w Javie wy-
konujący poszczególne czynności, zaczynając od prostego programu drukującego dokument XML.
W kolejnym rozdziale rozpocznie się intensywny proces nauki manipulowania składnikami doku-
mentu XML oraz ich stosowania w aplikacjach Javy.
52
Rozdział 2. Tworzenie dokumentów XML
C:\WINDOWS\Pulpit\Szymon\Java i XML\02-08.doc — strona 52