r09-01.doc

(310 KB) Pobierz
Helion









Rozdział 1 ¨ Pierwsze kroki (Nagłówek strony)

Rozdział 9

w oryginale 12

.
Java i SAX

Poprzedni rozdział w całości poświęciliśmy użyciu Javy do obsługi modelu DOM XML. Jednak dla wielu osób użycie DOM jest zbyt skomplikowane, a traktowanie dokumentu jako drzewa uważają za nadmiernie skomplikowane. Uważają, że to nie oni powinni przeszukiwać dokument, ale to cały dokument powinien zostać im udostępniony. Takie właśnie głosy stały się przyczynkiem powstania Prostego interfejsu API dla XML (SAX, Simple API for XML), któremu poświęcimy cały ten rozdział. SAX jest znacznie prostszy w użyciu w przypadku wielu, a być może nawet większości zastosowań XML.

Być może będziesz zaskoczony, jeśli się dowiesz, że myśl przewodnią twórców SAXa wcielaliśmy w życie w całym poprzednim rozdziale. Jak pamiętasz, do każdego węzła drzewa DOM stosowaliśmy rekursywną metodę display, w tej metodzie używaliśmy z kolei instrukcji switch. Poszczególne frazy case instrukcji switch obsługiwały różne rodzaje węzłów:

public static void display(Node node, String indent)

{

  if(node == null) {

    return;

  }

 

  int type = node.getNodeType();

 

  switch (type) {

      case Node.DOCUMENT_NODE: {

          displayStrings[numberDisplayLines] = indent;

          displayStrings[numberDisplayLines] +=

            "<?xml version=\"1.0\" encoding=\"iso-8859-2\"?>";

          numberDisplayLines++;

          display(((Document)node).getDocumentElement(), "");

          break;

      }

      case Node.ELEMENT_NODE: {

          displayStrings[numberDisplayLines] = indent;

          displayStrings[numberDisplayLines] += "<";

          displayStrings[numberDisplayLines] += node.getNodeName();

 

          int length = (node.getAttributes() != null) ?

            node.getAttributes().getLength() : 0;

          Attr attributes[] = new Attr[length];

          for (int loopIndex = 0; loopIndex < length; loopIndex++){

            attributes[loopIndex] =

            (Attr)node.getAttributes().item(loopIndex);

          }

      }

      .

      .

      .

Dalsze frazy case obsługiwały instrukcje przetwarzania i inne części dokumentu XML.

W zasadzie przetwarzanie dokumentów za pomocą SAX wygląda tak samo. Zamiast nawigować sami po dokumencie, korzystamy z dokumentu opisując sposób obsługi poszczególnych przypadków. SAX jest oparty na obsłudze zdarzeń, co oznacza, że kiedy parser SAX napotyka element, traktuje to jako zdarzenie i wywołuje fragment kodu obsługujący elementy; kiedy napotyka instrukcję przetwarzania, wywołuje znów inny fragment kodu, i tak dalej. W ten sposób nie trzeba samemu po dokumencie nawigować – to dokument „sam się przetwarza”, wystarczy tylko odpowiednio reagować. To, że znakomita większość poprzednich przykładów na takiej technice się opiera, wskazuje, jak użyteczna jest ta technika.

Używany przez nas w poprzednim rozdziale pakiet XML for Java firmy alphaWorks

W.D.: AlphaWorks to website IBM

obsługuje także SAX. Oznacza to, że możemy użyć tych samych plików JAR, co w poprzednim rozdziale; wystarczy tylko do zmiennej CLASSPATH dopisać na końcu ścieżki do tych plików (pamiętaj, że wszystko ma być w jednym wierszu):

C:\SET CLASSPATH=%CLASSPATH%;C:\xmlparser\XML4J_3_0_1\xerces.jar;

C:\xmlparser\XML4J_3_0_1\xercesSamples.jar

Można też, tak jak poprzednio, użyć przełącznika -classpath:

%javac -classpath C:\xmlparser\XML4J_3_0_1\xerces.jar;

C:\xmlparser\XML4J_3_0_1\xercesSamples.jar browser.java

%java -classpath C:\xmlparser\XML4J_3_0_1\xerces.jar;

C:\xmlparser\XML4J_3_0_1\xercesSamples.jar browser

Praca z interfejsem SAX

Teraz przejdziemy do pierwszego przykładu zastosowania interfejsu SAX. Oczywiście, tak samo jak poprzednio, zaczniemy od zliczania wystąpień elementu KLIENT w dokumencie zamówienia.xml

ta sama uwaga, co w poprzednim rozdziale – jest to plik orders.xml, a nie customer.xml (także dalej)

. Oto nasz plik roboczy XML:

<?xml version="1.0" encoding="iso-8859-2"?>

<DOKUMENT>

  <KLIENT STATUS="Rzetelny kredytobiorca">

    <IMIĘNAZWISKO>

      <NAZWISKO>Smith</NAZWISKO>

      <IMIĘ>Sam</IMIĘ>

    </IMIĘNAZWISKO>

    <DATA>15 października 2001</DATA>

    <ZAMÓWIENIA>

      <POZYCJA>

        <PRODUKT>Pomidory</PRODUKT>

        <ILOŚĆ>8</ILOŚĆ>

        <CENA>5zł</CENA>

      </POZYCJA>

     <POZYCJA>

        <PRODUKT>Pomarańcze</PRODUKT>

        <ILOŚĆ>24</ILOŚĆ>

        <CENA>9.98zł</CENA>

      </POZYCJA>

    </ZAMÓWIENIA>

  </KLIENT>

  <KLIENT STATUS="Kredytobiorca niesolidny">

    <IMIĘNAZWISKO>

      <NAZWISKO>Jones</NAZWISKO>

      <IMIĘ>Polly</IMIĘ>

    </IMIĘNAZWISKO>

    <DATA>20 października 2001</DATA>

    <ZAMÓWIENIA>

      <POZYCJA>

        <PRODUKT>Chleb</PRODUKT>

        <ILOŚĆ>12</ILOŚĆ>

        <CENA>28.80zł</CENA>

      </POZYCJA>

      <POZYCJA>

        <PRODUKT>Jabłka</PRODUKT>

        <ILOŚĆ>6</ILOŚĆ>

        <CENA>6.00zł</CENA>

      </POZYCJA>

    </ZAMÓWIENIA>

  </KLIENT>

  <KLIENT STATUS="Rzetelny kredytobiorca">

<IMIĘNAZWISKO>

      <NAZWISKO>Weber</NAZWISKO>

      <IMIĘ>Bill</IMIĘ>

    </IMIĘNAZWISKO>

    <DATA>25 października 2001</DATA>

    <ZAMÓWIENIA>

      <POZYCJA>

        <PRODUKT>Asparagus</PRODUKT>

        <ILOŚĆ>12</ILOŚĆ>

        <CENA>11.90zł</CENA>

      </POZYCJA>

      <POZYCJA>

        <PRODUKT>Sałata</PRODUKT>

        <ILOŚĆ>6</ILOŚĆ>

        <CENA>31.50zł</CENA>

      </POZYCJA>

    </ZAMÓWIENIA>

  </KLIENT>

</DOKUMENT>

Nasz nowy program oprzemy na nowej klasie FirstParserSAX. Będziemy potrzebować obiektu tej klasy, aby przekazać go parserowi SAX, aby ten z kolei mógł wywoływać metody przekazanego obiektu przy napotykaniu elementów, początku dokumentu, końca dokumentu i tak dalej. Zaczniemy od utworzenia obiektu klasy FirstParserSAX o nazwie SAXHandler:

import org.xml.sax.*;

import org.apache.xerces.parsers.SAXParser;

public class FirstParserSAX

{

  public static void main(String[] args)

  {

    FirstParserSAX SAXHandler = new FirstParserSAX();

      .

      .

      .

  }

}

Następnie tworzymy parser SAX, którego będziemy używać. Obiekt parsera jest obiektem klasy org.apache.xerces.parsers.SAXParser (tak jak w poprzednim rozdziale parser DOM był obiektem klasy org.apache.xerces.parsers.DOMParser). Aby użyć klasy SAXParser, importujemy odpowiednie klasy z pakietu org.xml.sax i możemy utworzyć nowy parser SAX o nazwie parser:

import org.xml.sax.*;

import org.apache.xerces.parsers.SAXParser;

public class FirstParserSAX

{

  public static void main(String[] args)

  {

    FirstParserSAX SAXHandler = new FirstParserSAX();

 

    SAXParser parser = new SAXParser();

      .

      .

      .

  }

}

Klasa SAXParser pochodzi z klasy XMLParser, która z kolei pochodzi z klasy java.lang.Object:

java.lang.Object

|

+--org.apache.xerces.framework.XMLParser

   |

   +--org.apache.xerces.parsers.SAXParser

Konstruktorem klasy SAXParser jest SAXParser(); metody klasy SAXParser zestawiono w tabeli 9.1. Konstruktorem klasy XMLParser jest protectedXMLParser().

końcówka zdania świadomie pominięta – proszę sprawdzić akapit „Do Składacza” zaraz za tabelą 9.1.

Tabela 9.1.
Metody SAXParser

Metoda

Opis

void attlistDecl(int elementTypeIndex, int attrNameIndex, int attType, java.lang.String enumString, int attDefaultType, int attDefaultValue)

Metoda zwrotna deklaracji atrybutu.

void characters(char[] ch, int start, int length)

Metoda zwrotna znaków z tablicy znakowej.

void comment(int dataIndex)

Metoda zwrotna komentarzy.

void commentInDTD(int dataIndex)

Metoda zwrotna komentarzy występujących w DTD.

void elementDecl(int elementTypeIndex, XMLValidator.ContentSpec contentSpec)

Metoda zwrotna deklaracji elementu.

void endDATA()

Metoda zwrotna końca sekcji CDATA.

void endDocument()

Metoda zwrotna końca dokumentu.

void endDTD()

Wywoływana przy napotkaniu końca DTD.

void endElement(int elementTypeIndex)

Metoda zwrotna końca elementów.

void endEntityReference(int entityName, int entityType, int entityContext)

Metoda zwrotna końca odwołania do encji.

void endNameSpaceDeclScope(int prefix)

Metoda zwrotna końca zakresu deklaracji przestrzeni nazw.

void externalEntityDecl(int entityName, int publicId, int systemId)

Metoda zwrotna deklaracji parsowanej zewnętrznej encji parametrycznej.

void externalPEDecl(int entityName, int publicId, int systemId)

Metoda zwrotna deklaracji zewnętrznej encji parametrycznej.

ContentHandler getContentHandler()

Instrukcja pobierająca treść procedury obsługi zdarzenia.

protected DeclHandler getDeclHandler()

Instrukcja pobierająca procedurę obsługi zdarzenia deklaracji DTD.

DTDHandler getDTDHandler()

Instrukcja pobierająca bieżącą procedurę obsługi zdarzenia.

boolean getFeature(java.lang.String featureId)

Pobiera bieżący stan wskazanej cechy parsera.

java.lang.String[] getFeaturesRecognized()

Pobiera listę cech rozpoznawanych przez parser.

protected LexicalHandler getLexicalHandler()

Instrukcja pobierająca procedurę obsługi leksykalnej parsera.

protected boolean getNamespacePrefixes()

Instrukcja pobierająca wartość przedrostków przestrzeni nazw.

java.lang.String[] getPropertiesRecognized()

Pobiera listę właściwości rozpoznawanych przez parser.

java.lang.Object getProperty(java.lang.String propertyId)

Pobiera wartość właściwości parsera SAX2.

void ignorableWhitespace(int dataInde...

Zgłoś jeśli naruszono regulamin