Share

XSLT – Exkurs

Weil ichs mal in Erwägung gezogen habe, aber Abstand davon genommen habe, da es eine wirklich nützliche XSLT Lib für JavaScript nocht nicht gibt.
Das Problem ist, dass man XML Daten bekommt (so wie das bei mir der Fall ist), aber diese Daten zum Beispiel als HTML Inseln (siehe letzter Post) in seinen DOM Baum “einhängen” möchte.
Man könnte sich ja jetzt fragen, wieso man dann nicht gleich HTML als Ausgabeformat nutzen möchte, aber letztendlich soll es ja alles schön kompatibel zu anderen Client bleiben und ich denke mal, dass das von mir gewünschte Format alles andere als Standard wäre. Es fehlt also eine Anweisung, um XML in das gewünschte HTML Format zu überführen. Genau das bietet einem XSLT (Extensible Stylesheet Language Transformation).
Hierbei wird durch ein XSL-Script fest gelegt, welche Daten wo im Ausgabeformat (in meinem Fall also HTML) landen sollen.
Also nehmen wir folgendes XML File:
user.xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user uri="http://localhost:8080/cotodo/resources/users/3/">
    <email>Test3</email>
    <forename>Test</forename>
    <surname>NeuerTester</surname>
    <userId>3</userId>
    <created uri="http://localhost:8080/cotodo/resources/users/3/tasks/">
        <taskRef uri="http://localhost:8080/cotodo/resources/users/3/tasks/1/">
            <taskId>1</taskId>
        </taskRef>
        <taskRef uri="http://localhost:8080/cotodo/resources/users/3/tasks/2/">
            <taskId>2</taskId>
        </taskRef>
    </created>
    <groups uri="http://localhost:8080/cotodo/resources/users/3/groups/">
        <groupRef uri="http://localhost:8080/cotodo/resources/users/3/groups/1/">
            <groupId>1</groupId>
        </groupRef>
        <groupRef uri="http://localhost:8080/cotodo/resources/users/3/groups/2/">
            <groupId>2</groupId>
        </groupRef>
    </groups>
    <inbox uri="http://localhost:8080/cotodo/resources/users/3/tasks/">
        <taskRef uri="http://localhost:8080/cotodo/resources/users/3/tasks/2/">
            <taskId>2</taskId>
        </taskRef>
    </inbox>
    <outbox uri="http://localhost:8080/cotodo/resources/users/3/tasks/">
        <taskRef uri="http://localhost:8080/cotodo/resources/users/3/tasks/2/">
            <taskId>2</taskId>
        </taskRef>       
    </outbox>
</user>

Wie man gut erkennt, eine – recht tief – verschachtelte Ansammlung von Datenblöcken. Wichtig für REST sind zum Beispiel auch die Referenzen auf die verschiedenen Objekte (URIs), um ggf. Objekte vollständig nach zuladen.
Meine gewünschte HTML Ausgabe soll dann so aussehen:

user.html:

<li id="3" uri="http://localhost:8080/cotodo/resources/users/3/">
    <ul>
        <li id="email">Test3</li>
        <li id="forename">Test</li>
        <li id="surname">NeuerTester</li>
    </ul>
    <ul style="display:none" uri="http://localhost:8080/cotodo/resources/users/3/groups/">
        <li>1</li>
        <li>2</li>
    </ul>
    <ul style="display:none" uri="http://localhost:8080/cotodo/resources/users/3/outbox/">
        <li>2</li>
    </ul>
    <ul style="display:none" uri="http://localhost:8080/cotodo/resources/users/3/inbox/">
        <li>2</li>
    </ul>
    <ul style="display:none" uri="http://localhost:8080/cotodo/resources/users/3/created/">
        <li>1</li>
        <li>2</li>
    </ul>
</li>

Es handelt sich letztendlich um ein Listenelement (welches dann in einer users Liste landet), welches weitere Unterlisten enthält. Die Anzahl der Referenzen habe ich – zur optimierten Platzausnutzung und zur Übersichtlichkeit – verringert. Letztendlich reicht mir eine Referenz der Liste und kann dann mit Hilfe der RefIds auf die URIs der einzelnen Elemente zugreifen. Das display:none habe ich nur aus dem Grund eingefügt, dass gewisse Elemente nicht sichtbar sein müssen. Mir reicht, dass sie im DOM hinterlegt sind.
Um also so eine Ausgabe zu erreichen benutze ich folgendes Script:

user.xsl:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html"/>

    <xsl:template match="/">
        <xsl:element name="li">
            <xsl:attribute name="class">user</xsl:attribute>
            <xsl:attribute name="id"><xsl:value-of select="user/userId" /></xsl:attribute>
            <xsl:attribute name="uri"><xsl:value-of select="user/@uri" /></xsl:attribute>
            <xsl:element name="ul">
                <xsl:attribute name="class">attributes</xsl:attribute>
                    <li id="email"><xsl:value-of select="user/email"/></li>
                    <li id="forename"><xsl:value-of select="user/forename"/></li>
                    <li id="surname"><xsl:value-of select="user/surname"/></li>
        </xsl:element>
        <xsl:element name="ul">
                    <xsl:attribute name="class">groups</xsl:attribute>
                    <xsl:attribute name="style">display:none</xsl:attribute>
                    <xsl:attribute name="uri"><xsl:value-of select="user/@uri" />groups/</xsl:attribute>
                    <xsl:for-each select="user/groups/groupRef">   
                        <li><xsl:value-of select="groupId"/></li>
                    </xsl:for-each>
                </xsl:element>
                <xsl:element name="ul">
                    <xsl:attribute name="class">outbox</xsl:attribute>
                    <xsl:attribute name="style">display:none</xsl:attribute>
                    <xsl:attribute name="uri"><xsl:value-of select="user/@uri" />outbox/</xsl:attribute>
                    <xsl:for-each select="user/outbox/taskRef">
                        <li><xsl:value-of select="taskId"/></li>
                    </xsl:for-each>
        </xsl:element>   
                <xsl:element name="ul">
                    <xsl:attribute name="class">inbox</xsl:attribute>
                    <xsl:attribute name="style">display:none</xsl:attribute>
                    <xsl:attribute name="uri"><xsl:value-of select="user/@uri" />inbox/</xsl:attribute>
                    <xsl:for-each select="user/inbox/taskRef">   
                        <li><xsl:value-of select="taskId"/></li>
          </xsl:for-each>
        </xsl:element>   
                <xsl:element name="ul">
                    <xsl:attribute name="class">created</xsl:attribute>
                    <xsl:attribute name="style">display:none</xsl:attribute>
                    <xsl:attribute name="uri"><xsl:value-of select="user/@uri" />created/</xsl:attribute>
                    <xsl:for-each select="user/created/taskRef">   
                        <li><xsl:value-of select="taskId"/></li>
                    </xsl:for-each>
        </xsl:element>           
    </xsl:element>      
    </xsl:template>
</xsl:stylesheet>

Hierbei gelten folgende Regeln:

Der Zugriff auf die einzelnen Elemente erfolgt über XPath.

Also <xsl:value-of select=”user/userId” /> bedeutet, dass der Wert aus der Hirachie user/ geholt wird, welche zwischen den Tags userId steht. Möchte man auf ein Attribute zugreifen, so benutzt man das @ Zeichen. Wie z.B. bei <xsl:value-of select=”user/@uri” />.

Ich habe mich immer für die “Root” URI entschieden, weil die anderen URIs sich per Definitionem davon ableiten lassen.
Wollte man das XML Document nun direkt als HTML ausgeben haben, so fügt man in obiges Dokument unter

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

folgendes ein:

<?xml-stylesheet type="text/xsl" href="user.xsl"?>

Hierbei sollte die Datei natürlich unter dem gleichen Pfad erreichbar sein wir die user.xml. (Aus Testzwecken war das bei mir der Fall). Aber natürlich kann man auch jede andere URL angeben. Das Einbinden entspricht ungefähr dem von einer CSS Datei.
Empfehlenswert zu dem Thema sind folgende Links:

und zu guter Letzt:

You may also like...

1 Response

  1. Tim says:

    Cooler Artikel, werde ich mir merken.

Leave a Reply