Das Package org.xml.sax

(Auszug aus "XML in a Nutshell" von Elliotte Rusty Harold & W. Scott Means)

Das Package org.xml.sax enthält den Kern von SAX, d.h. die Interface-Definitionen und Klassen, die die Simple API for XML ausmachen.

 


Das Interface Attributes

Die Attributliste eines Start-Tags wird durch eine Implementierung des Interfaces Attributes repräsentiert. Die Reihenfolge der Attribute in der Liste ist dabei nicht unbedingt identisch mit der Reihenfolge im XML-Dokument. Man erhält Objekte vom Typ Attributes als Argumente der startElement( )-Methode aus dem ContentHandler-Interface. Um einzelne Attribute anzusprechen, hat man die folgenden drei Möglichkeiten:

  • über eine Zahl, nämlich die Position in der Attributliste
  • über den URI des Namensraums und den lokalen Namen
  • über den vollständig-qualifizierten Namen

Die Attribute zur Deklaration von Namensräumen (xmlns und xmlns:präfix) sind auf diese Weise nicht zugänglich, außer wenn das Feature "http://xml.org/sax/features/namespace-prefixes" gesetzt ist. Standardmäßig steht dieses Attribut auf false.

Wenn das Feature "http://xml.org/sax/features/namespace-prefixes" false ist, kann es sein, dass kein Zugriff auf qualifizierte Namen möglich ist. Wenn das Feature "http://xml.org/sax/features/namespaces" false ist, kann es sein, dass lokale Namen und Namensraum-URIs nicht verfügbar sind.

package org.xml.sax;

public interface Attributes {

  public int    getLength( );
  public String getURI(int index);
  public String getLocalName(int index);
  public String getQName(int index);
  public int    getIndex(String uri, String localName);
  public int    getIndex(String qualifiedName);
  public String getType(int index);
  public String getType(String uri, String localName);
  public String getType(String qualifiedName);
  public String getValue(String uri, String localName);
  public String getValue(String qualifiedName);
  public String getValue(int index);

}

 


Das Interface ContentHandler

Das Interface ContentHandler ist der Schlüssel zu SAX. Will man mit SAX arbeiten, benötigt man dieses Interface fast immer. Eine Instanz dieses Interfaces übergibt man an den XMLReader (d.h. den Parser) mit Hilfe seiner Methode setContentHandler( ). Der Zweck von ContentHandler ist die Bereitstellung von Callbacks: Während der Parser das Dokument liest, ruft er die jeweils passenden Methoden des ContentHandler auf, um dem Programm mitzuteilen, was er gerade gelesen hat.

package org.xml.sax;

public interface ContentHandler {

 public void setDocumentLocator(Locator locator);
 public void startDocument( ) throws SAXException;
public void endDocument( ) throws SAXException;
 public void startPrefixMapping(String prefix, String uri)
  throws SAXException;
 public void endPrefixMapping(String prefix) throws SAXException;
 public void startElement(String namespaceURI, String localName,
  String qualifiedName, Attributes atts) throws SAXException;
 public void endElement(String namespaceURI, String localName,
  String qualifiedName) throws SAXException;
 public void characters(char[] text, int start, int length)
  throws SAXException;
 public void ignorableWhitespace(char[] text, int start, int length)
  throws SAXException;
 public void processingInstruction(String target, String data)
  throws SAXException;
 public void skippedEntity(String name) throws SAXException;

}

 


Das Interface DTDHandler

Wenn der setDTDHandler( )-Methode von XMLReader eine Instanz des DTDHandler-Interfaces übergeben wurde, wird das Programm benachrichtigt, wenn in der DTD Deklarationen von Notationen und ungeparsten Entities auftauchen. Man kann die so erhaltenen Informationen speichern und später verwenden, um Informationen über nicht ersetzte Entities zu bekommen, die beim Lesen des Dokuments aufgefallen sind:

package org.xml.sax;

public interface DTDHandler {

 public void notationDecl(String name,  String publicID, String systemID)
  throws SAXException;
 public void unparsedEntityDecl(String name, String publicID,
  String systemID, String notationName) throws SAXException;

}

 


Das Interface EntityResolver

Übergibt man dem XMLReader eine Instanz des Interfaces EntityResolver, erhält man Kontrolle über den Zugriff des Parsers auf externe Entities. Zu diesen externen Entities gehört auch die externe DTD-Teilmenge. Eine denkbare Anwendung wäre etwa, die originalen Entities durch andere zu ersetzen. Zum Beispiel könnte man eine Referenz auf eine im Internet liegende DTD durch eine lokale Kopie ersetzen oder nach den Stellen in einem Verzeichnis suchen, die einen bestimmten PUBLIC-Identifier verwenden.

package org.xml.sax;

public interface EntityResolver {

public InputSource resolveEntity  (String publicID, String systemID)
  throws SAXException, IOException;

}

 


Das Interface ErrorHandler

Durch eine Instanz des Interfaces ErrorHandler kann man eine individuelle Fehlerbehandlung in den XML-Parser integrieren. Der XMLReader erhält den ErrorHandler durch Aufruf der Methode setErrorHandler( ). Zum Beispiel können Sie festlegen, dass ein Fehler beim Validieren des Dokuments einen Programmabbruch bewirkt, indem Sie in der error()-Methode eine Exception auslösen. Die drei Methoden dieses Interfaces erhalten je eine SAXParseException, die die detaillierten Angaben über den Fehlergrund und -ort im XML-Dokument enthalten:

package org.xml.sax;

public interface ErrorHandler {

 public void warning(SAXParseException exception) throws SAXException;
 public void error(SAXParseException exception) throws SAXException;
 public void fatalError(SAXParseException exception)
  throws SAXException;

}

Warnungen sind Hinweise auf mögliche Probleme, die der Parser erkannt hat, die aber nicht unbedingt eine Verletzung der Wohlgeformtheits- oder Gültigkeitsregeln darstellen. Zum Beispiel könnte ein xml:lang-Attribut keinen gültigen Wert nach ISO-639 enthalten. Die häufigsten Ursachen von Fehlern sind aber Verletzungen der Gültigkeitsregeln: Der Parser sollte darüber informieren, aber das XML-Dokument weiterverarbeiten. Fatale Fehler sind diejenigen, bei denen die Wohlgeformtheit betroffen ist: Der Parser kann nicht weiterarbeiten, nachdem ein solcher Fehler aufgetreten ist. Einige Parser melden Fehler bei der Wohlgeformtheit von Namensräumen als fatale Fehler. Andere melden sie als nicht-fatale Fehler.

 


Das Interface Locator

Im Unterschied zu den meisten anderen Interfaces im Package org.xml.sax ist der Locator kein Interface, das Sie selbst implementieren müssen: Dieses Interface wird vom Parser implementiert. Dazu kann der Parser die Methode setDocumentLocator( ) in der ContentHandler-Instanz aufrufen. Dies muss vor dem Aufruf von startDocument( ) geschehen. Sie können dann eine Referenz auf den DocumentLocator in einem Feld Ihrer ContentHandler-Klasse speichern, um sie später zu benutzen:

private Locator locator;

public void setDocumentLocator(Locator locator) {
this.locator = locator;
}

Den gespeicherten Locator können Sie innerhalb von Methoden wie startElement() oder characters() des eigentlichen ContentHandler benutzen, um die aktuelle Zeile und Spalte bestimmen zu lassen. Im Locator steht zum Beispiel, dass das aktuelle Start-Tag in Zeile 17, Spalte 3 der URL "http://www.slashdot.org/slashdot.xml" beginnt:

package org.xml.sax;

public interface Locator {

 public String getPublicId( );
public String getSystemId();
 public int  getLineNumber( );
 public int  getColumnNumber( );

}

 


Das Interface XMLFilter

Ein XMLFilter ist ein XMLReader, der seine Events nicht von einer der üblichen Eingabequellen wie z.B. einem InputStream erhält, sondern von einem anderen XMLReader. Filter sitzen damit zwischen dem XML-Dokument und der Anwendung. Ihr Zweck ist die Modifikation des XML-Dokuments vor der Übergabe an die Anwendung. Dieses Interface wird gewöhnlich nicht direkt implementiert. Es ist fast immer einfacher, stattdessen die vollständigere Klasse org.xml.sax.helpers.XMLFilterImpl zu verwenden.

package org.xml.sax;

public interface XMLFilter extends XMLReader {

  public void   setParent(XMLReader);
  public XMLReader getParent( );

 }

 


Das Interface XMLReader

Der XMLReader ist der eigentliche Parser, der ein oder mehrere XML-Dokumente liest und analysiert. Dieses Interface wird nicht vom Anwender implementiert, sondern man verwendet die Klasse org.xml.sax.helpers.XMLReaderFactory, um eine parserspezifische Implementierung zu erhalten. Über die verschiedenen set-Methoden wird der Parser konfiguriert. Schließlich wird eine parse()-Methode aufgerufen. Der Parser liest das übergebene Dokument und ruft die Methoden seines ContentHandler, seines ErrorHandler, seines EntityResolver und/oder seines DTDHandler auf:

package org.xml.sax;

public interface XMLReader {

  public boolean getFeature(String name)
   throws SAXNotRecognizedException, SAXNotSupportedException;
  public void  setFeature(String name, boolean value)
   throws SAXNotRecognizedException, SAXNotSupportedException;
  public Object getProperty(String name)
   throws SAXNotRecognizedException, SAXNotSupportedException;

  public void  setProperty(String name, Object value)
 throws SAXNotRecognizedException, SAXNotSupportedException;
  public void      setEntityResolver(EntityResolver resolver);
  public EntityResolver getEntityResolver( );
  public void      setDTDHandler(DTDHandler handler);
  public DTDHandler   getDTDHandler( );
  public void ssetContentHandler(ContentHandler handler);
public ContentHandler getContentHandler( );
  public void           setErrorHandler(ErrorHandler handler);
  public ErrorHandler   getErrorHandler( );

  public void parse(InputSource input) throws IOException, SAXException;
  public void parse(String systemID) throws IOException, SAXException;

}

 


Die Klasse InputSource

Die Klasse InputSource ist eine Abstraktion einer Datenquelle, aus der die rohen Bytes eines XML-Dokuments gelesen werden. Eine InputSource-Instanz kann einen SYSTEM-Identifier, einen PUBLIC-Identifier, einen InputStream und/oder einen Reader verstecken. Wenn der Parser eine InputSource erhält, versucht er, die Daten aus dem Reader zu lesen. Wenn die InputSource keinen Reader hat, versucht der Parser, den InputStream zu lesen. Dabei berücksichtigt er die angegebene Zeichenkodierung. Ist keine Zeichenkodierung angegeben, muss er selbst die Zeichenkodierung ermitteln, indem er die XML-Deklaration analysiert. Zu guter Letzt baut der Parser eine Verbindung zu der URL auf, die im SYSTEM-Identifier angegeben ist, wenn weder ein Reader noch ein InputStream vorhanden ist.

package org.xml.sax;

public class InputSource {

  public InputSource( );
  public InputSource(String systemID);
  public InputSource(InputStream byteStream);
  public InputSource(Reader reader);

  public void        setPublicId(String publicID);
  public String      getPublicId( );
  public void        setSystemId(String systemID);
  public String      getSystemId( );
  public void        setByteStream(InputStream byteStream);
  public InputStream getByteStream( );
  public void        setEncoding(String encoding);
  public String      getEncoding( );
  public void        setCharacterStream(Reader reader);
  public Reader      getCharacterStream( );

}

 


Die Klasse SAXException

Die meisten von SAX-Methoden ausgelösten Exceptions sind Instanzen der Klasse SAXException oder einer ihrer Unterklassen. Es gibt eine einzige Ausnahme von dieser Regel, nämlich die Methode parse() des XMLReader, die im Fall von I/O-Problemen eine IOException auslösen kann. Ein typisches Beispiel wäre etwa der Abbruch einer TCP-Verbindung, wenn ein Dokument über das Internet gelesen wird.

Eine SAXException erbt von ihrer Superklasse die üblichen Methoden einer Exception, wie getMessage() und printStackTrace(). Darüber hinaus kennt die SAXException aber auch eine Methode getException( ), mit der man eine andere Exception verpacken kann, die den eigentlichen Grund eines Problems darstellt:

package org.xml.sax;

public class SAXException extends Exception {

  public SAXException(String message);
  public SAXException(Exception ex);
  public SAXException(String message, Exception ex);

  public String    getMessage( );
  public Exception getException( );
  public String    toString( );

}

 


SAXParseException

Wenn beim Parsen eines Dokuments eine Verletzung der Wohlgeformtheitsregeln festgestellt wird, löst der Parser eine SAXParseException aus. Die SAXParseException ist eine Unterklasse der SAXException, die ebenfalls an den ErrorHandler übergeben wird. Der ErrorHandler entscheidet dann, ob er den Parser durch Auslösen der Exception unterbricht oder den Fehler ignoriert.

Zusätzlich zu den Methoden seiner Superklasse kennt die SAXParseException Methoden zur Abfrage der Zeilen- und Spaltennummer, des SYSTEM- und des PUBLIC-Identifiers des Dokuments, in dem der Fehler auftrat:

package org.xml.sax;

public class SAXParseException extends SAXException {

  public SAXParseException(String message, Locator locator);
  public SAXParseException(String message, Locator locator,  Exception e);
  public SAXParseException(String message,
   String publicID,  String systemID, int lineNumber, int columnNumber);
  public SAXParseException(String message,
   String publicID,  String systemID, int lineNumber, int
 columnNumber, Exception e);

  public String getPublicId( );
  public String getSystemId( );
  public int    getLineNumber( );
  public int    getColumnNumber( );

}

 


SAXNotRecognizedException

Eine SAXNotRecognizedException wird ausgelöst, wenn Sie versuchen, ein Property oder ein Feature zu setzen, das der Parser nicht kennt. Neben dem Konstruktor kennt diese Exception nur die Methoden ihrer Superklasse:

package org.xml.sax;

public class SAXNotRecognizedException extends SAXException {

  public SAXNotRecognizedException( );
  public SAXNotRecognizedException(String message);

}

 


SAXNotSupportedException

Die SAXNotSupportedException wird verwendet, wenn der Parser ein Feature oder ein Property zwar kennt, es aber entweder nicht lesen oder setzen kann oder wenn der bestimmte Wert, auf den Sie es zu setzen versuchen, nicht zulässig ist. Auch hier gibt es nur einen einzigen Konstruktor sowie die Methoden der Superklasse:

 

package org.xml.sax;

public class SAXNotSupportedException extends SAXException {

  public SAXNotSupportedException( );
  public SAXNotSupportedException(String message);

}
Tipp der data2type-Redaktion:
Zum Thema XML bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

  


Copyright © 2005 O'Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XML in a Nutshell" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

O’Reilly Verlag GmbH & Co. KG, Balthasarstraße 81, 50670 Köln, kommentar(at)oreilly.de