original in en Egon Willighagen
en to de Guido Socher
Egon ist aktives Mitglied des niederländischen _LF_ Teams seit 1999 und ist seit diesem Jahr Editor des niederländischen _LF_. Er studiert Chemie an der Universität in Nijmegen, spielt Basketball und wandert gerne.
XSL Transformations (XSLT) ist eine W3C Empfehlung und kann daher als Standard angesehen werden. XSLT ist Teil von XSL, der XML Stylesheet Sprache. Sein Zweck ist es, wie der Name Stylesheet schon sagt, das Layout eines XML Dokumentes zu definieren. Formatierungsobjekte spielen eine große Rolle in XSL, um das Layout zu erzeugen. Für diesen Layoutprozeß ist es jedoch oft erforderlich, Daten umzuwandeln (Transform) und das ist der Punkt wo XSLT ins Spiel kommt.
Im Gegensatz zu XSL selbst ist XSLT schon ein ausgereifter Standard. XSLT Formattierungsprogramme werden deshalb in verschiedenen Sprachen entwickelt. Die am weitesten ausgereiften Programme sind in C (XT, von James Clark) und in Java (Xalan, früher von Lotus Inc. und jetzt vom Apache Projekt entwickelt). In Perl gibt es auch zwei Projekte: XML::XSLT und XML::Sabotron. Das erste ist älter und komplett in Perl geschrieben, das letztere ist ein Interface zu dem C++ XSLT Prozessor.
Die augenblickliche Version ist 0.21 und kann von CPAN heruntergeladen werden. Seit kurzem ist das Projekt auch bei SourceForge, und ein CVS Baum ist dort verfügbar. Dieser Artikel basiert auf der Version 0.21. Das Perl Modul wird von Geert Josten, einem Chemiestudenten an der Uni Nijmegen entwickelt, aber inzwischen haben schon viele andere Leute zu diesem Projekt beigetragen. Es ist zu erwarten, daß mit der öffentlichen Verfügbarkeit des CVS Baums die Entwicklung von XML::XSLT beschleunigt wird. Das ist nötig, um den augenblicklichen W3C working draft für XSLT zu implementieren.
Der folgende Perl Code zeigt, wie das Modul benutzt wird:
#!/usr/bin/perl use XML::XSLT; my $xmlfile = "example.xml"; my $xslfile = "example.xsl"; my $parser = XML::XSLT->new ($xslfile, "FILE"); $parser->transform_document ($xmlfile, "FILE"); $parser->print_result();
Das Beispiel zeigt wie eine XML Datei (example.xml) mit der Hilfe einer XSLT Datei (example.xsl) formatiert wird. Es können jedoch auch Stylesheets basierend auf einem DOM-Baum benutzt werden:
#!/usr/bin/perl use XML::XSLT; use XML::DOM; my $domparser = new XML::DOM::Parser; my $doc = $domparser->parsefile ("file.xml"); my $parser = XML::XSLT->new ($doc, "DOM");
... oder als ein String:
#!/usr/bin/perl use XML::XSLT; my $xsl_string = qq{ <?xml version="1.0"?> <xsl:stylesheet> <xsl:template match="/"> <html> <xsl:apply-templates/> </body> </xsl:template> </xsl:stylesheet> }; my $parser = XML::XSLT->new ($xsl_string, "STRING");
Diese drei Datentypen sind auch für die transform_document() Funktion aus dem ersten Beispiel verfügbar.
Hier ist ein Script, das eine XML Datei basierend auf einem XSLT Stylesheet konvertiert. Das Script nimmt zwei Kommandozeilen-Argumente, die Datei des XSLT Stylesheets und die XML Datei. Dieses Script benutzt den Perl "FILE" Mechanismus.
Jetzt da wir wissen wie der XSLT Prozessor in Perl benutzt wird, können wir uns dem XSLT Standard widmen.
XSL Transformation wurde entwickelt, um das Formatieren von Daten, die in XML gespeichert sind, zu ermöglichen. XSLT erledigt das einfache Umwandeln von Daten wie Sortieren, Informationsauswahl und das Kombinieren von Informationen aus verschiedenen Quellen. Es hat sich jedoch in der Praxis herausgestellt, daß XSLT alleine auch schon für Layout und Design geeignet ist.
XML::XSLT unterstützt noch nicht alle XSLT Befehle, aber alle Befehle, die in diesem Artikel aufgeführt sind, werden unterstützt.
XSLT Dokumente definieren wie, ein XML Dokument transformiert werden soll. Das geschieht, indem ein Template (Formular oder Layoutmuster) für jedes Element definiert wird. Unten finden sich mehrere Beispiele eines XSLT Dokumentes, die alle für ein XML Dokument geschrieben sind, das ein Gnumeric worksheet (GNOME Tabellenkalkulation) enthält (Jetzt wissen wir, daß das File-Format von Gnumeric ein XML Dokument ist. Normalerweise sind *.gnumeric Dateien gzipped. Probier mal "gunzip IrdendEinGnumericWorksheet.gnumeric")
Wenn man ein solches Worksheet der Tabellenkalkulation Gnumeric untersucht, dann sieht man neben den eigentlichen Daten auch Layoutinformationen. Z.B das Seitenlayout und Breite/Höhe einzelner Zellen. Wir entwickeln einige XSLT Sheets für bestimmte Aufgaben wie:
Um die Grundlagen von XSLT kennenzulernen schreiben wir eine XSLT Seite die eine ganz einfach Zusammenfassung erzeugt (verysimple.xsl):
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="*"> <xsl:apply-templates/> </xsl:template> <xsl:template match="text()"/> <xsl:template match="Item"> <xsl:value-of select="./name"/> : <xsl:value-of select="./val-string"/> </xsl:template> </xsl:stylesheet>
Das erste Template (Formular) paßt auf alle Elemente des XML Dokumentes. Das zweite Template paßt nur auf alle CDATA Elemente in dem XML Dokument. Das letzte Template macht nun schließlich was wir wollen. Jedes Element in der Zusammenfassung in dem Gnumeric Dokument bekommt einen CDATA Wert von name und dem val-string Element. Probier es aus! Vergleiche einfach die Ausgabe mit dem, was du ausgehend von dem XML Dokument erwarten würdest.
Das erste Template paßt schon auf jedes Element. Warum wird dann das dritte angewandt und nicht das erste? Das kommt daher, das das letztere das erste überschreibt. Templates werden daher in der Reihenfolge allgemein zu spezifisch hin gespeichert.
Es ist zu beachten, daß XML::XSLT sehr viele Leerzeichen, die vom dem XSLT Sheet kommen, druckt. Ich glaube nicht, daß es in dieser Version von XML::XSLT einen Weg gibt, um das zu verhindern. Da die endgültige Ausgabe des Dokumentes in HTML sein wird, ist das im Moment egal. Das nächste Beispiel hat dieselbe Funktion, fügt jedoch XHTML spezifische Elemente hinzu, so daß man es mit einem Webbrowser betrachten kann (simple.xsl):
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="*"> <xsl:apply-templates/> </xsl:template> <xsl:template match="text()"/> <xsl:template match="Item"> <b><xsl:value-of select="./name"/></b>: <i><xsl:value-of select="./val-string"/></i><br /> </xsl:template> <xsl:template match="/"> <html> <head> <title>Summary Gnumeric File</title> </head> <body bgcolor="white"> <xsl:apply-templates/> </body> </html> </xsl:template> </xsl:stylesheet>
Hier findet sich nun ein zusätzliches Template für das root (/) Element. Das macht es möglich, XHTML Code um alle anderen Ausgaben zu wickeln. Die Ausgabe des ersten Beispiels ist nun im Hauptteil (Body) des Dokumentes. Warum? Wenn XML::XSLT die Datei bearbeitet, dann sucht es nach dem Template, das auf Root paßt. Danach druckt es den XHTML Code bis zum body Element. Danach werden weitere Templates auf alle Folgeelemente angewendet. Wenn das geschehen ist, wird mit dem root Template weiter gearbeitet und alle schließenden body und html Tags werden gedruckt.
Es gibt auch zusätzlichen Code in dem item Template. Beachte, daß man XSLT Befehle mit Ausgabedaten mischen kann. Ein XSLT Prozessor nimmt an, daß jedes Element, das nicht in den xsl Definitionsraum paßt, Ausgabe ist.
Bis jetzt waren die Beispiele nur neue oder veränderte Templates. Um unser Beispiel zu Ende zu bringen, fügen wir einen Kopfteil hinzu and betrachten den zweiten apply-templates Befehl (finalsimple.xsl):
<xsl:template match="Summary"> <h2>Summary</h2> <ul> <xsl:apply-templates/> </ul> </xsl:template>
Der xsl:for-each Befehl stellt zusätzliche Kontrollmöglichkeiten zum Verarbeiten eines XML Dokumentes zur Verfügung, speziell in Kombination mit xsl:sort, aber sort ist in XML::XSLT noch nicht implementiert.
Um Informationen über die Tabellenseiten in den Gnumeric Dateien hinzuzufügen, benutzen wir den xsl:for-each Befehl (foreach.xsl):
<xsl:template match="Sheets"> <xsl:for-each select="Sheet"> <h2><xsl:value-of select="Name"/></h2> <ul> Rows: <xsl:value-of select="MaxRow"/><br /> Cols: <xsl:value-of select="MaxCol"/><br /> </ul> </xsl:for-each> </xsl:template>
Leider hat das hier benutzte Gnumeric Worksheet nur eine Seite. Du solltest das obige Beispiel mit einem größeren Gnumeric Worksheet testen.
Wie schon erwähnt, kann man mit XML::XSLT im Moment nicht sortieren. Das ist schade, denn die XML Daten in den Gnumeric Dateien sind nicht sortiert. Wenn wir sortieren könnten, dann wäre es möglich, eine XHTML Tabelle anzulegen, die exakt den Inhalt einer Seite in der Gnumeric Tabellenkalkulation wiedergibt. Was man im Augenblick jedoch schon machen kann, ist die Daten einer bestimmten Reihe der Spalte ausgeben. Im nächsten Abschnitt wird das näher erläutert.
Um alle Daten in der dritten Spalte (in ihr steht das Gehalt eines reichen Studenten aus den Niederlanden) auszugeben, kann man den xsl:if Befehl benutzen (if.xsl):
<xsl:template match="Sheets"> <xsl:for-each select="Sheet"> <h2><xsl:value-of select="Name"/></h2> <ul> Rows: <xsl:value-of select="MaxRow"/><br /> Cols: <xsl:value-of select="MaxCol"/><br /> <xsl:apply-templates select="Cells"/><br /> </ul> </xsl:for-each> </xsl:template> <xsl:template match="Cells"> Content of Col 3: <xsl:for-each select="Cell"> <xsl:if test="@Col='3'"> <xsl:value-of select="Content"/><xsl:text>, </xsl:text> </xsl:if> </xsl:for-each> </xsl:template>
In dem wir das Select Attribute des xsl:apply-templates Befehls benutzen, erreichen wir, daß die Templates nur auf die Elemente einzelner Zellen angewendet werden.
Das Zell Template wird in einer Schleife auf alle Kinder-Zell-Elemente (siehe Quell-Code der XML Datei) angewendet, gibt aber nur einen Wert aus, wenn die Spalte den Wert "3" hat.
Jetzt wo die Templates komplexer werden, ist es whictig zu wissen was das augenblickliche Element ist. Das Zelltemplate wird z.B nur auf eine bestimmte Instanz eines Zellelementes angewandt. Sobald Information selektiert wird (select="." in einem Zelltemplate bezeichnet das Zellelement) fokussiert das Template auf diese Information. select="Cell" in dem xsl:for-each Befehl würde alle Zellelemente selektieren, aber innerhalb der Schleife ist der Fokus auf eine dieser Zellen gerichtet. Das test="@Col" bezieht sich daher auf eine Zelle. Innerhalb der Schleife kann man sich mit select="../@name" auf die Attribute von Zellen beziehen (mal abgesehen davon, daß Zellen keine Attribute haben).
Der xsl:text Befehl stellt sicher, daß aller Text ausgegeben wird. Normalerweise würden die Leerzeichen in ", " nicht ausgegeben, aber indem man xsl:text benutzt kann, man sicherstellen, daß alles ausgegeben wird.
Es gibt noch viele weitere Funktionen in dem XSLT und dem XML::XSLT Modul. Dieser Artikel ist nur eine Einführung. Vielleicht hast du jetzt mehr Fragen als Antworten, aber das ist gut. Schreib Deine Fragen in die talkback-Seite oder schreib sie in der XML::XSLT Mailingliste.
CDATA
CDATA sind Zeichendaten (Character Data) und kann jede
Zeichensequenz, die nicht "]]>", enthält sein.
Siehe
XML
Recommendation.
DOM
Dokument Objekt Modell. Ein Interface, das benutzt werden
kann, um auf Dokumente zuzugreifen. Zum Beispiel XML Dokumente.
Siehe
DOM Web-Seite.
Gnumeric
Eine Tabellenkalkulation für Gnome.