
mike.shaw.nz+python.org@gmail.com schrieb am 01.04.21 um 13:11:
Hi Adrian/Stefan, Apologies for dredging up a 2-year-old thread but I've hit the same issue and found that although the posted solution works for variables declared with simple string values, it fails when considering xsl:param values or "calculated" values. Consider:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:abc="bar" extension-element-prefixes="abc"> <xsl:output method="xml"/> <xsl:param name="param1">default param value</xsl:param>
<xsl:template match="/"> <xsl:variable name="var1" select="concat( 'http://', $param1 )"/> <abc:foo attr1="{$var1}"/> <baz><xsl:value-of select="concat( 'XSLT ouput: ', $var1 )"/></baz> </xsl:template>
</xsl:stylesheet>
Now let's say I want to receive the value of "$var1" in my extension-element foo():
#!/usr/local/bin/python3 # -*- coding: utf-8 -*-
import sys
from lxml import etree from copy import deepcopy
class FooExtensionElement( etree.XSLTExtension ):
def execute( self, context, self_node, input_node, output_parent ): print( "attr1: {}".format( self_node.get( "attr1" )))
parser = etree.XMLParser( load_dtd=True ) extensions = { ( 'bar', 'foo' ) : FooExtensionElement() } transformer = etree.XSLT( etree.parse( sys.stdin, parser ), extensions = extensions ) xml_doc = etree.XML( '<dummy/>' ) result = transformer( xml_doc, param1=etree.XSLT.strparam( "passed param value" )) print( result )
When run, the output is:
attr1: {$var1}
<?xml version="1.0"?>
<baz bif="http://passed param value">XSLT ouput: http://passed param value</baz>
This shows that:
- self_node.get( "attr1" ) returns the literal string "{$var1}" in execute(), i.e. the transformer has not evaluated {$var1} when passing it to abc:foo/@attr1
- baz/@bif gets the evaluated value of {$var1} as expected
If I were to perform the solution suggested below and lookup //xsl:variable[ @name = 'var1']/@select from within execute(), it would return the string "concat( 'http://', $param1 )" I could attempt to evaluate this in self_node.xpath(), but I don't have access to the value of $param1, right? So this would result in: lxml.etree.XPathEvalError: Undefined variable What if I first looked up the value of $param1 in the same way as suggested below for xsl:variable? //xsl:param[ @name = 'param1']/text() would return "default param value", NOT the actual value ("passed param value") which was passed in: AFAIK, I have *no* way to access that value from execute().
Hmm, interesting problem. Thanks for bringing it up.
This problem goes away if evaluation of {$xyz} -syntax is honored for extension-elements. As demonstrated above, this is already working perfectly for elements in the XSL which have no namespace (the "baz" element in my example). Is there a fundamental reason why extension-elements are excluded from these evaluations?
The evaluation of the content and attributes of an extension element (including their order and semantics) is specific to the element, and thus needs to be done explicitly.
If this contravenes XSLT convention, is it possible to place a map of variable/param names and their values within the 'context' parameter passed to the execute() function so that extension elements can perform their own lookup?
I think it could be solved by providing an XPath entry point that knows about the current XSLT context, i.e. variables and parameters. Could be a method on the extension class.
However, I also see an advantage in providing access to the current name mappings. That would generally be nice to have in an extension element, and thus potentially cover a wider range of use cases.
I'd be happy to receive a PR that implements this.
Stefan