Wszystkie przykładowe programy:
SAX jest to interfejs programistyczny oparty o zdarzeniowy model dokumentu. Może być zaimplementowany w obiektowych językach programowania, a interfejsy zbliżone do SAX także w językach pozwalających na przekazywanie referencji do funkcji (np. C). My zajmiemy się standardową implementacją w Javie.
Cechy charakterystyczne SAX:
API:
org.xml.sax
[.*
], javax.xml.parsers
.Zobacz także:
Pliki: SaxSimplePrinter, InfoHandler.
Program parsuje podany dokument i wypisuje na wyjście informacje o węzłach (niektórych rodzajów). Klasa InfoHandler
jest realizacją interfejsu ContentHandler
, jej obiekty obsługują zdarzenia SAX.
Plik: LiczbySAX.
Program liczy sumę wartości tych elementów l
, które znajdują się w elementach grupa
o atrybucie wazne
równym tak
.
Programista podaje swój kod tworząc klasę implementującą interfejs ContentHandler
.
Parserowi wskazuje się obiekt, który ma obsługiwać zdarzenia, a podczas parsowania metody tego obiektu
wywoływane są w odpowiedzi na zdarzenia takie jak początek elementu czy węzeł tekstowy.
Więcej zdarzeń można obsługiwać, jeśli zaimplementuje się także interfejsy ErrorHandler
(obsługa błędów, m.in. walidacji), LexicalHandler
(obsługa encji, sekcji CDATA, komentarzy),
DeclHandler
(obsługa DTD). Szczegóły w API.
Napisz klasę PrintHandler
(rozszerzenie DefaultHandler
),
której działanie polega na wypisywaniu na wyjście dokumentu w postaci sformatowanej
(większe wcięcia na kolejnych poziomach zagnieżdżenia elementów).
Wystarczy wypisywać elementy z atrybutami i węzły tekstowe, nie należy przejmować się znakami specjalnymi.
Użyj tej klasy w programie parsującym w trybie SAX i wypisującym w opisany wyżej sposób dowolny dokument.
Plik: SaxPodmiana.
Program pokazuje, że można podmienić obiekt ContentHandler
-a w trakcie parsowania,
a dokładnie w trakcie obsługi zdarzenia przez poprzedniego ContentHandler
-a.
Kolejne zdarzenia będą obsługiwane przez nowy obiekt.
Podobnie jak w DOM, w SAX możemy przetwarzać dokument uwzględniając lub nie przestrzenie nazw.
Jeśli nie chcemy uwzględniać przestrzeni nazw, powinniśmy:
setNamespaceAware(false)
(tak na wszelki wypadek, to jest domyślna wartość),qName
w metodzie startElement
i metodą getQName
dla atrybutów.Jeśli chcemy uwzględniać przestrzenie nazw, powinniśmy:
setNamespaceAware(true)
,uri
i localName
w metodzie startElement
oraz metodami getURI
i getLocalName
dla atrybutów.
W pewnych sytuacjach użyteczne mogą być też nazwy kwalifikowane (z ewentualnym prefiksem),
ale to para (uri, localName) decyduje o znaczeniu elementu bądź atrybutu.
Filtr to obiekt klasy implementującej interfejs XMLFilter
(można rozszerzać domyślną klasę XMLFilterImpl
).
Obiekt taki można umieścić między parserem a ContentHandler
-em,
z punktu widzenia „handlera” działa on jak parser (można wywołać na nim metodę parse
,
on wywołuje metody „handlera”), natomiast z punktu widzenia parsera zachowuje się on jak „handler”
– parser wywołuje metody filtra.
Filtry można łączyć w łańcuchy, każdy filtr może filtrować lub modyfikować zdarzenia, a także wykonywać pewne czynności / obliczenia. Dzięki temu podczas jednego parsowania dokumentu można wykonać wiele czynności.
XMLReader parser = XMLReaderFactory.getXMLReader(); ContentHandler handler = new MyHandler(); XMLFilter filtr = new MyFilter(); filtr.setParent(parser); filtr.setContentHandler(handler); filtr.parse();
Plik: FiltrySAX.
Prosty przykład użycia filtra SAX. Filtr przepuszcza tylko niepuste węzły tekstowe i zmienia wielkość liter w nazwach elementów.
Dla dokumentów takich jak w przykładzie LiczbySAX
zaimplementuj filtr GroupFilter
, który przepuszcza tylko grupy o atrybucie ważne równym tak i ich zawartość (podelementy i tekst),
natomiast zatrzymuje nieważne grupy i ich zawartość.
Wykorzystaj filtr do implementacji programu zliczającego zawartość elementów l w ważnych grupach.
Napisz program, który wypisuje elementy i zawartość tekstową dokumentu przefiltrowanego filtrem GroupFilter
.
Wykorzystaj także klasę PrintHandler
(z wcześniejszego przykładu).
Dokumenty można walidować podczas parsowania w trybie SAX.
Najprościej walidować dokument względem jego DTD (wystarczy ustawić w fabryce parserów setValidating(true)
).
Walidacja względem XML Schema wymaga niewielkich dodatkowych zabiegów (podobnych jak dla DOM).