XSL mit Saxon und der Java Aufruf mit XML als Parameter
Setzt man eine XSL Transformation in Java um, bieten die genutzten Prozessoren meist einen Java Exit, also eine Möglichkeit an, aus der Transformation heraus eine Java Funktion aufzurufen. So auch der Saxon.
Bei der Umsetzung stieß ich dabei auf Stolpersteine. Der wichtigste: die Saxon Home Edition (HE) unterstützt den Java Aufruf nicht und man bekommt beim Ausführen der Transformation die hilfreiche Fehlermeldung “Cannot find a matching 1-argument function named {java:org.package.foo.Klasse}function()”. Es gibt also keinen Hinweis darauf, dass es an Saxon selbst scheitert. Bevor man also überhaupt etwas an der Transformation oder der Java Implementierung ändert, zuerst nachsehen, ob statt der saxon9he.jar aus der Home Edition, die saxon9.jar und die saxon9-dom.jar als external Jar im Build Path hinterlegt sind.
Eine weitere Möglichkeit, dass der Aufruf nicht funktioniert, kann darin liegen, dass die aufzurufende Funktion auf jeden Fall als
definiert sein muss. Zu guter letzt muß die Einbindung der Funktion korrekt sein. Einmal im <xsl:stylesheet> mit
<xsl:stylesheet
xmlns:Abkuerzung="java:org.package.foo.Klasse"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
und desweiteren im gewünschten Ziel-Knoten dann mit
<Zielknoten><xsl:value-of select="Abkuerzung:function()"/></Zielknoten>
Funktioniert die Transformation und der Aufruf der Java Funktion liefert das gewünschte ein Ergebnis, kann die Frage aufkommen, wie man einen Ausschnitt aus dem XML an Java übergeben kann. Während dies mit XSL 2.0 kein Problem darstellen sollte, sieht es bei XSL 1.0 anders aus. Bei diesem gibt es keine Unterstützung für temporäre Bäume, so dass bei der versuchten Übergabe des Baumes nur dessen Inhalt übernommen wird. Einen Ausweg stellt die Nutzung von <![CDATA[ dar.
Ein
<ziel><xsl:value-of select="/pfad/quelle"/></xsl:value>
würde also nur eventuell vorhandene Inhalte in den Knoten kopieren. Wenn man den zu kopierenden Knoten mit einem CDATA einpackt, kann er komplett übergeben und v.a. auch zurückgegeben werden.
Quelle:
1
2
3
4
5
| <quelle>
<knoten>
<kind><![CDATA[Testinhalt auch Knoten <moep></moep> test]]></kind>
</knoten>
</quelle> |
Wenn man das Einpacken des Quellknotens auch selbst machen muss und der Inhalt des Knotens ebenso irgendwoher kopiert wird, ist ebenfalls ein Eingriff notwendig:
1
2
3
4
5
6
7
8
9
10
11
| <quelle>
<knoten>
<kind>
<xsl:variable name="cdstart"><![CDATA[</xsl:variable>
<xsl:variable name="cdend">]]></xsl:variable>
<xsl:value-of disable-output-escaping="yes" select="$cdstart"/>
<xsl:copy-of select="/anderer/quell/knoten"/>
<xsl:value-of disable-output-escaping="yes" select="$cdend"/>
</kind>
</knoten>
</quelle> |
Mit diesem XSL kann man dann den Inhalt kopieren und erhält an der gewünschten Stelle auch den XML-Baum statt einer mit < und > oder nur Inhalt versehenen Version.
1
2
3
| <ziel>
<xsl:value-of select="/quelle/knoten/kind"/>
</ziel> |
Zur Erklärung: den Umweg das CDATA in Variablen zu stecken muss man gehen, da sonst die < und > zu den HTML-Entities werden.