XSL, XSLT, XSL-FO, FOP

+ andere TechDocs
+ XML
+ XSD (Schema)
+ JAXB (Binding)
+




Inhalt

  1. Begriffe und Übersicht
  2. Vorwort zu den folgenden Beispielen
  3. Formatierung mit CSS (Cascading Style Sheets) (ohne XSL-Stylesheet)
  4. Transformation mit XSL nach HTML
  5. Transformation mit XSL nach XHTML
  6. Transformation mit XSL nach CSV (z.B. für Excel)
  7. Transformation mit XSL nach XML mit Sortierung, XSLT-Bedingungen und XPath-Ausdrücken
  8. Transformation zu PDF mit XSL-FO und Apache FOP per Kommandozeile
  9. Transformation zu PDF mit XSL-FO und Apache FOP per Java
  10. XSL-Transformation per Java
  11. XSL-Transformation per Java mit Multithreading über threadsichere Templates
  12. Transformation von TXT zu XML


Begriffe und Übersicht

XPath (XML Path Language),
XSL (Extensible Stylesheet Language),
XSLT (XSL Transformations),
XSL-FO (XSL Formatting Objects),
FOP (Formatting Objects Processor),
TrAX (Transformation API for XML)

Die XSL-Spezifikation des W3C enthält die drei Unterspezifikationen XPath, XSLT und XSL-FO.

XPath bietet eine Syntax für Lokalisierungspfade zur Identifikation von Elementen und Attributen in XML-Dokumenten. XPath wird zum Beispiel bei XML Schema, XSLT, XPointer und XForms verwendet.

XSL definiert eine Sprache für Umwandlungsregeln.

XSLT beschreibt, wie XML-Dokumente in andere Formate transformiert werden können.

XSL-FO spezifiziert, wie die grafische Aufbereitung von XML-Dokumenten beschrieben wird und enthält Anweisungen zur Formatierung und Präsentation der Daten.

Apache FOP ist eine Implementierung von XSL-FO und erstellt aus XSL-FO-Layout-Beschreibungen verschiedene Ausgabeformate, zum Beispiel PDF, Java2D/AWT, AFP, PCL, MIF, PS, RTF, TIFF, PNG, SVG und TXT.

TrAX wird manchmal als Oberbegriff für die Transformations-APIs verwendet.

Ein einfaches XSL-Stylesheet kann zum Beispiel so aussehen:

<?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="xml" version="1.0" indent="yes" encoding="ISO-8859-1" />
  <xsl:template match="MeinRootElement">
    <MeinNeuesRootElement>
      <MeinNeuesUnterElement><xsl:value-of select="MeinUnterElement"/></MeinNeuesUnterElement>
    </MeinNeuesRootElement>
  </xsl:template>
</xsl:stylesheet>

Auch wenn man es in diesem einfachen Beispiel nicht erkennen kann: Bei "<xsl:value-of select="..."/>" ist ein XPath-Ausdruck eingesetzt.

Für einen einfachen Test speichern Sie das XSL-Stylesheet in MeinStylesheet.xsl und erzeugen folgende Input.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<MeinRootElement>
  <MeinUnterElement>Elementinhalt</MeinUnterElement>
</MeinRootElement>

Die XSL-Transformation kann mit beliebigen XSLT-Transformationstools erfolgen, beispielsweise:

Transformation mit Eclipse: Klicken Sie in Eclipse mit der rechten Maustaste auf MeinStylesheet.xsl, wählen Sie 'Run As' | 'XSL Transformation' und wählen Sie als 'XML Input File' über die Schaltflächen die XML-Datei Input.xml.

Transformation mit Xalan: Downloaden Sie Xalan, kopieren Sie xalan.jar und serializer.jar zu den beiden XML-Dateien und rufen Sie auf:

java -cp xalan.jar;serializer.jar org.apache.xalan.xslt.Process -XSL MeinStylesheet.xsl -IN Input.xml -OUT Result.xml

Transformation unter Windows mit MSXML: Downloaden Sie den Microsoft-MSXML-Wrapper msxsl.exe und rufen Sie auf:

msxsl Input.xml MeinStylesheet.xsl -o Result.xml

Siehe auch:
http://www.w3schools.com, http://xml.klute-thiemann.de, http://www.w3.org/Style/XSL, http://www.w3.org/TR/xsl, http://www.w3.org/TR/xslt, http://docs.oracle.com/javase/7/docs/api/javax/xml/transform/package-summary.html und http://docs.oracle.com/javase/7/docs/api/javax/xml/xpath/package-summary.html



Vorwort zu den folgenden Beispielen

Bitte beachten Sie die Encoding-Angaben. Wenn Ihr Editor nicht mit dem in den Beispielen meistens angegebenen "ISO-8859-1"-Encoding speichert, müssen Sie die Encoding-Angaben entsprechend ändern.



Formatierung mit CSS (Cascading Style Sheets) (ohne XSL-Stylesheet)

Bevor auf Transformationen per XSL-Stylesheets eingegangen wird, soll eine Umwandlung per CSS gezeigt werden. Cascading Style Sheets stellen eine Beschreibungssprache für Formatierungen für HTML-Webseiten dar. Aber nicht nur HTML-Seiten können mit CSS formatiert werden, sondern auch XML-Dokumente, wie das folgende Beispiel zeigt.

Genaueres zu CSS erfahren Sie unter: Einführung bei Wikipedia, W3C Specification (engl.), deutsche Übersetzung, CSS bei SELFHTML und CSS bei Wikibooks.

Speichern Sie folgendes XML-Dokument: Adressen1.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/css" href="Adressen1.css" ?>
<adressen>
   <adresse>
      <name>Torsten Horn</name>
      <strasse>Meinestr. 26</strasse>
      <plz>52072</plz>
      <ort>Aachen</ort>
   </adresse>
   <adresse>
      <name>Heinz Hinz</name>
      <strasse>Hafenstr. 42</strasse>
      <plz>21079</plz>
      <ort>Hamburg</ort>
   </adresse>
   <adresse>
      <name>Karl Kunz</name>
      <strasse>Königstr. 1</strasse>
      <plz>50676</plz>
      <ort>Köln</ort>
   </adresse>
</adressen>

Diese XML-Datei enthält mehrere Adressdatensätze. Bitte beachten Sie die <?xml-stylesheet ...?>-PI (Processing Instruction), in der als Stylesheet-Type text/css und als Stylesheet-Datei Adressen1.css angegeben ist.

Speichern Sie folgende Cascading-Stylesheet-Datei:
Adressen1.css

* {
   font: 11pt Arial,sans-serif;
}
adressen {
   border: 1px solid #A0B8F0;
}
adresse {
   display:       block;
   margin-top:    12pt;
   margin-bottom: 12pt;
}
name {
   display:       block;
   margin-left:   12pt;
   font-size:     15pt;
}
strasse {
   display:       block;
}
strasse, plz {
   margin-left:   30pt;
}
  

Öffnen Sie das XML-Dokument Adressen1.xml in Ihrem Webbrowser, zum Beispiel, indem Sie unter Windows im Windows-Explorer mit der rechten Maustaste auf den Dateinamen und dann auf 'Öffnen mit' | 'Firefox' bzw. 'Internet Explorer' klicken. Übliche moderne Webbrowser stellen Adressen1.xml nicht als XML-Datei dar, sondern werten die PI aus und zeigen den Inhalt als schön formatierte HTML-Datei (wirklich schön allerdings nur im Firefox 3.5; der Internet Explorer 8 interpretiert die border-Anweisung seltsam).

Torsten Horn
Meinestr. 26
52072 Aachen
Heinz Hinz
Hafenstr. 42
21079 Hamburg     
Karl Kunz
Königstr. 1
50676 Köln


Transformation mit XSL nach HTML

Speichern Sie folgendes XML-Dokument: Adressen2.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="Adressen2.xsl" ?>
<adressen>
   <adresse>
      <name>Torsten Horn</name>
      <strasse>Meinestr. 26</strasse>
      <plz>52072</plz>
      <ort>Aachen</ort>
   </adresse>
   <adresse>
      <name>Heinz Hinz</name>
      <strasse>Hafenstr. 42</strasse>
      <plz>21079</plz>
      <ort>Hamburg</ort>
   </adresse>
   <adresse>
      <name>Karl Kunz</name>
      <strasse>Königstr. 1</strasse>
      <plz>50676</plz>
      <ort>Köln</ort>
   </adresse>
</adressen>

Die XML-Datei ist fast identisch zur obigen Adressen1.xml, lediglich die PI (Processing Instruction) ist anders: Als Stylesheet-Type ist text/xsl und als Stylesheet-Datei Adressen2.xsl angegeben.
Bitte beachten Sie, dass text/xsl eigentlich nicht korrekt ist, weil es nicht der W3C/IANA-Spezifikation für Media-Typen entspricht. Aber es ist bislang der einzige von einigen Webbrowsern für HTML unterstützte Typ. text/xml, application/xml oder application/xslt+xml würde im Webbrowser für HTML nicht funktionieren (anders als bei XHTML, siehe unten).

Speichern Sie folgendes XSL-Stylesheet: Adressen2.xsl

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns="http://www.w3.org/TR/REC-html40">
   <xsl:output method="html" version="4.0" indent="yes" encoding="ISO-8859-1"/>
   <xsl:template match="adressen">
      <html>
         <head>
            <title>Adressen</title>
            <meta http-equiv="content-type" content="text/html;charset=iso-8859-1"/>
         </head>
         <body>
            <h2> Meine Adressen </h2>
            <table border="1" cellspacing="0" cellpadding="5">
               <tr><th>Name</th><th>Straße</th><th>PLZ und Ort</th></tr>
               <xsl:for-each select="adresse">
                  <tr>
                     <td><xsl:value-of select="name"/></td>
                     <td><xsl:value-of select="strasse"/></td>
                     <td><xsl:value-of select="plz"/>
                         <xsl:text> </xsl:text>
                         <xsl:value-of select="ort"/></td>
                  </tr>
               </xsl:for-each>
            </table>
         </body>
      </html>
   </xsl:template>
</xsl:stylesheet>

Als xmlns-Default-Namespace ist der HTML-4.0-Namespace und als Output ist html 4.0 definiert.
Sehen Sie sich die Erläuterungen zu den XSL-Tags an: xsl:stylesheet, output, method, version, indent, Template-Einführung, Template-Regeln, match, for-each, select, value-of und xsl:text.

Öffnen Sie auch das XML-Dokument Adressen2.xml wieder in Ihrem Webbrowser, zum Beispiel, indem Sie unter Windows im Windows-Explorer mit der rechten Maustaste auf den Dateinamen und dann auf 'Öffnen mit' | 'Internet Explorer' klicken. Einige Webbrowser (z.B. der Internet Explorer 8) werten die PI aus und zeigen den Inhalt als schön formatierte HTML-Datei. Andere Webbrowser (z.B. der Firefox 3.5) machen dies nicht, sondern präsentieren den gesamten Inhalt in einer unformatierten Zeile (beim W3C finden Sie übrigens die Empfehlung, "<?xml-stylesheet type="text/xsl" ...?>"-PIs nicht so zu verwenden).

Aber diesmal sind wir nicht auf die Eigenschaften des Webbrowsers angewiesen, da die XSL-Transformation vor der Übergabe an den Webbrowser mit einem beliebigen XSL-Transformationstool ("XSLT-Prozessor") erfolgen kann (dabei können Sie die fragliche PI auch komplett weglassen oder alternativ text/xsl durch text/xml ersetzen).

Transformieren Sie beispielsweise mit Xalan: Downloaden Sie Xalan, kopieren Sie xalan.jar und serializer.jar zu den beiden XML-Dateien und rufen Sie auf:

java -cp xalan.jar;serializer.jar org.apache.xalan.xslt.Process -XSL Adressen2.xsl -IN Adressen2.xml -OUT Result.html

Wenn das XML-Dokument wie im Beispiel eine PI enthält, würde alternativ für dieses Beispiel auch folgendes etwas kürzeres Kommando genügen, da Xalan auch die PI auswerten kann (sowohl mit text/xsl als auch mit text/xml):

java -cp xalan.jar;serializer.jar org.apache.xalan.xslt.Process -IN Adressen2.xml -OUT Result.html

Die resultierende Result.html können Sie jetzt mit jedem beliebigen Webbrowser öffnen und erhalten die korrekt formatierte Darstellung:

start Result.html

Alternativ zu Xalan können Sie unter Windows auch den Microsoft-MSXML-Wrapper msxsl.exe verwenden:

msxsl Adressen2.xml Adressen2.xsl -o Result.html

    
NameStraßePLZ und Ort
Torsten HornMeinestr. 2652072 Aachen
Heinz HinzHafenstr. 4221079 Hamburg
Karl KunzKönigstr. 150676 Köln

Oder Sie verwenden alternativ das weiter unten gezeigte Java-Transformationsprogramm:

java XslTransformation Adressen2.xsl Adressen2.xml Result.html

Beachten Sie, dass die Ausdrücke bei select="..." XPath-Ausdrücke sind und Sie zum Beispiel in eckigen Klammern "Prädikate" hinzufügen können, um Teilmengen zu selektieren: Ersetzen Sie testweise select="adresse" durch: select="adresse[1]", select="adresse[last()]", select="adresse[position() &lt;= 2]", select="adresse[position() &gt;= 2]", select="adresse[ort='Aachen']" oder select="adresse[plz &gt; 40000]". Genaueres zu XPath finden Sie unter: XPath 2.0, XPath 1.0 und Deutsche Übersetzung.



Transformation mit XSL nach XHTML

Speichern Sie folgendes XML-Dokument: Adressen3.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xml" href="Adressen3.xsl" ?>
<adressen>
   <adresse>
      <name>Torsten Horn</name>
      <strasse>Meinestr. 26</strasse>
      <plz>52072</plz>
      <ort>Aachen</ort>
   </adresse>
   <adresse>
      <name>Heinz Hinz</name>
      <strasse>Hafenstr. 42</strasse>
      <plz>21079</plz>
      <ort>Hamburg</ort>
   </adresse>
   <adresse>
      <name>Karl Kunz</name>
      <strasse>Königstr. 1</strasse>
      <plz>50676</plz>
      <ort>Köln</ort>
   </adresse>
</adressen>

Die XML-Datei ist fast identisch zur obigen Adressen2.xml, lediglich die PI (Processing Instruction) ist anders: Als Stylesheet-Type ist nicht der eigentlich inkorrekte text/xsl angegeben, sondern für XHTML kann der erlaubte text/xml verwendet werden (und außerdem lautet die Stylesheet-Datei Adressen3.xsl).

Speichern Sie folgendes XSL-Stylesheet: Adressen3.xsl

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns="http://www.w3.org/1999/xhtml">
   <xsl:output method="xml" indent="yes" encoding="ISO-8859-1"/>
   <xsl:template match="adressen">
      <html>
         <head>
            <title>Adressen</title>
            <meta http-equiv="content-type" content="text/html;charset=iso-8859-1"/>
         </head>
         <body>
            <h2> Meine Adressen </h2>
            <table border="1" cellspacing="0" cellpadding="5">
               <tr><th>Name</th><th>Straße</th><th>PLZ und Ort</th></tr>
               <xsl:for-each select="adresse">
                  <tr>
                     <td><xsl:value-of select="name"/></td>
                     <td><xsl:value-of select="strasse"/></td>
                     <td><xsl:value-of select="plz"/>
                         <xsl:text> </xsl:text>
                         <xsl:value-of select="ort"/></td>
                  </tr>
               </xsl:for-each>
            </table>
         </body>
      </html>
   </xsl:template>
</xsl:stylesheet>

Das XSL-Stylesheet ist nahezu identisch zur obigen Adressen2.xsl: Lediglich zu Beginn der Datei ist <xsl:stylesheet xmlns="..."> und <xsl:output .../> etwas anders definiert, damit XHTML statt HTML generiert wird. Denken Sie daran, das gewünschte Encoding korrekt anzugeben.

Wenn Sie diesmal das XML-Dokument Adressen3.xml wieder in Ihren Webbrowser laden, zum Beispiel, indem Sie unter Windows im Windows-Explorer mit der rechten Maustaste auf den Dateinamen und dann auf 'Öffnen mit' | 'Firefox' bzw. 'Internet Explorer' klicken, ist es umgekehrt: Diesmal wertet der Firefox 3.5 die PI aus und präsentiert die korrekt formatierte XHTML-Datei, während der Internet Explorer 8 die PI nicht auswertet und lediglich die XML-Datei zeigt.

Um eine mit allen modernen Webbrowsern darstellbare XHTML-Datei zu erzeugen, verfahren Sie analog wie beim letzten Beispiel (wenn Sie wollen, können Sie vorher die PI entfernen, da sie hierfür nicht benötigt wird):

java -cp xalan.jar;serializer.jar org.apache.xalan.xslt.Process -XSL Adressen3.xsl -IN Adressen3.xml -OUT Result.html

Oder alternativ:

msxsl Adressen3.xml Adressen3.xsl -o Result.html

Oder alternativ:

java XslTransformation Adressen3.xsl Adressen3.xml Result.html

Die resultierende Result.html können Sie jetzt mit beliebigen Webbrowsern öffnen und erhalten die korrekt formatierte Darstellung:

start Result.html



Transformation mit XSL nach CSV (z.B. für Excel)

Speichern Sie folgendes XML-Dokument: Adressen4.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<adressen>
   <adresse>
      <name>Torsten Horn</name>
      <strasse>Meinestr. 26</strasse>
      <plz>52072</plz>
      <ort>Aachen</ort>
   </adresse>
   <adresse>
      <name>Heinz Hinz</name>
      <strasse>Hafenstr. 42</strasse>
      <plz>21079</plz>
      <ort>Hamburg</ort>
   </adresse>
   <adresse>
      <name>Karl Kunz</name>
      <strasse>Königstr. 1</strasse>
      <plz>50676</plz>
      <ort>Köln</ort>
   </adresse>
</adressen>

Die XML-Datei ist wieder fast identisch zu den obigen, allerdings ist die PI diesmal weggelassen (falls Sie eine einfügen wollen: sie könnte so lauten: <?xml-stylesheet type="text/xml" href="Adressen4.xsl" ?>).

Speichern Sie folgendes XSL-Stylesheet: Adressen4.xsl

<?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="text" encoding="ISO-8859-1"/>
<xsl:template match="adressen">Name;Straße;Plz;Ort
<xsl:for-each select="adresse">
<xsl:value-of select="name"/>
<xsl:text>;</xsl:text>
<xsl:value-of select="strasse"/>
<xsl:text>;</xsl:text>
<xsl:value-of select="plz"/>
<xsl:text>;</xsl:text>
<xsl:value-of select="ort"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

In diesem XSL-Stylesheet können leider nicht die üblichen Einrückungen verwendet werden, weil sonst einige der Leerzeichen auch in der Ausgabedatei erscheinen würden. Bitte beachten Sie am Ende des XSL-Stylesheets, wie das Zeilenende definiert wird:

<xsl:text>
</xsl:text>

Die Transformation kann wieder mit einem beliebigen XSL-Transformationstool erfolgen, zum Beispiel mit Xalan (falls Sie eine PI eingefügt haben, könnten Sie den "-XSL Adressen4.xsl"-Teil weglassen):

java -cp xalan.jar;serializer.jar org.apache.xalan.xslt.Process -XSL Adressen4.xsl -IN Adressen4.xml -OUT Result.csv

Oder alternativ mit msxsl:

msxsl Adressen4.xml Adressen4.xsl -o Result.csv

Oder alternativ mit XslTransformation:

java XslTransformation Adressen4.xsl Adressen4.xml Result.csv

Das CSV-Ergebnis können Sie sich wahlweise in einem Texteditor oder in Excel ansehen (CSV = Comma Separated Values; als Trennzeichen wird meistens das Semikolon bevorzugt, damit die Datei direkt in Excel geöffnet werden kann):

type Result.csv

start Result.csv

    
 ABCD
1NameStraßePlzOrt
2Torsten HornMeinestr. 2652072Aachen
3Heinz HinzHafenstr. 4221079Hamburg
4Karl KunzKönigstr. 150676Köln


Transformation mit XSL nach XML mit Sortierung, XSLT-Bedingungen und XPath-Ausdrücken

Ein sehr einfaches, aber korrektes Prinzip-Beispiel für die Transformation eines XML-Dokuments in ein anderes XML-Format mit XSL haben Sie bereits oben gesehen. Jetzt folgt ein etwas umfangreicheres Beispiel

Speichern Sie folgendes XML-Dokument: Adressen5.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<adressen>
   <adresse id="42">
      <name>Torsten Horn</name>
      <strasse>Meinestr. 26</strasse>
      <plz>52072</plz>
      <ort>Aachen</ort>
   </adresse>
   <adresse id="43">
      <name>Heinz Hinz</name>
      <strasse>Hafenstr. 42</strasse>
      <plz>21079</plz>
      <ort>Hamburg</ort>
   </adresse>
   <adresse id="44">
      <name>Karl Kunz</name>
      <strasse>Königstr. 1</strasse>
      <plz>50676</plz>
      <ort>Köln</ort>
   </adresse>
</adressen>

Die XML-Datei ist wieder sehr ähnlich zu den obigen, allerdings sind diesmal id-Attribute hinzugefügt.

Speichern Sie folgendes XSL-Stylesheet: Adressen5.xsl

<?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="xml" version="1.0" indent="yes" encoding="ISO-8859-1"/>
<xsl:template match="adressen">
<xsl:text>
</xsl:text>
   <personen>
      <anzahlPersonen> <xsl:value-of select="count(adresse)"/>   </anzahlPersonen>
      <summePlz>       <xsl:value-of select="sum(adresse/plz)"/> </summePlz>
      <xsl:for-each select="adresse[@id &gt;= 42 and plz &lt; 60000 and ort != 'Bonn']">
         <xsl:sort select="plz"     data-type="number" order="ascending"/>
         <xsl:sort select="strasse" data-type="text"   order="ascending"/>
         <person>
            <xsl:attribute name="pid"> <xsl:value-of select="@id"/> </xsl:attribute>
            <nummer>  <xsl:number value="position()" format="1. "/> </nummer>
            <name>    <xsl:value-of select="name"/>    </name>
            <strasse> <xsl:value-of select="strasse"/> </strasse>
            <ort>     <xsl:value-of select="plz"/>
                      <xsl:text> </xsl:text>
                      <xsl:value-of select="ort"/> </ort>
            <xsl:if test="ort='Aachen'">
               <AachenGruesse> Hallo Aachen! </AachenGruesse>
            </xsl:if>
         </person>
      </xsl:for-each>
   </personen>
</xsl:template>
</xsl:stylesheet>

Der anfängliche <xsl:text></xsl:text>-Block ist nicht unbedingt notwendig. Er ist eingefügt, damit das Ergebnis unter Xalan und unter msxsl identisch aussieht.

Die Ergebnisliste wird diesmal vor der Ausgabe sortiert, zuerst nach Postleitzahl und bei gleicher Postleitzahl nach Straße. Außerdem sind noch einige weitere XSLT- und XPath-Ausdrücke verwendet (nicht unbedingt immer sinnvoll, wie etwa die Summe der Postleitzahlen oder die Aachen-Grüße). Sehen Sie sich hierzu die Doku zu XSLT und XPath an.

Bitte beachten Sie, dass beim Zugriff auf Attributwerte ein "@" vorangestellt werden muss, wie beim value-of select="@id" gezeigt ist, sowie dass beim Schreiben von Attributen <xsl:attribute...> verwendet werden muss.

Die Transformation kann wieder mit einem beliebigen XSL-Transformationstool erfolgen, zum Beispiel mit Xalan:

java -cp xalan.jar;serializer.jar org.apache.xalan.xslt.Process -XSL Adressen5.xsl -IN Adressen5.xml -OUT Result.xml

Oder alternativ mit msxsl:

msxsl Adressen5.xml Adressen5.xsl -o Result.xml

Oder alternativ mit XslTransformation:

java XslTransformation Adressen5.xsl Adressen5.xml Result.xml

Das XML-Ergebnis können Sie sich wahlweise in einem Texteditor, im Webbrowser oder in einem XML-Tool ansehen:

type Result.xml

start Result.xml

Alternativ können Sie auch mit Eclipse transformieren: Klicken Sie in Eclipse mit der rechten Maustaste auf Adressen5.xsl, wählen Sie 'Run As' | 'XSL Transformation' und wählen Sie als 'XML Input File' über die Schaltflächen die XML-Datei Adressen5.xml.

    
<?xml version="1.0" encoding="ISO-8859-1"?>
<personen>
  <anzahlPersonen>3</anzahlPersonen>
  <summePlz>123827</summePlz>
  <person pid="43">
    <nummer>1. </nummer>
    <name>Heinz Hinz</name>
    <strasse>Hafenstr. 42</strasse>
    <ort>21079 Hamburg</ort>
  </person>
  ... [weitere <person>-Elemente]
</personen>


Transformation zu PDF mit XSL-FO und Apache FOP per Kommandozeile

XSL-FO (XSL Formatting Objects) ist ein Teil der XSL-Spezifikation des W3C und spezifiziert, wie die grafische Aufbereitung von XML-Dokumenten beschrieben wird, und enthält Anweisungen zur Formatierung und Präsentation der Daten (siehe auch XSL FO Reference).

Apache FOP (Formatting Objects Processor) ist eine Implementierung von XSL-FO und erstellt aus XSL-FO-Layout-Beschreibungen verschiedene Ausgabeformate, zum Beispiel PDF, Java2D/AWT, AFP, PCL, MIF, PS, RTF, TIFF, PNG, SVG und TXT.

Falls Sie PDF mit Docbkx aus DocBook-Beschreibungen erzeugen wollen: Sehen Sie sich DocBook mit Docbkx an.
Falls Sie PDF nicht per XSL, sondern mit Java erzeugen und bearbeiten wollen: Sehen Sie sich PDF mit Apache PDFBox an.

Das folgende Beispiel verwendet XSL-FO und Apache FOP und erzeugt zu unserer bekannten Adressenliste ein PDF-Dokument.

Speichern Sie folgendes XSL-FO-Transformationsdokument: Adressen6.xsl

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:stylesheet version="1.0"
               xmlns:xs="http://www.w3.org/1999/XSL/Transform"
               xmlns:fo="http://www.w3.org/1999/XSL/Format">

   <!-- Attribut-Sets fuer Tabellenzellen -->
   <xs:attribute-set name="cell-style">
      <xs:attribute name="border-width">0.5pt</xs:attribute>
      <xs:attribute name="border-style">solid</xs:attribute>
      <xs:attribute name="border-color">black</xs:attribute>
   </xs:attribute-set>
   <xs:attribute-set name="block-style">
      <xs:attribute name="font-size">  10pt</xs:attribute>
      <xs:attribute name="line-height">15pt</xs:attribute>
      <xs:attribute name="start-indent">1mm</xs:attribute>
      <xs:attribute name="end-indent">  1mm</xs:attribute>
   </xs:attribute-set>

   <!-- Seitenaufteilung -->
   <xs:template match="/">
      <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
         <fo:layout-master-set>
            <fo:simple-page-master master-name="DIN-A4"
                  page-height="29.7cm" page-width="21cm"
                  margin-top="2cm"     margin-bottom="2cm"
                  margin-left="2.5cm"  margin-right="2.5cm">
               <fo:region-body
                  margin-top="1.5cm" margin-bottom="1.8cm"
                  margin-left="2cm"  margin-right="2.5cm"/>
               <fo:region-before region-name="header" extent="1.3cm"/>
               <fo:region-after  region-name="footer" extent="1.5cm"/>
               <fo:region-start  region-name="left"   extent="1cm"/>
               <fo:region-end    region-name="right"  extent="2cm"/>
            </fo:simple-page-master>
         </fo:layout-master-set>
         <fo:page-sequence master-reference="DIN-A4">
            <fo:static-content flow-name="header">
               <fo:block font-size="14pt" text-align="center">
                  Meine Adressenliste
               </fo:block>
            </fo:static-content>
            <fo:static-content flow-name="footer">
               <fo:block text-align="center">
                  Seite <fo:page-number/> von <fo:page-number-citation ref-id="LastPage"/>
               </fo:block>
            </fo:static-content>
            <fo:flow flow-name="xsl-region-body">
               <xs:apply-templates/>
               <fo:block id="LastPage"/>
            </fo:flow>
         </fo:page-sequence>
      </fo:root>
   </xs:template>

   <!-- Tabellenkopf -->
   <xs:template name="table-head">
      <fo:table-row>
         <fo:table-cell xs:use-attribute-sets="cell-style">
            <fo:block xs:use-attribute-sets="block-style"
                      text-align="center">Name</fo:block>
         </fo:table-cell>
         <fo:table-cell xs:use-attribute-sets="cell-style">
            <fo:block xs:use-attribute-sets="block-style"
                      text-align="center">Straße</fo:block>
         </fo:table-cell>
         <fo:table-cell xs:use-attribute-sets="cell-style">
            <fo:block xs:use-attribute-sets="block-style"
                      text-align="center">PLZ und Ort</fo:block>
         </fo:table-cell>
      </fo:table-row>
   </xs:template>

   <!-- Adressen-Root-Element-Template -->
   <xs:template match="adressen">
      <fo:table border-style="solid" table-layout="fixed" width="100%">
         <fo:table-column column-width="3cm"/>
         <fo:table-column column-width="3cm"/>
         <fo:table-column column-width="4cm"/>
         <fo:table-header>
            <xs:call-template name="table-head"/>
         </fo:table-header>
         <fo:table-body>
            <xs:apply-templates select="adresse"/>
         </fo:table-body>
      </fo:table>
   </xs:template>

   <!-- Template der 'adresse'-Elemente -->
   <xs:template match="adresse">
      <fo:table-row>
         <fo:table-cell xs:use-attribute-sets="cell-style">
            <fo:block xs:use-attribute-sets="block-style">
               <xs:value-of select="name"/>
            </fo:block>
         </fo:table-cell>
         <fo:table-cell xs:use-attribute-sets="cell-style">
            <fo:block xs:use-attribute-sets="block-style">
               <xs:value-of select="strasse"/>
            </fo:block>
         </fo:table-cell>
         <fo:table-cell xs:use-attribute-sets="cell-style">
            <fo:block xs:use-attribute-sets="block-style">
               <xs:value-of select="plz"/>
               <xs:text> </xs:text>
               <xs:value-of select="ort"/>
            </fo:block>
         </fo:table-cell>
      </fo:table-row>
   </xs:template>

</xs:stylesheet>

Downloaden Sie Apache FOP (z.B. fop-0.95-bin.zip). Entpacken Sie die Zipdatei und kopieren Sie daraus das komplette Verzeichnis fop-0.95 in das Verzeichnis, in dem Sie obige Adressen6.xsl gespeichert haben. Kopieren Sie außerdem noch die Adressen5.xml aus dem vorherigen Beispiel in dieses Verzeichnis.

Rufen Sie auf:

"fop-0.95/fop.bat" -xsl Adressen6.xsl -xml Adressen5.xml -pdf Result.pdf

start Result.pdf



Transformation zu PDF mit XSL-FO und Apache FOP per Java

Speichern Sie folgende Java-Klasse: FopBeispiel.java

import java.io.*;
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.fop.apps.*;

public class FopBeispiel
{
   public static void main( String[] args ) throws Exception
   {
      if( args.length != 3 ) {
         System.out.println( "Bitte XSL- und XML-Inputdateien sowie PDF-Outputdatei angeben." );
         return;
      }
      FopBeispiel.xmlToPdfPerXsl( args[0], args[1], args[2] );
      System.out.println( args[0] + " + " + args[1] + " --> " + args[2] );
   }

   public static void xmlToPdfPerXsl( String inputXSL, String inputXML, String outputPDF ) throws Exception
   {
      OutputStream pdf = new FileOutputStream( outputPDF );
      Fop    fop = FopFactory.newInstance().newFop( MimeConstants.MIME_PDF, pdf );
      Source xml = new StreamSource( inputXML );
      Source xsl = new StreamSource( inputXSL );
      Result sax = new SAXResult( fop.getDefaultHandler() );
      Transformer transformer = TransformerFactory.newInstance().newTransformer( xsl );
      transformer.transform( xml, sax );
   }
}

Downloaden Sie Apache FOP (z.B. fop-0.95-bin.zip). Entpacken Sie die Zipdatei und kopieren Sie die fop.jar aus dem fop-0.95\build-Verzeichnis sowie alle .jar-Libraries aus dem fop-0.95\lib-Verzeichnis in das neue Unterverzeichnis lib.

Rufen Sie im Kommandozeilenfenster auf:

javac -cp .;lib\fop.jar FopBeispiel.java

java -cp .;lib\fop.jar FopBeispiel Adressen6.xsl Adressen5.xml Result.pdf

start Result.pdf



XSL-Transformation per Java

Speichern Sie folgende Java-Klasse: XslTransformation.java

import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public class XslTransformation
{
   public static void main( String[] args ) throws Exception
   {
      if( args.length != 3 ) {
         System.out.println( "Bitte XSL- und XML-Inputdateien sowie Outputdatei angeben." );
         return;
      }
      XslTransformation.transform( args[0], args[1], args[2] );
      System.out.println( args[0] + " + " + args[1] + " --> " + args[2] );
    }

   public static void transform( String inputXSL, String inputXML, String outfile ) throws Exception
   {
      Result out = new StreamResult( outfile  );
      Source xml = new StreamSource( inputXML );
      Source xsl = new StreamSource( inputXSL );
      Transformer transformer = TransformerFactory.newInstance().newTransformer( xsl );
      transformer.transform( xml, out );
   }
}

Rufen Sie im Kommandozeilenfenster beispielsweise auf:

javac XslTransformation.java

java XslTransformation Adressen2.xsl Adressen2.xml Result.html

start Result.html



XSL-Transformation per Java mit Multithreading über threadsichere Templates

Falls Sie (z.B. im Batchbetrieb) mit immer demselben XSL-Stylesheet viele XML-Dokumente transformieren wollen, sparen Sie Zeit, wenn Sie das XSL-Stylesheet nur einmal kompilieren und die XML-Dokumente parallel in mehreren Threads transformieren. Dies zeigt folgendes Beispiel.

Speichern Sie folgende Java-Klasse: MultithreadingXslTransformation.java

import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public class MultithreadingXslTransformation
{
   // Erster Parameter:  XSL-Stylesheet
   // Weitere Parameter: Paare von XML- und Outputdateien
   // Beispielkommandozeile:
   //     java MultithreadingXslTransformation MyXsl.xsl 1.xml 1.out 2.xml 2.out 3.xml 3.out
   public static void main( String[] args ) throws Exception
   {
      if( args.length < 3 ) {
         System.out.println( "Bitte XSL-Datei sowie Paare von XML- und Outputdateien angeben." );
         return;
      }
      // Threadsichere Templates:
      Templates templates = compileStylesheetTemplates( args[0] );
      // Multithreading:
      for( int i=2; i<args.length; i+=2 ) {
         (new Thread( new TransformationRunnable( templates, args[i-1], args[i] ) )).start();
         System.out.println( args[0] + " + " + args[i-1] + " --> " + args[i] );
      }
   }

   public static Templates compileStylesheetTemplates( String inputXSL ) throws Exception
   {
      Source xsl = new StreamSource( inputXSL );
      return TransformerFactory.newInstance().newTemplates( xsl );
   }

   public static void transform( Templates templates, String inputXML, String outfile )
   {
      try {
         Source xml = new StreamSource( inputXML );
         Result out = new StreamResult( outfile  );
         templates.newTransformer().transform( xml, out );
      } catch( TransformerException ex ) {
         throw new RuntimeException( ex );
      }
   }
}

class TransformationRunnable implements Runnable
{
   Templates templates;
   String    inputXML;
   String    outfile;

   TransformationRunnable( Templates templates, String inputXML, String outfile )
   {
      this.templates = templates;
      this.inputXML  = inputXML;
      this.outfile   = outfile;
   }

   @Override
   public void run()
   {
      MultithreadingXslTransformation.transform( templates, inputXML, outfile );
   }
}


Transformation von TXT zu XML

Das Ausgangsdateiformat ist bei XSL-Transformationen immer XML. Sie können also nur von XML in andere Dateiformate transformieren, aber nicht umgekehrt. Falls Sie Textdateien mit festen Feldlängen zu XML transformieren wollen, sehen Sie sich Transformation von TXT zu CSV und zu XML an.





Weitere Themen: andere TechDocs | XML | XSD (Schema) | JAXB (Binding)
© 2009-2010 Torsten Horn, Aachen