XSLT Transformation mit eigenen Funktionen

Hier als kleine Dokumentation für mich selbst ein Beispiel wie man eigene Funktionen während einer XSLT Transformation verwenden kann.

Hintergrund ist, dass man öfters auf das Problem stösst, dass die verfügbaren Methoden in XSL nicht ausreichen um das gewünschte Ergebnis zu erhalten. Z.B. füge das aktuelle Datum im deutschen Format an eine bestimmte stelle hinzu.

Um dies zu lösen, kann man einen eigenen Namespace registrieren und innerhalb dieses Namespaces eigene Methoden hinterlegen. In meinem Beispiel sind dies die Methode ecm:today() und ecm:greetings(//wert). Bei der zweiten Methode übergebe ich zusätzlich ein Element aus dem Quell XML mit welches dann in der Methode zur Verfügung steht.

Das Ganze kann man natürlich auch weiter treiben und Methoden definieren, die XMLs als Ergebnis zurück geben über welche man anschliessend im XSL iterieren kann.

@bb und @danielstraub: Vielleicht könnte das auch für eure Bemühungen relevant sein.

XML als Quelle

<root>
  <wert>Mein Wert</wert>
</root>

XSL Template

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ecm="https://ecmind.ch/extensions">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
  <xsl:template match="/">
    <result>
      <datum><xsl:value-of select="ecm:today()" /></datum>
      <begruessung><xsl:value-of select="ecm:greetings(//wert)" /></begruessung>
    </result>
  </xsl:template>
</xsl:stylesheet>

Code

from lxml import etree
from datetime import date

def today(context):
  return date.today().strftime("%d.%m.%Y")
  
def greetings(context, a):
  value = a[0].text
  return f"Hello '{value}'"

ns = etree.FunctionNamespace('https://ecmind.ch/extensions')
ns.prefix = 'ecm'

ns['today'] = today
ns['greetings'] = greetings

source = etree.parse("source.xml")
xsl = etree.parse("transform.xsl")

transform = etree.XSLT(xsl)

result = transform(source)

print(result)

Ergebnis

<result xmlns:ecm="https://ecmind.ch/extensions">
  <datum>30.03.2021</datum>
  <begruessung>Hello 'Mein Wert'</begruessung>
</result>

Alternativ können auch Parameter in die transform(mein xml, var1=etree.XSLT.strparam("mein wert")) Methode übergeben werden. Diese können im XSL per <xsl:param name="var1"/> bekannt gemacht werden und anschliessend im XML z.B. per <xsl:value-of select="$var1" />eingesetzt werden.