DieSimple API for XML (SAX) ist einDe-facto-Standard, der einApplication Programming Interface (API) zumParsen vonXML-Daten beschreibt. Die aktuelle Hauptversion SAX 2.0 wurde 2000 vonDavid Megginson veröffentlicht und istPublic Domain. Ein SAX-Parser liest XML-Daten als sequentiellenDatenstrom und ruft für im Standard definierte Ereignisse vorgegebeneRückruffunktionen(callback function) auf. Eine Anwendung, die SAX nutzt, kann eigeneUnterprogramme als Rückruffunktionen registrieren und auf diese Weise die XML-Daten auswerten.
SAX wurde ursprünglich inJava entwickelt und besteht aus einer Anzahl von Java-Interfaces, heute finden sich jedoch Implementierungen für nahezu alle gängigen Programmiersprachen. SAX unterliegt keinem formalen Komitee oder Konsortium, was für eine XML-Spezifikation eher untypisch ist, dennoch ist SAX ein De-facto-Standard. Es spezifiziert eine Menge von Methoden für den Zugriff auf XML-Dokumente mittels eines SAX-Parsers. SAX arbeitet, anders alsDOM, ereignisorientiert. Das Verarbeitungsprinzip entspricht dem Konzept einer Pipeline. SAX definiert eine Menge von Ereignissen, die beim sequentiellen Lesen eines XML-Dokuments vorkommen können. Diese Ereignisse sind zustandslos, sie referenzieren nicht auf andere, vorhergegangene Ereignisse und stehen auch sonst in keinem Verhältnis zu anderen Ereignissen. Beim Erkennen einer syntaktischen Struktur startet der SAX-Parser eine Behandlungsroutine, welche gegebenenfalls eine individuelle Behandlungsroutine des Ereignisses ausführt.
Hierdurch kann mit dem Einlesen der ersten Zeichen bereits mit der Auswertung des Dokuments begonnen werden. Dies verkürzt insbesondere in interaktiven Systemen die subjektiv gefühlte Zugriffszeit. Gleichzeitig minimiert der SAX-Parser den Speicherbedarf, da neben dem jeweils eingelesenen Element nur solche Daten im Speicher stehen, die mittels einer Behandlungsroutine explizit ausgewählt wurden.
SAX-Ereignisse werden parallel zum Einlesen des Dokuments in den Parser ausgeworfen. In der Praxis bedeutet dies, dass es SAX-Ereignisse auf nicht wohlgeformte XML-Dokumente geben kann, bevor das Dokument als ungültig erkannt wird. Daher spielt die Fehlerbehandlung bei SAX-Parsern eine wichtige Rolle, entsprechende Klassen stehen in Java zur Verfügung. Das Validieren eines XML-Dokuments vor dem Parsen mit SAX widerspricht der Natur von SAX, da hierfür zunächst das gesamte Dokument in den Speicher geladen werden müsste. Dennoch findet sich eine Vielzahl validierender SAX-Parser.
Gegeben sei folgendes Dokument:
<?xml version="1.0"?><seminararbeit><titel>DOM,SAXundSOAP</titel><inhalt><kapitelvalue="1">Einleitung</kapitel><kapitelvalue="2">Hauptteil</kapitel><kapitelvalue="3">Fazit</kapitel></inhalt></seminararbeit>
Wird das gezeigte XML-Dokument mit Hilfe eines SAX-Parsers gelesen, wirft dieser der Reihe nach die folgenden Ereignisse aus[1][2]
| SAX-Ereignis | Erläuterung |
|---|---|
startDocument() | Parser ist auf Anfang des XML-Dokuments gestoßen |
startElement("seminararbeit",[]) | ein Element mit dem Namen"seminararbeit" wurde gefunden; der 2. Parameter (die eckigen Klammern "[]") ist eine Liste aller zum Element gehörenden Attribute; da dieses Element allerdings keine Attribute hat, ist diese Liste in diesem Fall leer. |
characters("\n ") | ein SAX-Parser gibt auch sämtlicheWhitespaces aus, die er zwischen zwei Element-Tags findet;[3] in diesem Fall ist das der Zeilenumbruch (newLine, "\n") gefolgt von einem Leerzeichen, welches im XML zur besseren Lesbarkeit für die Zeileneinrückung verwendet wurde. |
startElement("titel",[]) | |
characters("DOM, SAX und SOAP") | der Inhalt des Elements"titel" |
endElement("titel") | kennzeichnet, dass das Ende des zuvor gefundenen Elements erreicht wurde |
characters("\n ") | |
startElement("inhalt",[]) | |
characters("\n ") | da die Einrückung im XML nun 2 Leerzeichen beträgt, gibt auch das Ereignis 2 Leerzeichen aus |
startElement("kapitel", ["value="1""]) | der 2. Parameter enthält eine Liste sämtlicher Attribute; in diesem Fall enthält die Liste nur ein einziges Listenelement, nämlich "value=1". |
characters("Einleitung") | |
endElement("kapitel") | |
characters("\n ") | |
startElement("kapitel", ["value="2""]) | |
characters("Hauptteil") | |
endElement("kapitel") | |
characters("\n ") | |
startElement("kapitel", ["value="3""]) | |
characters("Fazit") | |
endElement("kapitel") | |
characters("\n ") | |
endElement("inhalt") | |
characters("\n") | da diese Zeile im XML nicht mehr eingerückt ist, wird nur noch "\n" (ohne folgende Leerzeichen) ausgegeben |
endElement("seminararbeit") | |
endDocument() | Parser hat Ende des XML-Dokumentes erreicht |
Bei jedem Ereignis unterbricht der Parser seine Arbeit und wartet darauf, dass er vom Dokument-Handler die Arbeitserlaubnis zurückbekommt. Dieser kann in der Zwischenzeit zur Auswertung des Ereignisses eine Behandlungsroutine starten. Dabei müssen jedoch nur für solche Ereignisse Behandlungsroutinen geschrieben werden, die für die weitere Verarbeitung auch von Interesse sind – ansonsten wird die Kontrolle sofort wieder an den Parser zurückgegeben.
Im folgenden Beispiel inJava soll im Rahmen einer Dokumentenanalyse der Titel und die Anzahl der Kapitel ausgelesen und am Ende ausgegeben werden. Dafür müssen zunächst entsprechende SAX-Klassen importiert werden und der SAX-Parser initialisiert werden. Zusätzlich muss ein Dokument-Handler gestartet werden, der über die Ereignisse vom Parser informiert wird. Dieser Dokument-Handler beinhaltet für das Beispiel folgende Methoden für die Ereignisse „characters“, „startElement“ und „endDocument“:
publicintcount=0;publicbooleantitel=false;publicStringseminararbeit="";publicvoidcharacters(char[]ch,intstart,intlength)throwsSAXException{if(titel==true&&seminararbeit.equals("")){seminararbeit=newString(ch,start,length);titel=false;}}publicvoidstartElement(Stringname,AttributeListatts)throwsSAXException{if(name.equals("kapitel"))++count;if(name.equals("titel"))titel=true;}publicvoidendDocument()throwsSAXException{System.out.println(seminararbeit+" enthält "+count+" Kapitel");}
In LuaExpat[4] (Lua mit einem SAX-Parser) werden für das Parsen von XML-Dateien zunächst sogenannte „Callbacks“ vorbereitet, mit denen der Parser seine Daten an das ihn aufrufende Anwendungsprogramm übergeben kann. Im Beispiel sind das einfache Aufrufe von Ausgabefunktionen. Das folgende Programm gibt eine XML-Datei als einfachen Text aus.
require"lxp"xml_file="irgendeineXMLdatei.xml"dolocalcount=0callbacks={StartElement=function(parser,name,attributes)-- StartTag ausgeben--io.write("+ ",string.rep(" ",count*2),name,"\n")count=count+1-- Attribute ausgeben --localattributenamefor_,attributenameinipairs(attributes)doio.write(" ",string.rep(" ",count*2),attributename,'="',attributes[attributename],'"\n')endend,EndElement=function(parser,name)-- Endtag ausgeben --count=count-1io.write("- ",string.rep(" ",count*2),name,"\n")end,CharacterData=function(parser,text)-- Text ausgeben --io.write("----------\n",text,"\n----------\n")end}endp=lxp.new(callbacks)-- Generiere eine Instanz des Parsersfile=assert(io.open(xml_file.."","r"))p:parse(file:read("*all"))-- Parsen der gesamten Datei-- (Auch zeilenweises Einlesen wäre möglich)file:close();collectgarbage()p:parse()-- Beendet das Dokumentp:close()-- Schließt den Parser