Supposing I have an XPath function I'm calling from an XSL transform using lxml
(with libxml
and libxslt
), eg:
<xsl:template match="/">
<xsl:variable name="result" select="myns:my-func(./*)" />
...
</xsl:template>
From this function, I'd like to return an XML fragment that consists the following:
some sample <em>text</em>
The python function my_func
is set-up correctly using lxml
to be available via the XSL stylesheet, and used lxml.html.fragments_fromstring
to obtain the results which are in the format:
['some sample ', <Element em at 0x106c203b0>]
How can I return this list so it can be used later in the XSL transform from the variable as though it were collected from an XPath expression directly in the XSL context? It seems that whenever I pass a list of strings back to the XSL processor lxml
throws an exception.
The first thing is to define your function. It needs to return the node-set as a list of items. The items may include Elements (also comments and processing instructions), strings and tuples.
A hardcoded example might look like this:
from lxml import etree
def myFunc(context, parm):
em = etree.Element('em')
em.text = 'text'
return ['some sample ', em]
Note that the parm parameter isn't necessary in this case, but I've included it here to match your example code which is passing a parameter in the call to myns:my-func.
And if you wanted to use the fragments_fromstring to construct your node-set, rather than building it manually, the function definition becomes even simpler.
def myFunc(context, parm):
import lxml.html
return lxml.html.fragments_fromstring('some sample <em>text</em>')
Next you need to setup the namespace and register the function name.
myns = etree.FunctionNamespace('http://example.org/myNamespace')
myns['my-func'] = myFunc
And finally you can use it from within an XSLT stylesheet like this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:myns="http://example.org/myNamespace">
<xsl:template match="/">
<xsl:variable name="result" select="myns:my-func(./*)" />
<xsl:for-each select="$result">
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Note the namespace URL used in the stylesheet must match the one registered in the FunctionNamespace.
Now assuming you've loaded this stylesheet into a string called xslt, an example transform might look like this:
root = etree.XML('<root></root>')
doc = etree.ElementTree(root)
transform = etree.XSLT(etree.XML(xslt))
res = transform(doc)
For a full working example, see this pastebin link.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With