Die XSLT-Funktion unparsed-text()

(Auszug aus "XSLT 2.0 & XPath 2.0" von Frank Bongers, Kapitel 3.)

Auch externe Textressourcen können eingelesen und verarbeitet werden. Dies können beispielsweise CSV-Dateien sein, wie sie durch einen Datenbunk-Dump erzeugt werden, oder andere Formate. Muss oder soll die Ressource nicht geparst werden, so setzt man die XSLT-Funktion unparsed-text() ein.

Angenommen, es liegt eine Ressource vor, die Informationen über Bücher enthält, die pro Buch eine Zeile einnehmen. Die einzelnen Informationen sind durch Komma getrennt, wobei Felder leer bleiben können, die keine Informationen (oder Defaultwerte) enthalten sollen:

Java für Anfänger, Tiger, Theobald, Java Verlag, 45.00, , 3-899-77618-4
Java für Praktiker, Jobst, Julius, EDV Verlag, 42.95, ,
Another Dog's Guide, Murr, Kater, Miau Publishing, 23.95, Dollar, ,
Java für Theoretiker Bd.1, Jobst, Julius, EDV Verlag, 42.95, ,
Java für Theoretiker Bd.2, Jobst, Julius, EDV Verlag, 42.95, ,
Siddhartha, Hesse, Hermann, Suhrkamp, 11.80, , 3-518-36682-3

Code-Beispiel: kap03/3.07/buchliste.txt (Ausschnitt).

Zur Verarbeitung wird die Datei im Stylesheet in eine Variable gespeichert – Sie können hierfür eine globale oder eine lokale Variable einsetzen. In diesem Fall wurde eine lokale Variable gewählt:

<xsl:variable name="text" select="unparsed-text('buchliste.txt','ISO-8859-1')"/>

Code-Beispiel: kap03/3.07/buchliste_txt.xsl (Ausschnitt).

Die Ressource wird über das select-Attribut geholt. Beachten Sie, dass unparsed-text() als ersten Parameter einen String mit Pfad und Dateiname der Ressource erwartet. Der zweite Parameter ist optional und bezeichnet (wieder als Zeichenkette) das Encoding der externen Ressource.

Im Starttemplate soll der eingelesene Text nun in Einzelzeilen aufgespalten und die Zeilen in einer Schleife ausgegeben werden. Ersteres geschieht mit Hilfe der XPath-Funktion fn:tokenize() und einem regulären Ausdruck, der Zeilenumbruchzeichen erkennt. Die Funktion erzeugt eine Sequenz aus String-Items (den Zeilen), die von einer xsl:for-each-Instruktion verarbeitet werden:

<xsl:template match="/">
  <html>
    ...
    <body>
      <h1>Buchliste aus externer Textressource</h1>
      <xsl:for-each select="fn:tokenize($text,'(\r)|(\n)|(\r\n)')">
        <xsl:if test="fn:string-length(fn:normalize-space(.)) gt 0">
          <p><xsl:value-of select="."/></p>
        </xsl:if>
      </xsl:for-each>
    </body>
  </html>
</xsl:template>

Code-Beispiel: kap03/3.07/buchliste_txt.xsl (Ausschnitt).

Beachten Sie, dass jede Zeile in einem p-Container ausgegeben wird. Um zu vermeiden, dass bei leeren Zeilen in der Ressource entsprechend ein leerer <p>-Container ausgegeben wird, wird vorher getestet, ob überhaupt ausgegeben werden soll. Hierzu dient die innenliegene Instruktion xsl:if. Es wird jedoch nicht einfach geprüft, ob ein Teilstring (die Zeile) nicht dem leeren String entspricht, sondern dieser wird mit fn:normalize-space() vorher normalisiert. Dies fängt die Möglichkeit ab, dass eine scheinbar »leere« Zeile in Wirklichkeit Leerzeichen oder Tabulatoren enthält (da die Ressource nicht im Vorfeld geparst wird, kann dies der Fall sein):

<xsl:if test="fn:string-length(fn:normalize-space(.)) gt 0">

Die Ausgabe funktioniert soweit, sieht jedoch nicht sonderlich attraktiv aus (siehe die folgende Abbildung).

Buchliste aus externer Text-Ressource

Abbildung: Buchliste aus externer Text-Ressource.

Die einzelnen Felder der Information sollen einzeln erfasst und verschieden formatiert werden können. Man könnte mit fn:tokenize() die Tatsache ausnützen, dass die Felder durch Komma getrennt sind und auf diesem Wege eine Sequenz erzeugen, die anschließend weiterverarbeitet wird. In diesem Fall ist das ein Umweg – genausogut ist für unseren Zweck der Direktzugriff auf ein Item, das fn:tokenize() erzeugt.

Hierfür bietet sich ein einfaches Filterprädikat an, beispielsweise fn:tokenize(., ',')[1], um an das erste Item zu gelangen und so fort. Der Punkt steht für das Current Item, das in der xsl:for-each-Schleife gerade ansteht (hier also einen Zeilenstring). Folgendermaßen kann man vorgehen:

<xsl:for-each select="fn:tokenize($text,'(\r)|(\n)|(\r\n)')">
  <xsl:if test="fn:string-length(.) gt 0">
    <p><b><xsl:value-of select="fn:tokenize(.,',')[1]"/></b> von <i><xsl:value-of select="fn:tokenize(.,',')[2]"/>, <xsl:value-of select="fn:tokenize(.,',')[3]"/></i><br/> <xsl:value-of select="fn:tokenize(.,',')[4]"/>; Preis: <xsl:value-of select="fn:tokenize(.,',')[5]"/>
    ...
    </p>
  </xsl:if>
</xsl:for-each>

Code-Beispiel: kap03/3.07/buchliste_txt2.xsl (Ausschnitt).

Bis einschließlich der Preisangabe ist dies einfach, da alle entsprechenden Informationen vorliegen müssen. Nun kommen jedoch zwei Felder, die leer sein können – erstens die Währungsangabe, die per Default auf 'Euro' stehen soll, wenn sie entfällt und zweitens die Angabe einer ISBN-Nummer.

Wir gehen ähnlich vor wie beim Test auf Leerzeilen, erweitern den Test jedoch um eine in XPath formulierte Bedingung:

<xsl:value-of select="if(fn:normalize-space(fn:tokenize(.,',')[6]) eq '') then ' Euro' else fn:tokenize(.,',')[6]"/>
  

Code-Beispiel: kap03/3.07/buchliste_txt2.xsl (Ausschnitt).

Analog funktioniert die Ausgabe der ISBN-Nummer bzw. eines Defaulttextes:

<xsl:value-of select="if (fn:normalize-space(fn:tokenize(.,',')[7]) eq '') then '(ISBN-Nr. liegt nicht vor)' else fn:concat(' (ISBN: ',fn:tokenize(.,',')[7],')')"/>
  

Code-Beispiel: kap03/3.07/buchliste_txt2.xsl (Ausschnitt).

In diesem Fall sollen jedoch der Feldinformation noch weitere Strings hinzugefügt werden – hier muss die Funktion fn:concat() zu Hilfe genommen werden. Diese Funktion nimmt eine beliebige Anzahl von Stringargumenten entgegen und verkettet sie zu einem einzugen Ausgabestring.

Das Ergebnis sieht jetzt ganz vernünftig aus:

Buchliste aus externer Text-Ressource, formatiert

Abbildung: Buchliste aus externer Text-Ressource, formatiert.

Im nächsten Abschnitt wird nun nicht, wie bisher, nur ein einzelnes Ergebnisdokument ausgegeben, sondern es werden gleich eine ganze Reihe von Dokumenten erzeugt.

   

<< zurück vor >>
Tipp der data2type-Redaktion:
Zum Thema XSLT bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © Galileo Press, Bonn 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XSLT 2.0 & XPath 2.0 ― Das umfassende Handbuch" 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.


Galileo Press, Rheinwerkallee 4, 53227 Bonn