XSLT

Aus Joachim Schuster Wiki
Version vom 16. April 2010, 15:41 Uhr von Joachim (Diskussion | Beiträge)

(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu: Navigation, Suche

Hier entsteht eine Sammlung von Informationen rund um die Transformation von XML via XSLT.

Inhaltsverzeichnis

* vs node()

Der * Operator matcht alle Elemente, wohingegen node() alle Knoten, also auch Text matcht.

<element>TEXT<inlineImage src='foo'/></element>

so würde ein template das auf * matcht nur das innere Element inlineImage verarbeiten.
Ein Match auf node() verarbeitet sowohl den Text als auch das inlineImage.

copy-of vs value-of

Beispiel:

<element>Text <foo>kindtext</foo> weiterer text</element>

value-of liefert den Wert des selektierten Knotens, bzw. inklusive dessen Kindknoten.

<xsl:value-of select="element"/>

liefert

Text kindtext weiterer text

copy-of liefert den Knoten inklusive seiner Kindknoten.

<xsl:copy-of select="."/>

liefert

<element>Text <foo>kindtext</foo> weiterer text</element>

find first or last element

Um das erste bzw. letzte Element eines bestimmten Typs zu finden kann im einfachsten Fall

<xsl:value-of select="//element[1]"/>

bzw.

 <xsl:value-of select="//element[last()]"/>

verwenden.

Dies liefert aber unter Umständen ein unerwartetes/falsches Ergebnis. Hier wird über den gesamten Baum nach element gesucht. Das [1] bedeutet, dass ein element, das an erster Stelle steht, ermittelt wird. Ebenso bedeutet, dass bei last() das element ermittelt wird, das an letzter Stelle steht. Diese umständliche Ausdrucksweise wird hier deutlich:

<doc>
 <chapter name="first">
  <element name="1.1"/>
  <element name="1.2"/>
 </chapter>
 <chapter name="second">
  <element name="2.1"/>
  <element name="2.2"/>
 </chapter>
</doc>

Der Ausdruck //element[1] wird 2 Elemente als Rückgabewert liefern. Weil die Bedinung [1] hier auf den Kontext und nicht auf das gesamte Dokument bezogen angewendet wird. Die Ergebnismenge wäre also element 1.1 und element 2.1. Analog würde es sich für den Ausdruck //element[last()] ergeben.

Möchte man aber nun wirklich das erste element und wirklich nur dieses haben, so muss man die den Ausdruck klammern, oder die ermittelten Elemente über eine for-each auswerten.

Klammern

<xsl:value-of select="(//element)[1]"/>

bzw.:

<xsl:value-of select="(//element)[last()]"/>

for-each

Darin wird die Ergebnismenge unabhängig von der Dokumentstruktur behandelt, sodass das erste bzw. letzte Element korrekt ermittelt wird.

<xsl:for-each select="//element">
 <xsl:if test="position() = 1">
  <xsl:value-of select="."/>
 </xsl:if>
</xsl:for-each> 

bzw.:

<xsl:for-each select="//element">
 <xsl:if test="position() = last()">
  <xsl:value-of select="."/>
 </xsl:if>
</xsl:for-each>

Links

[1]


JavaScript Funktionen in XSLT nutzen

Möchte man Beispielsweise das Datum in einer Transformation nutzen, so ist man auf Externe Hilfe angewiesen. Entweder schon im Quell-Dokument enthalten, oder über eine Extension-Function. Man kann aber Extension-Functions auch direkt im XSLT definieren. Am Beispiel einer JavaScript Funktion soll dies hier verdeutlicht werden.

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" 
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
   xmlns:msxsl="urn:schemas-microsoft-com:xslt"
   xmlns:myJavaScript="urn:internal:my-javascript">
   <msxsl:script language="JScript" implements-prefix="myJavaScript">
   <![CDATA[
       function GetCurrentDateTime()
       {
       var currentTime = new Date();
       var month = currentTime.getMonth() + 1;
       var day = currentTime.getDate();
       var year = currentTime.getFullYear();
       return(month + "/" + day + "/" + year);
       }
   ]]>
   </msxsl:script>

<xsl:template match="/">
   <xsl:value-of select="myJavaScript:GetCurrentDateTime()"/>
</xsl:template>

</xsl:stylesheet>

Der Namespace-Prefix "myJavaScript" wird im Root-Element festgelegt. Im Element script wird über das Attribut implements-prefix festgelegt, welchem Prefix dieses Script zugeordnet wird.

Das Script selbst wird in einen CDATA-Block gepackt.

Über myJavaScript:GetCurrentDateTime() kann auf die darin enthaltene JavaScript Funktion zugegriffen werden.

Namespace

Namespaces dienen der Gruppierung und Differenzierung von Element in einem Dokument. Es können damit auch Elemente mit gleichem (local-)name in verschiedenen Namensräumen existieren, die damit auch unterschiedliche Bedeutungen haben.

xmlns:PREFIX='URI'

PREFIX: kann frei gewählt werden. Kann dokumentenübergreifend sogar unterschiedliche sein, solange der URI der selbe ist.

URI: Eindeutiger Bezeichner.

Lässt man den PREFIX weg, so wird der Default-Namespace festgelegt.

Einfaches Beispiel:

<memo xmlns='urn:bogus:ns' xmlns:html='http://www.w3.org/1999/xhtml'>
 <html:body>
   Now hear <html:i>this</html:i>
 </html:body>
</memo>

Default-Namespace xmlns='urn:bogus:ns': Sämtliche Namespaces ohne Prefix gehören diesem Namespace an.

Namespace mit Prefix html xmlns:html='http://www.w3.org/1999/xhtml': Sobald ein Element den Prefix html erhält, gehört es diesem Namespace an.

URL vs. URN

Zunächst mal ist es egal, welchen Typen man als URI nutzt.

URLs haben den Vorteil, dass man damit z.B. auf existierende Schemas verlinken kann. Es wird aber dabei nirgends programmatisch ausgewertet, es dient nur dem besseren Verständnis und bietet sich zudem der Eindeutigkeit wegen als URI an.

URNs identifizieren eine Ressource eindeutig. Anders als URLs also bleiben diese auch dann gleich, wenn man diese Resource an einen anderen Ort bewegt. Eine korrekt vergebene URN benötigt demnach einen etwas größeren Aufwand.

In der Praxis findet man häuftig mit URN: eingeleitete URIs, die nicht unbedingt der Konvention entsprechen.

Da meist nur eine Identifizierung / Eindeutigkeit im Dokument gewährleistet sein muss, ist dieses Vorgehen legitim.


http://www.ibm.com/developerworks/xml/library/x-namcar.html

http://msdn.microsoft.com/en-us/library/ms950779.aspx