|
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 praktycznego 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[Author:PG] .
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), rozpoczniemy 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 przykł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 referencyjnego. Innymi słowy, nie przedstawiamy poszczególnych pojęć wraz z ich definicjami, nie jest to też skrótowe wprowadzenie do standardu XML. Będziemy posuwać się kolejnymi krokami naprzó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ąć powtarzania 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. Leksykon 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">
<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:Ksiazka7>
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 --> [Author:ts] 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 stosowany. 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=wartość; 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 przedstawionym powyżej przykładowym dokumencie XML, tłumacz dodał informację o kodowaniu (encoding="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.).
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 arkusz. 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 definicji 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 lokalnym 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 element 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 PUBLIC. Ponieważ wpisaliśmy SYSTEM, parser XML będzie oczekiwał, że w następnym argumencie 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 systemie 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ę odwoł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 wykorzystywaną 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 identyfikatora 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[Author:ts] .
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. Jego definicję stanowią zawsze pierwszy znacznik otwierający i ostatni znacznik zamykający w dokumencie. 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 <JavaXML: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łą pozostałą zawartość dokumentu XML. Specyfikacja XML zezwala na obecność tylko jednego elementu 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 sprawę 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 odpowiadał żaden inny dokument XML, można użyć przedrostka w rodzaju JavaXML, powodującego przypisanie elementu do danej przestrzeni nazw. Specyfikacja przestrzeni nazw wymaga przypisania danemu przedrostkowi niepowtarzalnego identyfikatora URI, tak aby możliwe było odróżnienie 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 elementach, wszystkie bowiem do niej należą. Poprawnym sposobem związania elementu z przestrzenią nazw jest podanie jej identyfikatora jako przedrostka oddzielonego dwukropkiem od właściwej nazwy elementu:
<JavaXML:Rozdzial tematyka=" --> XML[Author:ts] ">
<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 nazwach 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 jednym 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 dokumencie. Zazwyczaj pojedyncza przestrzeń nazw umożliwia stworzenie jednego, „czystego” dokumentu 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 egzemplarza (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 podawania 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 (inaczej 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ś przestrzeni 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 przestrzeni 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 schemaLocation, należący do przestrzeni nazw XML Schema. Przed tym atrybutem stawiamy jego przestrzeń 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 identyfikator to domyślna przestrzeń nazw, którą właśnie zadeklarowaliśmy, a drugi to plik mySchema.xsd w lokalnym systemie plików. Jak każdy inny atrybut XML, para ta umieszczana jest wewną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 dokładnie. Element opatrzony jest dowolną nazwą i musi zawierać się w nawiasach kątowych. W naszym 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 kropek. Nazwy nie mogą zawierać spacji — poniższy przykład nie jest poprawnym elementem XML:
<!-- Zagnieżdżone spacje nie są dozwolone -->
<niepoprawna nazwa elementu>
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ć poprawne 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 programistó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ć kolejnoś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. Poprawnie 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 poprawnie skonstruowany dokument niekoniecznie musi być poprawny (ang. --> valid[Author:ts] ), tzn. nie musi być zgodny z ograniczeniami narzuconymi przez DTD lub schemat. Pomiędzy dokumentem poprawnie 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 <znacznik2> 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 dokumentów w takim sensie, w jakim jest to rozumiane w definicji XML. Ścisłe przestrzeganie zasad zagnież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ę znaczniki 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 należałoby zapisywać w następujący sposób:
<rozdzialNiedokonczony></rozdzialNiedokonczony>
<img src="/images/xml.gif"></img>
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[Author:PG] , 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ł atrybut 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 standardowo 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 cudzysłowy otaczające wartości atrybutów na apostrofy (lub odwrotnie), co może spowodować nieprzewidywalne 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ólnie 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ć przedstawione klientowi albo aplikacji, najprawdopodobniej zostaną opisane za pomocą elementu. Mogą 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ą przekazujemy 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 towar (np. krzesło czy stół), „rezerwując” go w ten sposób dla siebie. Poinformowana o tym aplikacja 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 <sprzedane/> 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 reprezentacji 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 wartości. Dla przykładu, typową reprezentacją ścieżki do katalogu instalacyjnego jest zapis <sciezka-do-Cocoon> lub <katalog-Cocoon>. W obu przypadkach tekst taki zostałby zamieniony przez użytkownika na nazwę wybranego katalogu instalacyjnego. W rozdziale opisującym aplikacje WWW jest przedstawiony przykład, w którym konieczne jest podanie szczegółowych 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 zakomunikuje 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ływania się do innych rodzajów danych. Składa się ona z niepowtarzalnej nazwy poprzedzonej znakiem 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>
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 powinien te zmiany odzwierciedlić. Być może Czytelnik zauważył, że składnia wykorzystana w przykł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 zauważ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 tekstu. 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 — przekaż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 przeznaczenie. 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 poznamy 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 wykonują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 dokumentu XML oraz ich stosowania w aplikacjach Javy.
52 Rozdział 2. Tworzenie dokumentów XML
Co dalej? 51
C:\Helion\Java i XML\jAVA I xml\02-08.doc — strona 52
C:\Helion\Java i XML\jAVA I xml\02-08.doc — strona 51
C:\Helion\Java i XML\jAVA I xml\02-08.doc — strona 41
[Author ID1: at Thu Feb 22 01:28:00 2001 ][Author ID1: at Thu Feb 22 01:28:00 2001 ][Author ID1: at Thu Feb 22 01:28:00 2001 ][Author ID1: at Thu Feb 22 01:28:00 2001 ][Author ID1: at Thu Feb 22 01:28:00 2001 ][Author ID1: at Thu Feb 22 01:28:00 2001 ]„how Java provides callbacks to the parsing process": "callback" [Author ID1: at Thu Feb 22 01:28:00 2001 ]and[Author ID1: at Thu Feb 22 01:29:00 2001 ] "parsing" [Author ID1: at Thu Feb 22 01:28:00 2001 ]are terms of the art of programming. They have been summarily dismissed. It doesn't matter here, but it may well in a more technical context.[Author ID1: at Thu Feb 22 01:29:00 2001 ] [ts] I agree that it doesn't matter here, thus they have been summarily dismissed
z „parserem” jest pewien problem — teoretycznie powinno się powiedzieć „analizator [składniowy]”, bo słówka „parser” oficjalnie nie ma w słowniku. Ale, zgodnie z informacjami uzyskanymi od tłumacza, „parser” nie tylko analizuje, ale również modyfikuje dokument, więc słowo „analizator” może być nieprecyzyjne. Użycie słów „procesor” i „translator” odpada (pierwsze znaczy w tym kontekście co innego, drugie jest zbyt ogólne). Czy Recenzent odda swój głos w tej sprawie? — See Comment 2 above. "Parser" sounds great. It comes from the Latin "pars"[Author ID1: at Thu Feb 22 01:53:00 2001 ] — part. [Author ID1: at Thu Feb 22 01:53:00 2001 ]S[Author ID1: at Thu Feb 22 02:16:00 2001 ]lapping Polish endings on Latin words[Author ID1: at Thu Feb 22 02:16:00 2001 ] [Author ID1: at Thu Feb 22 01:57:00 2001 ]is[Author ID1: at Thu Feb 22 02:17:00 2001 ] an even older tradition in Polish than sla[Author ID1: at Thu Feb 22 01:57:00 2001 ]pping Polish endings on English words. [Author ID1: at Thu Feb 22 01:58:00 2001 ]- pg.[Author ID1: at Thu Feb 22 01:59:00 2001 ] [ts] OK, to zostaje parser, ale ja się pod tym nie podpisuję.
[PG]The yellow highlighted text, in which the Translator explains why he added the above string, should better be moved to a footnote. [ts] Zgadzam się i proszę Tłumacza o stosowanie się do zasady, że uzupełnienia od tłumacza muszą być opatrzone dopiskiem „przyp. tłum.” (mogą być umieszczane bezpośrednio w tekście lub w przypisach). (tłumacz: ok., od tej pory będzie wszędzie jednolicie „przyp. tłum”)
Zawężanie dokumentów XML? specyfikacji XML? Akceptuję możliwość odmiany akronimu XML, ale w tytule brzmi to trochę nieciekawie. Mam też pewne wątpliwości do samego słowa „zawężanie” (ograniczanie?)
albo Helion — to zależy, na czym w końcu stanie w kwestii adresu WWW; zob. uwaga 2.
tu też konieczna będzie aktualizacja po ustaleniu ostatecznego spisu treści
?
[Author ID1: at Thu Feb 22 03:19:00 2001 ][Author ID1: at Thu Feb 22 03:19:00 2001 ][Author ID1: at Thu Feb 22 03:19:00 2001 ][Author ID1: at Thu Feb 22 03:19:00 2001 ][Author ID1: at Thu Feb 22 03:19:00 2001 ][Author ID1: at Thu Feb 22 03:19:00 2001 ]It doesn't seem to make sense to give English equivalents of terms other than [Author ID1: at Thu Feb 22 03:19:00 2001 ]those used in [Author ID1: at Thu Feb 22 03:21:00 2001 ]software strings. If we [Author ID1: at Thu Feb 22 03:19:00 2001 ]offer "valid", why not "document" and "book" etc[Author ID1: at Thu Feb 22 03:21:00 2001 ].[Author ID1: at Thu Feb 22 03:19:00 2001 ] [ts] It does make sense here. The distinction between Polish equivalents of „valid” and ”well-formed” is somewhat less obvious than between „document” and „book”.
[Author ID1: at Thu Feb 22 03:22:00 2001 ][Author ID1: at Thu Feb 22 03:22:00 2001 ][Author ID1: at Thu Feb 22 03:22:00 2001 ][Author ID1: at Thu Feb 22 03:22:00 2001 ][Author ID1: at Thu Feb 22 03:22:00 2001 ][Author ID1: at Thu Feb 22 03:22:00 2001 ]"nie musi być" can mean "is not necessarily", but also can be misunderstood as "doesn't need to be".[Author ID1: at Thu Feb 22 03:22:00 2001 ] [ts] splitting hairs
thanks, this is much more elegant