15.3 XSLT
Wenn Sie dem Kapitel bis hierhin gefolgt sind, wird Ihnen aufgefallen sein, dass Sie zwar eine Reihe verschiedener XML-Dokumente und XML-Fragmente gesehen haben, aber noch keinen Screenshot oder eine andere Darstellung eines fertig verarbeiteten Dokuments. Das liegt daran, dass XML einzig und allein die Struktur eines Dokuments beschreibt. Für das Layout sind separate Formatierungsangaben zuständig, die meist in der Extensible Stylesheet Language (XSL) verfasst werden.
XSL besteht aus zwei verschiedenen Komponenten: Die in diesem Abschnitt behandelten XSL-Transformations (XSLT) beschreiben die Umwandlung (Transformation) beliebiger XML-Dokumente in andere Formate wie HTML oder PDF, während XSL Formatting Objects (XSL-FO) eine eigene Sprache zur Definition von Formatierungen und Stilen bilden. Eine dritte Alternative für die Formatierung bieten die am häufigsten für HTML-Dokumente eingesetzten Cascading Style Sheets (CSS), die in Kapitel 17, »Webseitenerstellung mit (X)HTML und CSS«, erläutert werden.
Ein XSLT-Dokument beschreibt, welche Elemente und Attribute eines XML-Eingabedokuments in welche Bestandteile eines Ausgabedokuments umgesetzt werden. Um die einzelnen Komponenten des Eingabedokuments zu identifizieren, verwendet XSLT eine Sprache namens XPath, die den Zugriff auf die Baumstruktur jedes XML-Dokuments ermöglicht.
Um XSLT einsetzen zu können, benötigen Sie eine spezielle Anwendung namens XSLT-Prozessor. Dieses Programm nimmt ein XSLT-Stylesheet und ein XML-Dokument entgegen und erzeugt gemäß den Regeln des Stylesheets das gewünschte Ausgabedokument.
Einer der bekanntesten XSLT-Prozessoren ist Apache Xalan, den Sie unter xml.apache.org/xalan herunterladen können. Es handelt sich um eine Java-Anwendung, die Sie von der Kommandozeile aus folgendermaßen aufrufen:
$ java org.apache.xalan.xslt.Process -IN comics.xml -XSL comics2htm.xsl -OUT comics.html
Der Kommandozeilenparameter -IN gibt, wie Sie wahrscheinlich richtig vermutet haben, das Eingabedokument an, -XSL bezeichnet die XSLT-Stylesheet-Datei mit der Endung .xsl und -OUT die Ausgabedatei.
Die häufigste Umwandlung – und die einzige, die in diesem kurzen Abschnitt demonstriert wird – ist diejenige von allgemeinem XML nach HTML.
Hier ein kurzes XSLT-Stylesheet, das die zu Beginn dieses Kapitels vorgestellte Datei comics.xml in ein einfaches HTML-Dokument umwandelt:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="comics">
<html>
<head>
<title>Comics</title>
</head>
<body>
<h1>Comics</h1>
<xsl:for-each select="./comic">
<xsl:call-template name="output-comic">
<xsl:with-param name="content" select="." />
</xsl:call-template>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template name="output-comic">
<xsl:param name="content" />
<h2>
<xsl:value-of select="$content/series/text()" />
#<xsl:value-of select="$content/issue/text()" />
</h2>
<h3>
<xsl:value-of select="$content/title/text()" />
<xsl:if test="$content/subtitle">
<br />
<xsl:value-of select="$content/subtitle/text()" />
</xsl:if>
<xsl:if test="$content/issue/@original">
<br />
(sammelt Originalausgaben
<xsl:value-of select="$content/issue/@original" />
)
</xsl:if>
</h3>
<p>
<b>Verlag:</b>
<xsl:value-of select="$content/publisher/text()" />
<br />
<b>Format:</b>
<xsl:value-of select="$content/format/text()" />
<br />
<b>Autoren:</b>
<xsl:for-each select="$content/authors/author">
<xsl:if test="position() > 1">, </xsl:if>
<xsl:value-of select="./text()" />
(<xsl:value-of select="./@role" />)
</xsl:for-each>
<br />
<b>Preis:</b>
<xsl:choose>
<xsl:when test="$content/price/@currency = 'USD'">
<xsl:variable name="rawprice" select="$content/price/
text() div 1.4" />
<xsl:value-of select="round($rawprice * 100) div 100" /> EUR
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$content/price/text()" />
<xsl:value-of select="$content/price/@currency" />
</xsl:otherwise>
</xsl:choose>
</p>
</xsl:template>
</xsl:stylesheet>
Wenn Sie das Stylesheet über den zuvor gezeigten Xalan-Aufruf oder mithilfe eines anderen XSLT-Prozessors verwenden und die entstandene HTML-Datei im Browser öffnen, erhalten Sie ein Ergebnis wie in Abbildung 15.2.
Abbildung 15.2 Das mithilfe von XSLT erzeugte HTML-Dokument im Browser
Falls Sie mit HTML-Code noch nichts anfangen können, lesen Sie zunächst Kapitel 17, »Webseitenerstellung mit (X)HTML und CSS«. Ansonsten sollten Sie sich den Quellcode des XSLT-Beispiels genauer anschauen. Wie Sie sehen, wird die gesamte Struktur des HTML-Dokuments einfach aufgeschrieben, umschlossen und unterbrochen von XSLT-Angaben, die die Inhalte bestimmter Elemente aus comics.xml an den passenden Stellen einfügen.
Hier eine Aufzählung besonders wichtiger XSLT-Elemente; einige von ihnen werden im vorigen Beispiel verwendet:
- xsl:stylesheet ist das Wurzelelement des gesamten XSLT-Stylesheets.
- xsl:template erwartet als Inhalt des Attributs match den Namen eines XML-Elements aus dem Dokument, dessen Inhalte verarbeitet werden
sollen. Bevor Sie die erste Zeile des Ausgabedokuments schreiben, müssen Sie mithilfe
von xsl:template das Wurzelelement des Eingabedokuments auswählen. Zu diesem Zweck bietet XSLT die
Kurzfassung match="/" an.
Daneben existiert auch die Schreibweise <xsl:template name="Name"> ... </template>. So benannte Templates werden mithilfe der Anweisung <xsl:call-template name="Name" /> aufgerufen. Dabei lassen sich sogar Parameter übergeben, beispielsweise XPath-Ausdrücke, um ein benanntes Template auf verschiedene Teile des XML-Baums anzuwenden. Dazu muss die Template-Definition gleich am Anfang ein oder mehrere Elemente in der Form <xsl:param name="Parmetername" /> enthalten. In den xsl:call-template-Aufruf werden dann die zugehörigen Wertzuweisungen verschachtelt; sie besitzen folgende Schreibweise: <xsl:with-param name="Parametername" select="X-Path-Ausdruck" />. In XPath-Ausdrücken werden Parameter als $Parametername referenziert.
- xsl:for-each funktioniert ähnlich wie xsl:template match="...". Allerdings durchläuft es sämtliche Elemente des unter select angegebenen Typs in einer Schleife.
- xsl:value-of liest den Textinhalt eines Elements, das PCDATA oder CDATA enthält; um ganz sicherzugehen,
sollten Sie wie im Beispiel die Funktion text() verwenden, um den Inhalt der enthaltenen Textknoten auszuwählen. Um ein Attribut
statt eines Elements auszuwählen, müssen Sie diesem innerhalb des XPath-Ausdrucks
ein @ voranstellen.
Falls ein Textinhalt als Wert eines Attributs übernommen werden soll, kann der betreffende XPath-Ausdruck auch in geschweiften Klammern in die Anführungszeichen dieses Attributwertes geschrieben werden. Angenommen, Sie möchten den Wert eines Attributs namens link in einen HTML-Hyperlink übernehmen, während das Attribut caption die Link-Beschriftung bilden soll. Dies funktioniert wie folgt:
<a href="{@link}"><xsl:value-of select="@caption"/></a>
Alternativ lassen sich auch <xsl:attribute>-Knoten zur Konstruktion von Attributen verwenden; der folgende Code ist daher äquivalent:
<a>
<xsl:attribute name="href">
<xsl:value-of select="@link"/>
</xsl:attribute>
<xsl:value-of select="@caption"/>
</a> - xsl:copy-of kopiert dagegen nicht nur reinen Text, sondern auch den XML-Teilbaum des Elements, das mithilfe von select ausgewählt wurde.
- xsl:if ermöglicht es, Teile Ihres XSLT-Codes von Bedingungen abhängig zu machen. Das Attribut
test="..." prüft dabei einen beliebigen Ausdruck. Falls Sie lediglich einen XPath-Ausdruck ohne
Vergleichsoperation angeben, wird dessen Existenz überprüft. Ansonsten können Sie
auch mithilfe verschiedener Operatoren und Funktionen Werte vergleichen.
Der gängigste Vergleichsoperator ist =, der Gleichheit überprüft; ansonsten stehen!= (ungleich), < (kleiner als), > (größer als), <= (kleiner oder gleich) und >= (größer oder gleich) zur Verfügung – da < und > besondere Bedeutungen haben, müssen für die entsprechenden Operatoren die zugehörigen Entity-Referenzen verwendet werden. Das folgende Beispiel wählt den Textinhalt eines Elements namens artikel nur dann aus, wenn sein Attribut preis einen niedrigeren Wert als 100 hat:
<xsl:if test="artikel/@preis < 100">
<xsl:value-of select="artikel"/>
</xsl:if>Beachten Sie, dass der Inhalt von test im xsl:if-Element die aktuelle XPath-Position nicht ändert; dies ist bei match in xsl:template und select in xsl:for-each anders. Deshalb muss innerhalb des if-Tags auch artikel und nicht etwa das aktuelle Element (abgekürzt .) ausgewählt werden.
- xsl:choose funktioniert ähnlich wie xsl:if. Es stellt jedoch eine Art if/else-Funktionalität zur Verfügung: Sie können mehrere aufeinanderfolgende xsl:when-Blöcke verwenden, die geprüft werden, bis einer der test-Ausdrücke zutrifft. Wenn keiner zutrifft, wird der Inhalt des optionalen xsl:otherwise-Blocks beachtet.
- xsl:variable speichert den Wert eines XPath-Ausdrucks zwischen. Trotz des Namens Variable kann ein einmal abgelegter Wert nachträglich nicht mehr geändert werden.
Einige XPath-Ausdrücke sollten Sie für das erfolgreiche Arbeiten mit XSLT übrigens auch noch kennen. Hier die wichtigsten im Überblick:
- Das jeweils aktive Element (Kontextelement), das beispielsweise mithilfe von xsl:template oder xsl:for-each ausgewählt wurde, hat einen einfachen Punkt (.) als Namen.
- Direkte Kindelemente des Kontextelements können einfach mit ihrem Namen angesprochen werden. Angenommen, Sie haben die Struktur <autor><name/> </autor> und das Kontextelement ist <autor>, dann genügt name für den Zugriff auf den Kindknoten name. ./name ist allerdings auch zulässig.
- In verschachtelten Strukturen werden die Elemente durch / voneinander getrennt. Wird beispielsweise die Struktur <buch><autor><name/></autor></buch> verarbeitet, und das Kontextelement ist <buch>, dann können Sie mit autor/name auf den Knoten <name> zugreifen.
- Ein * greift auf alle direkten Kinder des gewählten Knotens zu. Nützlich ist dies vor allem für xsl:for-each-Konstrukte. Mithilfe der XPath-Funktion local-name(.) können Sie dann innerhalb der Schleife herausfinden, um welche Art von Element es sich jeweils handelt. Auf diese Weise können Sie etwa mit xsl:if überprüfen, welches Element gerade verarbeitet wird.
- Attribute werden, wie bereits erwähnt, durch ein vorangestelltes @ von Elementen unterschieden. In der Struktur <buch isbn="..."/> greift @isbn (oder buch/@isbn, falls <buch> nicht das Kontextelement ist) beispielsweise auf den Wert des Attributs isbn zu.
Neben den eigentlichen XPath-Ausdrücken kommen in dem Beispiel noch einige XSLT-Funktionen und -Operationen zum Einsatz:
- text() wurde bereits angesprochen – es handelt sich um den PCDATA- oder CDATA-Textinhalt des angesprochenen Knotens und seiner Unterknoten.
- position() liefert die aktuelle Position in einer xsl:for-each-Schleife. Beachten Sie, dass die Zählung bei 1 beginnt, nicht bei 0 wie in den meisten Programmiersprachen. Hier wird die Funktion verwendet, um vor jedem Autorennamen außer dem ersten ein Komma einzufügen.
- round() rundet einen numerischen Wert auf eine Ganzzahl. Um zwei Nachkommastellen zu erhalten, wird der Betrag im vorliegenden Beispiel zunächst mit 100 multipliziert, dann gerundet und anschließend wieder durch 100 dividiert.
- div ist keine Funktion, sondern ein Operator – er wird für die Division verwendet, weil / bereits als XPath-Pfadtrennzeichen zum Einsatz kommt.
Ihr Kommentar
Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.