XML – ćwiczenia 13: SAX

Wszystkie przykładowe programy:

SAX – Simple API for XML

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 można spotkać także w językach pozwalających na przekazywanie referencji do funkcji (np. C). My zajmiemy się standardową implementacją w Javie.

Cechy charakterystyczne SAX:

Referencje

API Javy:

Zobacz także:

Parsowanie dokumentu i odczyt danych

Przykład 1.

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.

Przykład 2. LiczbySAX – z wykładu

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.

Zadanie 1.

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.

Write PrintHandler class (extension of DefaultHandler) that writes a document as formatted XML (nested elements indentation) to the standard output.

Handle elements with attributes and text nodes. Do not treat special characters specially.

Write a program using that class for a given XML file.

Obsługa przestrzeni nazw

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:

  • w fabryce ustawić setNamespaceAware(false) (dla czytelności i przenośności rozwiązania, to jest domyślna wartość),
  • parsować dokument parserem uzyskanym z takiej fabryki,
  • odczytywać nazwy z parametru qName w metodzie startElement i metodą getQName dla atrybutów.

Jeśli chcemy uwzględniać przestrzenie nazw, powinniśmy:

  • w fabryce ustawić setNamespaceAware(true),
  • parsować dokument parserem uzyskanym z takiej fabryki,
  • odczytywać nazwy z parametrów 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.

Filtry SAX

Filtr to obiekt klasy implementującej interfejs XMLFilter (można rozszerzać standardową 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 (metoda setParent), 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.

Przykład 3. Łączenie parsera i handlera poprzez filtr

XMLReader parser = XMLReaderFactory.getXMLReader();
ContentHandler handler = new MyHandler();
XMLFilter filtr = new MyFilter();
filtr.setParent(parser);
filtr.setContentHandler(handler);
filtr.parse();

Przykład 4. FiltrySAX

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.

Zadanie 2.

Dla plików jak shop2.xml, napisz filtr SAX (podklasę XMLFilterImpl), który przepuszcza towary z kategorii podanej jako parametr konstruktora klasy.

  1. Użyj napisanej przed chwilą klasy PrintHandler i stwórz program filtrujący podany plik ze sklepem.
  2. Niech filtr dodaje pod koniec dokumentu nowy element avg zawierający średnią cenę przepuszczonych towarów.

For files such as shop2.xml, implement a SAX filter (a subclass of XMLFilterImpl) that passes through only products from a given (as a parameter) category.

  1. Use PrintHandler class written before and make a program filtering products from a shop.
  2. Let the filter add a new element avg containing average price from products passed through.

Walidacja

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).


Valid XHTML 1.1Valid CSS