Kapitola 1. Rozhraní pro práci s XML (SAX, DOM, pull)

Obsah

Základní pojmy
Cílem rozhraní je
Hlavní typy rozhraní pro zpracování XML dat:
Stromově orientovaná rozhraní (Tree-based API)
Mapují XML dokument na stromovou strukturu v paměti
Modely specifické pro konkrétní prostředí
Rozhraní založená na událostech (Event-based API)
Při analýze ("parsing") dokumentu "vysílají" zpracovávající aplikaci sled událostí.
Událostmi je např.:
SAX - příklad analýzy dokumentu
Kdy zvolit událostmi řízené rozhraní?
Vlastnosti (features) nastavitelné pro analýzu - parsing
SAX filtry
Další odkazy k SAX
Rozhraní založená na technice "pull"
Rozhraní založená na technice "pull"
Streaming API for XML (StAX)
StAX - příklad s iterátorem
StAX - příklad s kurzorem
Document Object Model (DOM)
Základní rozhraní pro tvorbu a přístup ke stromové reprezentaci XML dat.
Specifický DOM pro HTML dokumenty
Odkazy k DOM
Implementace DOM
Alternativní stromové modely - XOM
Alternativní parsery a stromové modely - NanoXML
Prakticky dobře použitelný stromový model: dom4j
Kombinace stromových a událostmi řízených přístupů
Události -> strom
Strom -> události
Virtuální objektové modely

Základní pojmy

Cílem rozhraní je

  • poskytnout jednoduchý standardizovaný přístup ke XML datům

  • "napojit" analyzátor (parser) na aplikaci a aplikace navzájem

  • odstínit aplikaci od fyzické struktury dokumentu (entity)

  • zefektivnit zpracování XML dat

Hlavní typy rozhraní pro zpracování XML dat:

  • Stromově orientovaná rozhraní (Tree-based API)

  • Rozhraní založená na událostech (Event-based API)

  • Rozhraní založená na "vytahování" událostí/prvků z dokumentu (Pull API)

Stromově orientovaná rozhraní (Tree-based API)

Mapují XML dokument na stromovou strukturu v paměti

  • dovolují libovolně procházet ("traverse") vzniklý strom;

  • nejznámější je Document Object Model (DOM) konsorcia W3C, viz http://www.w3.org/DOM

Modely specifické pro konkrétní prostředí

Rozhraní založená na událostech (Event-based API)

Při analýze ("parsing") dokumentu "vysílají" zpracovávající aplikaci sled událostí.

  • technicky realizováno jako volání metod ("callback")

  • aplikace poskytuje handlery, které volání zachytávají a zpracovávají

  • událostmi řízená rozhraní jsou "nižší úrovně" než stromová, protože

  • pro aplikaci zůstává "více práce"

  • jsou však úspornější na paměť (většinou i čas), samotná analýza totiž nevytváří žádné „trvalé“ objekty

Událostmi je např.:

  • začátek a konec dokumentu (start document, end document)

  • začátek a konec elementu (start element, end element) - předá současně i atributy

  • instrukce pro zpracování (processing instruction)

  • komentář (comment)

  • odkaz na entitu (entity reference)

  • Nejznámějším takovým rozhraním je SAX http://www.saxproject.org

SAX - příklad analýzy dokumentu

<?xml version="1.0"?>
<doc>
   <para>Hello, world!</para>
</doc>

vyprodukuje při analýze (parsingu) sled událostí:

start document
start element: doc {seznam atributů: prázdný}
start element: para {seznam atributů: prázdný}
characters: Hello, world!
end element: para
end element: doc
end document

Kdy zvolit událostmi řízené rozhraní?

  • O co snazší pro autora parseru, o to náročnější pro aplikačního programátora...

  • Aplikace si musí (někdy složitě) pamatovat stav analýzy, nemá nikdy "celý dokument pohromadě".

  • Na úlohy, které lze řešit "lokálně", bez kontextu celého dokumentu, je to vhodné rozhraní.

  • Obvykle poskytuje nejrychlejší možné zpracování.

  • Aplikační nepříjemnosti lze obejít použitím nadstaveb, např. Streaming Transformations for XML (STX)

Vlastnosti (features) nastavitelné pro analýzu - parsing

Chování parseru produkujícího SAX události je možné ovlivnit nastavením tzv. features a properties.

SAX filtry

SAX rozhraní nabízí možnost napsat třídu jako tzv. SAX filtr (přesněji implementaci rozhraní org.xml.sax.XMLFilter).

Objekt takové třídy na jedné straně události přijímá, zpracuje je a posílá dále.

Další informace k filtrování událostí naleznete např. v článku Change the events output by a SAX stream (IBM DeveloperWorks/XML).

Další odkazy k SAX

Rozhraní založená na technice "pull"

Rozhraní založená na technice "pull"

  • Aplikace "nečeká na události", ale "vytahuje si" příslušná data ze vstupního parsovaného souboru.

  • Využíváme tam, kde "víme, co ve zdroji očekávat" a "postupně si to bereme"

  • ... vlastně opak API řízeného událostmi.

  • Z hlediska aplikačního programátora velmi pohodlné, ale implementace bývají o něco pomalejší než klasická "push" událostmi řízená rozhraní.

  • Pro Javu existuje XML-PULL parser API - viz Common API for XML Pull Parsing a také

  • nově vyvíjené rozhraní Streaming API for XML (StAX) vznikající "shora i zdola" jako produkt JCP (Java Community Process).

Streaming API for XML (StAX)

Toto API se později může stát standardní součástí javového prostředí pro práci s XML, tzv. JAXP.

Nabízí dva přístupy k "pull" zpracování:

  • přístup k "vytahovaným" událostem prostřednictvím iterátoru - pohodlnější

  • nízkoúrovňový přístup přes tzv. kurzor - rychlejší

StAX - příklad s iterátorem

Příklad 1.1. StAX - přístup iterátorem

import java.io.*;
import java.util.Iterator;
import javax.xml.namespace.QName;
import javax.xml.stream.*;
import javax.xml.stream.events.*;
public class ParseByEvent {
   public static void main(String[] args) 
                        throws FileNotFoundException, XMLStreamException {
      // Use the reference implementation for the XML input factory
      System.setProperty("javax.xml.stream.XMLInputFactory", 
                                  "com.bea.xml.stream.MXParserFactory");
      // Create the XML input factory
      XMLInputFactory factory = XMLInputFactory.newInstance();
      // Create the XML event reader
      FileReader reader = new FileReader("somefile.xml");
      XMLEventReader r = 
         factory.createXMLEventReader(reader);
      // Loop over XML input stream and process events
      while(r.hasNext()) {
         XMLEvent e = r.next();
         processEvent(e);
      }
   }
/**
 * Process a single XML event
 * @param e - the event to be processed
 */
  private static void processEvent(XMLEvent e) {
     if (e.isStartElement()) {
        QName qname = ((StartElement) e).getName();
        String namespaceURI = qname.getNamespaceURI();
        String localName = qname.getLocalPart();
        Iterator iter = ((StartElement) e).getAttributes();
        while (iter.hasNext()) {
           Attribute attr = (Attribute) iter.next();
           QName attributeName = attr.getName();
           String attributeValue = attr.getValue();
        }
     }
     if (e.isEndElement()) {
        QName qname = ((EndElement) e).getName();
     }
     if (e.isCharacters()) {
        String text = ((Characters) e).getData();
     }
     if (e.isStartDocument()) {
        String version = ((StartDocument) e).getVersion();
        String encoding = ((StartDocument) e).getCharacterEncodingScheme();
        boolean isStandAlone = ((StartDocument) e).isStandalone();
     }
  }
}
[Poznámka]Poznámka

příklad převzat z Tip: Use XML streaming parsers (IBM DeveloperWorks, sekce XML).

StAX - příklad s kurzorem

Příklad 1.2. StAX - přístup kurzorem

import java.io.*;
import javax.xml.stream.*;
public class ParseByIterator {
   public static void main(String[] args) 
                        throws FileNotFoundException, XMLStreamException {
      // Use reference implementation
      System.setProperty(
         "javax.xml.stream.XMLInputFactory",
         "com.bea.xml.stream.MXParserFactory");
      // Create an input factory
      XMLInputFactory xmlif = XMLInputFactory.newInstance();
      // Create an XML stream reader
      XMLStreamReader xmlr =
         xmlif.createXMLStreamReader(new FileReader("somefile.xml"));
      // Loop over XML input stream and process events
      while (xmlr.hasNext()) {
         processEvent(xmlr);
         xmlr.next();
      }
   }
   /**
    * Process a single event
    * @param xmlr - the XML stream reader
    */
   private static void processEvent(XMLStreamReader xmlr) {
      switch (xmlr.getEventType()) {
         case XMLStreamConstants.START_ELEMENT :
            processName(xmlr);
            processAttributes(xmlr);
            break;
         case XMLStreamConstants.END_ELEMENT :
            processName(xmlr);
            break;
         case XMLStreamConstants.SPACE :
         case XMLStreamConstants.CHARACTERS :
            int start = xmlr.getTextStart();
            int length = xmlr.getTextLength();
            String text =
               new String(xmlr.getTextCharacters(), start, length);
            break;
         case XMLStreamConstants.COMMENT :
         case XMLStreamConstants.PROCESSING_INSTRUCTION :
            if (xmlr.hasText()) {
               String piOrComment = xmlr.getText();
            }
            break;
      }
   }
   private static void processName(XMLStreamReader xmlr) {
      if (xmlr.hasName()) {
         String prefix = xmlr.getPrefix();
         String uri = xmlr.getNamespaceURI();
         String localName = xmlr.getLocalName();
      }
   }
   private static void processAttributes(XMLStreamReader xmlr) {
      for (int i = 0; i < xmlr.getAttributeCount(); i++)
         processAttribute(xmlr, i);
   }
   private static void processAttribute(XMLStreamReader xmlr, int index) {
      String prefix = xmlr.getAttributePrefix(index);
      String namespace = xmlr.getAttributeNamespace(index);
      String localName = xmlr.getAttributeName(index);
      String value = xmlr.getAttributeValue(index);
   }
}
[Poznámka]Poznámka

příklad převzat z Tip: Use XML streaming parsers (IBM DeveloperWorks, sekce XML).

Document Object Model (DOM)

Základní rozhraní pro tvorbu a přístup ke stromové reprezentaci XML dat.

  • existují verze DOM Level 1, 2, 3

  • DOM je obecně nezávislý na způsobu analýzy (parsingu) vstupního XML

  • Je popsán IDL definicemi+popisy rozhraní v jednotlivých jazycích (zejm. C++ a Java)

Specifický DOM pro HTML dokumenty

  • Core (základ) DOM pro HTML je nyní "víceméně" sloučen s DOM pro XML

  • určen pro styly CSS

  • určen pro programování dynamického HTML (skriptování - VB Script, JavaScript)

  • kromě samotného dokumentu model zahrnuje i prostředí prohlížeče (např. windowsearch with www.instantweb.com, historysearch with www.instantweb.com...)

Odkazy k DOM

Implementace DOM

Alternativní stromové modely - XOM

  • XOM (XML Object Model) vznikl jako one-man-show projekt (autor Elliote Rusty Harold) rozhraní, které je "papežštější než papež" a striktně respektuje model XML dat.

  • Motivaci a specifikaci najdete na domovské stránce XOM.

  • Tam je též k získání open-source implementace XOM a

  • dokumentace API.

Alternativní parsery a stromové modely - NanoXML

  • velmi malé (co do velikosti kódu) stromové rozhraní a parser v jednom

  • dostupné jako open-source na http://nanoxml.n3.net

  • adaptované též pro mobilní zařízení

  • z hlediska rychlosti a paměťové efektivity za běhu ale nejlepší není

Prakticky dobře použitelný stromový model: dom4j

Kombinace stromových a událostmi řízených přístupů

Události -> strom

  • Je např. možné "nezajímavou" část dokumentu přeskočit nebo odfiltrovat pomocí sledování událostí a pak

  • za "zajímavé" části vytvořit strom v paměti a ten zpracovávat.

Strom -> události

  • Vytvoříme strom dokumentu (a zpracujeme ho) a

  • strom následně procházíme a generujeme události jako bychom četli výchozí soubor.

  • Toto umožňuje snadnou integraci obou typů zpracování v jedné aplikaci

Virtuální objektové modely