Einführung in JAXP 1.1

(Auszug aus "Java und XSLT" von Eric M. Burke)

TrAX war eine großartige Idee, und die ursprüngliche Arbeit und die Konzepte dahinter wurden in JAXP (Java API for XML Processing) Version 1.1 aufgenommen. Wenn Sie im Web nach TrAX suchen und das Gefühl haben, nicht viel Brauchbares zu finden, liegt das nur daran, daß der Fokus sich von TrAX zu JAXP verschoben hat. Obwohl der Name sich geändert hat, ist das Konzept gleichgeblieben: JAXP bietet ein Standard-Java-Interface zu vielen XSLT-Prozessoren, was Ihnen die Möglichkeit bietet, aus Ihrer bevorzugten, zugrundeligenden Implementierung zu wählen und dabei die Portierbarkeit zu wahren.

Bei seiner ersten Veröffentlichung im März 2000 nutzte Suns JAXP 1.0 neben XML 1.0 auch XML Namespaces 1.0, SAX 1.0 und DOM Level 1. JAXP ist eine Standard-Erweiterung für Java, was bedeutet, daß Sun über seinen Java Community Process (JCP) eine Spezifikation und eine Referenz-Implementierung anbietet. JAXP 1.1 folgt denselben grundlegenden Design-Philosophien wie JAXP 1.0, erweitert um Unterstützung für DOM Level 2, SAX 2 und XSLT 1.0. Ein Tool wie JAXP ist deswegen notwendig, weil die XSLT-Spezifikation nur eine Transformationssprache definiert; sie sagt nichts darüber aus, wie man einen Java XSLT-Prozessor zu schreiben hat. Obwohl sie alle dieselben grundlegenden Aufgaben ausführen, verwendet jeder Prozessor eine andere API und hat seinen eigenen Satz von Programmierkonventionen.

JAXP ist weder XML-Parser noch XSLT-Prozessor. Statt dessen bietet es ein allgemeines Java-Interface, das die Unterschiede zwischen den verschiedenen Implementierungen der unterstützen Standards maskiert. Durch Einsatz von JAXP kann Ihr Code die Abhängigkeit von spezifischen Anbieterstandards vermeiden und so flexibler an neuere Tools angepaßt werden, wenn welche verfügbar werden.

Der Schlüssel zu JAXPs Design ist das Konzept von Adapterschichten, sogenannten Plugability-Layers. Diese Schichten bieten konsistente Java-Schnittstellen zu den darunterliegenden SAX-, DOM- und XSLT-Implementierungen. Um eine dieser APIs zu nutzen, müssen Sie an eine Factory-Klasse kommen, ohne Xalan- oder SAXON-Code in Ihrer Anwendung einzubauen. Das wird über einen Lookup-Mechanismus erreicht, der auf den Java-Systemeigenschaften beruht. Da drei separate Plugability-Layer verwendet werden, können Sie den DOM-Parser eines Anbieters nutzen, den SAX-Parser eines anderen Anbieters und einen XSLT-Prozessor von wieder einem anderen Anbieter. In der Praxis werden Sie wahrscheinlich einen zum XSLT-Prozessor kompatiblen DOM-Parser einsetzen müssen, wenn Sie den DOM-Baum direkt transformieren wollen. Die folgende Abbildung zeigt die High-Level-Architektur von JAXP 1.1.

Abbildung: JAXP 1.1-Architektur

Abbildung: JAXP 1.1-Architektur

Wie Sie sehen, hat der Anwendungscode nicht unmittelbar mit der spezifischen Parser- oder Prozessor-Implementierung, wie SAXON oder Xalan, zu tun. Statt dessen schreiben Sie Ihren Code gegen abstrakte, von JAXP gelieferte Klassen. Dieser Umweg erlaubt Ihnen die Wahl zwischen verschiedenen Implementierungen, ohne Ihre Anwendung neu kompilieren zu müssen.

Der Hauptnachteil einer API wie JAXP ist der "kleinste gemeinsame Nenner-Effekt", der allen AWT-Programmierern bekannt sein dürfte. Um die Portierbarkeit zu maximieren, bietet JAXP in der Hauptsache die Funktionalität, die von allen XSLT-Prozessoren unterstützt wird. Das heißt beispielsweise, daß Xalans eigene XPath-APIs in JAXP nicht enthalten sind. Um die Mehrwerte eines bestimmten Prozessors auszunutzen, müssen Sie zum nicht-portierbaren Code zurückkehren und somit die Vorteile des Konzepts der Plugability-Layer verneinen. Glücklicherweise werden die geläufigsten Aufgaben von JAXP unterstützt, so daß die Rückkehr zum implementierungsspezifischen Code die Ausnahme sein dürfte.

Obwohl die JAXP-Spezifikation keinen XML-Parser oder XSLT-Prozessor definiert, enthalten die Referenzimplementierungen diese Tools. Diese Referenzimplementierungen sind Open Source-Apache-XML-Tools (Crimson und Xalan) mit vollständig verfügbarem Quellcode.

JAXP 1.1-Implementierung

Sie haben es erraten – wir implementieren jetzt das einfache Beispiel nochmal mit Suns JAXP 1.1. Hinter den Kulissen kann dafür jeder JAXP 1.1-kompatible XSLT-Prozessor verwendet werden; der Code wurde entwickelt und getestet mit Apaches Xalan 2-Prozessor. Das folgende Beispiel zeigt den kompletten Quellcode.

Beispiel: BeispielJaxp.java

package kapitel5;

import java.io.*;

/**
 * Ein einfaches Beispiel für JAXP 1.1
 */
public class BeispielJaxp {
  
  /**
   * Akzeptiert zwei Kommandozeilenparameter: den Namen einer XML-Datei und
   * den Namen eines XSLT-Stylesheets. Das Ergebnis der Transformation wird auf
   * stdout ausgegeben.
   */
  public static void main(String[] args)
     throws javax.xml.transform.TransformerException {
   if (args.length != 2) {
     System.err.println("Syntax:");
     System.err.println(" java " + BeispielJaxp.class.getName( )
        + " xmlDateiname xsltDateiname");
     System.exit(1);
  }
  File xmlDatei = new File(args[0]);
  File xsltDatei = new File(args[1]);
       
  javax.xml.transform.Source xmlSource =
      new javax.xml.transform.stream.StreamSource(xmlDatei);
  javax.xml.transform.Source xsltSource =
      new javax.xml.transform.stream.StreamSource(xsltDatei);
  javax.xml.transform.Result ergebnis =
      new javax.xml.transform.stream.StreamResult(System.out);
       
  // eine Instanz von TransformerFactory wird erzeugt
  javax.xml.transform.TransformerFactory transFact =
      javax.xml.transform.TransformerFactory.newInstance( );
       
  javax.xml.transform.Transformer trans =
      transFact.newTransformer(xsltSource);
       
  trans.transform(xmlSource, ergebnis);
  }
}

Wie auch in den vorangegangenen Beispielen, werden explizite Paketnamen im Code verwendet, um hervorzuheben, welche Klassen Bestandteil von JAXP sind. In zukünftigen Beispielen werden import-Statements bevorzugt, weil dann weniger zu tippen ist und der Code lesbarer wird. Unser neues Programm beginnt mit der Deklaration, daß es eine TransformerException auslösen kann:

public static void main(String[] args)
     throws javax.xml.transform.TransformerException {

Das ist eine Allzweck-Exception, die für alles steht, was während des Transformationsprozesses schiefgehen könnte. In anderen Prozessoren werden dem Aufrufer typischerweise SAX-spezifische Exceptions mitgeteilt. In JAXP kann die TransformerException jeden Typ des von unterschiedlichen XSLT-Prozessoren ausgelösten Exception-Objekts kapseln.

Danach werden die Kommandozeilenparameter in File-Objekte umgewandelt. In den SAXON- und Xalan-Beispielen haben wir eine System-ID für jede dieser Dateien erzeugt. Da JAXP direkt von einem File-Objekt lesen kann, ist die zusätzliche Umwandlung in einen URI nicht erforderlich:

File xmlDatei = new File(args[0]);
File xsltDatei = new File(args[1]);

javax.xml.transform.Source xmlSource =
        new javax.xml.transform.stream.StreamSource(xmlDatei);
javax.xml.transform.Source xsltSource =
        new javax.xml.transform.stream.StreamSource(xsltDatei);

Das Interface Source wird sowohl zum Lesen der XML-Datei als auch für die XSLT-Datei verwendet. Anders als die SAX-Klasse InputSource oder Xalans XSLTInputSource-Klasse ist Source ein Interface, das viele Implementierungen haben kann. In diesem einfachen Beispiel nutzen wir ein StreamSource-Objekt, mit dem aus einem File-Objekt, einem InputStream, einem Reader oder einer System-ID gelesen werden kann. Später betrachten wir zusätzliche Source-Implementierungen, die SAX und DOM als Eingabe verwenden. Genau wie Source ist auch Result ein Interface, das verschiedene Implementierungen haben kann. In diesem Beispiel sendet ein StreamResult-Objekt die Ausgabe der Transformationen an System.out:

javax.xml.transform.Result ergebnis =
     new javax.xml.transform.stream.StreamResult(System.out);

Als nächstes wird eine Instanz von TransformerFactory erzeugt:

javax.xml.transform.TransformerFactory transFact =
     javax.xml.transform.TransformerFactory.newInstance( );

Die Klasse TransformerFactory ist zuständig für die Erzeugung von Transformer- und Template-Objekten. In unserem einfachen Beispiel erzeugen wir ein Transformer-Objekt:

javax.xml.transform.Transformer trans =
     transFact.newTransformer(xsltSource); 

Transformer-Objekte sind nicht für die Verwendung mit Threads geeignet, obwohl sie mehrfach verwendet werden können. In einem simplen Beispiel wie dem vorliegenden werden wir auf keinerlei Probleme stoßen. In einer Servlet-Umgebung, in der Threads eingesetzt werden, können aber nicht mehrere Benutzer gleichzeitig auf dieselbe Instanz von Transformer zugreifen. JAXP bietet aber auch ein Templates-Interface zur Repräsentation eines Stylesheets, auf das von vielen gleichzeitigen Threads zugegriffen werden kann.

Die Transformer-Instanz wird dann eingesetzt, um die eigentliche Transformation durchzuführen:

trans.transform(xmlSource, ergebnis);

So wird das XSLT-Stylesheet auf die XML-Daten angewandt und das Ergebnis an System.out geschickt.

XSLT Plugability Layer

JAXP 1.1 definiert eine spezifische Lookup-Prozedur, um einen passenden XSLT-Prozessor zu finden. Da das geschehen muß, ohne anbieterspezifischen Code in die Anwendungen einzufügen, werden Java-Systemeigenschaften und JAR-Datei-Dienstanbieter verwendet. Innerhalb des Codes lokalisiert man zunächst wie folgt eine Instanz der TransformerFactory-Klasse:

javax.xml.transform.TransformerFactory transFact =
     javax.xml.transform.TransformerFactory.newInstance( );

Weil TransformerFactory abstrakt ist, wird die Methode newInstance( ) eingesetzt, um eine Instanz einer spezifischen Unterklasse zu erzeugen. Der Algorithmus zur Lokalisierung der Unterklasse beginnt mit einem Blick auf die Systemeigenschaft javax.xml.transform.TransformerFactory. Lassen Sie uns annehmen, daß com.irgendwas.DingsTransformer ein neuer zu JAXP 1.1 kompatibler XSLT-Prozessor ist. Um statt des JAXP-Standardprozessors nun diesen Prozessor zu nutzen, kann man auf der Kommandozeile (Systemeigenschaften können auch in Ant-Konstruktionsdateien angegeben werden) beim Start der Anwendung die Systemeigenschaft angeben:

java -Djavax.xml.transform.TransformerFactory=com.irgendwas.DingsTransformer MyAppv

Vorausgesetzt, daß JAXP eine Instanz von DingsTransformer erzeugen kann, wird dieser XSLT-Prozessor verwendet. Selbstverständlich muß dafür DingsTransformer eine Unterklasse von TransformerFactory sein, daher liegt es bei den Anbietern JAXP-Unterstützung anzubieten.

Wird die Systemeigenschaft nicht angegeben, schaut JAXP als nächstes nach einer Eigenschaftendatei namens lib/jaxp.properties im JRE-Verzeichnis. Eine Eigenschaftendatei besteht aus name=wert-Paaren, und JAXP sucht nach einer solchen Zeile:

javax.xml.transform.TransformerFactory=com.irgendwas.DingsTransformer

Sie können den Speicherort der JRE über den folgenden Code ermitteln:

String javaHomeVerzeichnis = System.getProperty("java.home");

Hinweis:
Einige verbreitete Entwicklungstools ändern den Wert von java.home bei ihrer Installation. Das kann verhindern, daß JAXP seine jaxp.properties-Datei findet. Borlands JBuilder installiert beispielsweise seine eigene Version von Java 2, die er auch standardmäßig verwendet.

Der Vorteil, jaxp.properties in diesem Verzeichnis anzulegen, liegt darin, daß Sie Ihren bevorzugten Prozessor in all Ihren Anwendungen nutzen können, die JAXP verwenden, ohne die Systemeigenschaft auf der Kommandozeile angeben zu müssen. Sie können den Inhalt der Datei dann immer noch mit der -D Kommandozeilen-Syntax übergehen.

Wird jaxp.properties nicht gefunden, verwendet JAXP den JAR-Datei-Dienstanbieter-Mechanismus, um die passende Unterklasse von TransformerFactory zu lokalisieren.

Der in der JAR-Datei-Spezifikation von Sun skizzierte Dienstanbieter-Mechanismus erfordert lediglich, daß Sie eine Datei im META-INF/services-Verzeichnis einer JAR-Datei anlegen müssen. Für JAXP heißt diese Datei javax.xml.transform.TransformerFactory. Sie enthält eine einzelne Zeile, die die Implementierung von TransformerFactory festlegt: com.irgendwas.DingsTransformer aus unserem fiktiven Beispiel. Wenn Sie in JAXP 1.1 in xalan.jar schauen, werden Sie diese Datei finden. Um einen anderen JAXP 1.1-kompatiblen Parser zu nutzen, stellen Sie einfach sicher, daß dessen JAR-Datei in Ihrem CLASSPATH als erstes aufgeführt ist.

Wenn JAXP schließlich gar keine implementierende Klasse an einem der drei Orte finden kann, verwendet es seine Standardimplementierung von TransformerFactory. Hier noch einmal zusammenfassend die Schritte, die JAXP durchgeht, um eine Factory-Klasse zu finden:

  1. Verwende den Wert der Systemeigenschaft javax.xml.transform.TransformerFactory, falls diese existiert.
  2. Wenn die Datei JRE/lib/jaxp.properties existiert, suche nach einem Eintrag der Form javax.xml.transform.TransformerFactory=ImplementationClass.
  3. Verwende einen JAR-Datei-Diensteanbieter, um in jeder JAR-Datei im CLASSPATH nach einer Datei namens META-INF/services/javax.xml.transform.TransformerFactory zu suchen.
  4. Verwende die Standardinstanz von TransformerFactory.

Die JAXP 1.1 Plugability-Layer für SAX und DOM folgen exakt demselben Prozeß wie der XSLT-Layer, Sie nutzen allerdings die Systemeigenschaften javax.xml.parsers.SAXParserFactory bzw. javax.xml.parsers.DocumentBuilderFactory. Es bleibt anzumerken, daß JAXP 1.0 einen wesentlich einfacheren Algorithmus nutzt, denn es schaut nur nach, ob die Systemeigenschaft existiert. Ist die Eigenschaft nicht gesetzt, wird die Standardimplementierung genutzt.

Die Transformer-Klasse

Wie im Beispiel BeispielJaxp.java gezeigt, kann man ein Transformer-Objekt wie folgt über TransformerFactory erhalten:

javax.xml.transform.TransformerFactory transFact =
         javax.xml.transform.TransformerFactory.newInstance( );
javax.xml.transform.Transformer trans =
         transFact.newTransformer(xsltSource);

Die Transformer-Instanz kapselt dabei ein XSLT-Stylesheet und gestattet Ihnen, beliebig viele Transformationen durchzuführen. Vorsicht ist hauptsächlich im Zusammenhang mit Threads geboten, weil mehrere Threads nicht gleichzeitig eine einzelne Instanz von Transformer nutzen können. Rufen Sie für jede Transformation die transform-Methode auf:

abstract void transform(Source xmlSource, Result outputTarget)
     throws TransformerException

Diese Methode ist abstrakt, weil TransformerFactory eine Unterklasse von Transformer zurückliefert, die die eigentliche Arbeit macht. Das Interface Source definiert, woher die XML-Daten kommen, und das Interface Result legt fest, wohin das Ergebnis der Transformation gesendet wird. Die TransformerException wird ausgelöst, wenn während des Transformationsprozesses etwas schiefläuft, sie kann den Ort des Fehlers und eine Referenz auf die ursprüngliche Exception enthalten. Die Fähigkeit, den Ort eines Fehlers korrekt anzugeben, hängt vollständig von der Qualität der Fehlerberichterstattung der zugrundeliegenden XSLT-Transformer-Implementierung ab. Wir werden später in diesem Kapitel über spezifische Klassen sprechen, die die Interfaces Source und Result implementieren.

Neben der eigentlichen Durchführung der Transformation erlaubt die Implementierung von Transformer Ihnen, die Ausgabe-Eigenschaften und Stylesheet-Parameter festzulegen. In XSLT wird ein Stylesheet-Parameter wie folgt deklariert und genutzt:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html"/>
    <xsl:param name="bilder_verzeichnis" select="'bilder'"/>
    <xsl:template match="/">
        <html>
            <body>
                <h1>Beispiel für Stylesheet-Parameter</h1>
                <img src="{$bilder_verzeichnis}/sample.gif"/>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

Das Element <xsl:param> deklariert den Namen des Parameters und ein optionales select-Attribut. Dieses Attribut legt den Standardwert fest, falls der Stylesheet-Parameter nicht übergeben wird. In diesem Fall ist der String 'bilder' der Standardwert. Die Zeichenfolge ist in Hochkommas eingeschlossen, damit sie als String betrachtet wird und nicht als XPath-Ausdruck. Später wird mit der Attribute Value Template-Syntax auf die Variable bilder_verzeichnis verwiesen: {$bilder_verzeichnis}.

Die Übergabe einer Variablen zur Angabe des Speicherorts Ihrer Bilder ist sehr gebräuchlich, weil die Entwicklungsumgebung unter Umständen andere Verzeichnisnamen verwendet als der Produktionsserver. Eine andere gebräuchliche Verwendung für einen Stylesheet-Parameter ist die direkte dynamische Übergabe von Daten, wie beispielsweise einer ID an ein Servlet zwecks Session-Tracking.

Von JAXP aus wird dieser Parameter über die Transformer-Instanz übergeben. Der Code ist ziemlich simpel:

javax.xml.transform.Transformer trans = transFact.newTransformer(xsltSource);
trans.setParameter("bilder_verzeichnis", "grafiken");

Sie können so viele Parameter setzen, wie Sie möchten. Die Parameter werden gespeichert und für jede Transformation mit dieser Transformer-Instanz wiederverwendet. Wenn Sie einen Parameter entfernen wollen, müssen Sie clearParameters( ) aufrufen, dann werden alle Parameter für diese Transformer-Instanz zurückgesetzt. Parameter funktionieren ähnlich einer java.util.Map; wenn Sie einen Parameter doppelt setzen, überschreibt der zweite Wert den ersten.

Ein weiteres Einsatzgebiet der Transformer-Klasse ist das Auslesen und Setzen von Ausgabe-Eigenschaften über eine der folgenden Methoden:

void setOutputProperties(java.util.Properties props)
void setOutputProperty(String name, String value)
java.util.Properties getOutputProperties( )
String getOutputProperty(String name)

Wie Sie sehen können, werden die Eigenschaften als Name-Wert-Paare von Strings angegeben und können individuell oder als Gruppe gesetzt und ausgelesen werden. Anders als Stylesheet-Parameter, können individuelle Eigenschaften hier zurückgesetzt werden, indem man als Wert null übergibt. Die erlaubten Namen für Eigenschaften sind in der Klasse javax.xml.transform.OutputKeys definiert und werden in der folgenden Tabelle erläutert.

Tabelle: Konstanten in javax.xml.transform.OutputKeys

Konstante Bedeutung
CDATA_SECTION_ELEMENTS Spezifiziert eine whitespace-separierte Liste von Elementen, deren Inhalte als CDATA-Abschnitte ausgegeben werden sollten. Für Beispiele wird auf die XSLT-Spezifikation des W3C verwiesen.
DOCTYPE_PUBLIC Wird nur verwendet, wenn DOCTYPE_SYSTEM ebenfalls verwendet wird. Instruiert den Prozessor, eine PUBLIC-Dokumententyp-Deklaration auszugeben.
Zum Beispiel: <!DOCTYPE wurzelElement PUBLIC "public id" "system id">.
DOCTYPE_SYSTEM Weist den Prozessor an, eine Dokumententyp-Deklaration auszugeben.
Zum Beispiel: <!DOCTYPE wurzelElement SYSTEM "system id">.
ENCODING Legt die Zeichenkodierung des Ergebnisbaums fest. Beispielsweise UTF-8 oder ISO-8859-1.
INDENT Gibt an, ob dem Ergebnisbaum Whitespace hinzugefügt werden soll, was die Ausgabe lesbarer macht. Gültige Werte sind yes und no. Obwohl Einrückung die Ausgabe lesbarer macht, wird dadurch auch die Datei größer und die Performance beeinträchtigt.
MEDIA_TYPE Der MIME-Typ des Ergebnisbaums.
METHOD Die Ausgabemethode, entweder xml, html oder text. Obwohl andere Werte, wie xhtml, möglich sind, sind diese implementierungsspezifisch und könnten von Ihrem Prozessor abgelehnt werden.
OMIT_XML_DECLARATION Gültige Werte sind yes und no, wobei festgelegt wird, ob eine XML-Deklaration in der ersten Zeile des Ergebnisbaums eingefügt werden soll.
STANDALONE Gültige Werte sind yes und no. Angegeben wird, ob die XML-Deklaration anzeigen soll, daß das Dokument eigenständig ist.
Zum Beispiel: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>.
VERSION Legt die Version der Ausgabemethode fest, standardmäßig 1.0 bei XML-Ausgabe. Taucht in der XML-Deklaration wie folgt auf: <?xml version="1.0" encoding="UTF-8"?>.

Es ist kein Zufall, daß diese Ausgabe-Eigenschaften dieselben sind, die Sie im <xsl:output>-Element in Ihren Stylesheets setzen können. Zum Beispiel:

<xsl:output method="xml" indent="yes" encoding="ISO-8859-1"/>

Mit JAXP können Sie entweder zusätzliche Ausgabe-Eigenschaften angeben oder die im Stylesheet gesetzten überschreiben. Um die Zeichenkodierung zu ändern, schreiben Sie diesen Code:

// hat Vorrang vor der im Stylesheet angegebenen Zeichenkodierung
trans.setOutputProperty(OutputKeys.ENCODING, "UTF-16");

Bedenken Sie, daß dies nicht nur encoding="UTF-16" in die XML-Deklaration schreibt, sondern natürlich auch den Prozessor anweist, diese Zeichenkodierung für den Ergebnisbaum zu verwenden. Wenn Sie also UTF-16 angeben, werden 16-Bit Unicode-Zeichen erzeugt, was in vielen ASCII-Texteditoren zu Anzeigeproblemen führt.

JAXP XSLT-Design

Nun, da wir einigen Beispielcode gesehen und unsere Erkundung der Transformer-Klasse begonnen haben, lassen Sie uns einen Schritt zurückmachen und das Gesamt-Design des XSLT-Plugability-Layers betrachten. Die JAXP-Unterstützung für XSLT ist heruntergebrochen in die in folgende Tabelle aufgelisteten Pakete.

Tabelle: JAXP-Transformationspakete

Paket Beschreibung
javax.xml.transform Definiert eine Allzweck-API für XML-Transformationen ohne Abhängigkeiten von SAX oder DOM. Die Transformer-Klasse wird von der TransformerFactory-Klasse geliefert. Der Transformer transformiert von einem Source-Objekt in ein Result-Objekt.
javax.xml.transform.dom Legt fest, wie Transformationen mit DOM ausgeführt werden können. Enthält Implementierungen von Source und Result: DOMSource und DOMResult.
javax.xml.transform.sax Unterstützt SAX2-Transformationen. Definiert SAX-Versionen von Source und Result: SAXSource und SAXResult. Definiert auch eine Unterklasse von TransformerFactory, um SAX2-Events an einen XSLT-Prozessor zu übergeben.
javax.xml.transform.stream Definiert I/O-Stream-Implementierungen von Source und Result: StreamSource und StreamResult.

Das Herz der XSLT-Unterstützung von JAXP liegt im Paket javax.xml.transform, das die Mechanismen und den Gesamtprozeß für jede ausgeführte Transformation zur Verfügung stellt. Dieses Paket besteht hauptsächlich aus Interfaces und abstrakten Klassen mit Ausnahme von OutputKeys und ein paar Exception- und Fehlerklassen. Die folgende Abbildung zeigt ein UML-Klassendiagramm, das alle Teile in diesem wichtigen Paket darstellt.

javax.xml.transform-Klassendiagramm

Abbildung: javax.xml.transform-Klassendiagramm

Wie Sie sehen können, ist dies ein kleines Paket, typisch für die Tatsache, daß JAXP lediglich ein Wrapper um die Tools ist, die die Transformationen eigentlich durchführen. Der Einstiegspunkt ist die Klasse TransformerFactory, die, wie bereits gesehen, Instanzen von Transformer und zusätzlich Instanzen der abstrakten Templates-Klasse erzeugt. Ein Templates-Objekt stellt ein kompiliertes Stylesheet dar und wird weiter unten in diesem Kapitel detailliert besprochen. (Die exakte Definition eines »kompilierten« Stylesheets ist vage. XSLT-Prozessoren sind nämlich frei in der Art, ein zwischengespeichertes Stylesheet zu optimieren.) Der Vorteil der Kompilierung liegt in der Performance: Dasselbe Templates-Objekt kann immer und immer wieder von vielen Threads verwendet werden, ohne die XSLT-Datei erneut parsen zu müssen.

Das Interface URIResolver ist zuständig für die Auflösung von innerhalb eines Stylesheets gefunden URIs, generell also etwas, womit Sie nicht direkt zu tun haben werden. Es wird genutzt, wenn ein Stylesheet ein anderes Dokument importiert oder einbindet und der Prozessor herausfinden muß, wo er das Dokument findet. Zum Beispiel:

<xsl:import href="allgemeineFusszeile.xslt"/>

ErrorListener ist, wie Sie sicher schon vermuten, ein Interface, das es Ihrem Code erlaubt, sich als Listener für Fehlerzustände zu registrieren. Dieses Interface definiert die folgenden drei Methoden:

void error(TransformerException ex)
void fatalError(TransformerException ex)
void warning(TransformerException ex)

Die TransformerException ist in der Lage, eine andere Exception oder ein Throwable-Objekt zu kapseln und kann eine Instanz der SourceLocator-Klasse zurückliefern. Wenn die zugrundeliegende XSLT-Implementierung keinen SourceLocator liefert, wird null zurückgegeben. Das Interface SourceLocator definiert Methoden, um herauszufinden, wo eine TransformerException ihren Ursprung hatte. Im Fall von error() und warning() muß der XSLT-Prozessor die Verarbeitung bis zum Ende des Dokuments fortführen. Im Fall von fatalError() muß der Prozessor aber nicht weitermachen. Wenn Sie kein ErrorListener-Objekt registrieren, dann werden alle Fehler, Warnungen und fatalen Fehler ganz normal auf System.err ausgegeben. TransformerFactoryConfigurationError und TransformerConfigurationException runden die Fehlerbehandlungs-APIs von JAXP ab und zeigen Probleme mit der Konfiguration der zugrundeliegenden XSLT-Prozessor-Implementierung an. Die Klasse TransformerFactoryConfigurationError wird generell dann verwendet, wenn die Implementierungsklasse nicht im CLASSPATH aufgeführt ist oder nicht instantiiert werden kann. TransformerConfigurationException zeigt gemäß seiner Dokumentation einen »schweren Konfigurationsfehler« an.

   

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema Java & XSLT bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © 2002 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 "Java und XSLT" 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