XSLT returns different results [Saxon-EE vs Saxon-HE / PE]

I am currently working on pure XSL conversion with a Saxon processor in different versions. Below is my small stylesheet simplified for the needs of my question:

<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:foo="bar"> <xsl:output encoding="UTF-8" method="text"/> <xsl:template match="/"> <xsl:text>Call of func_1: </xsl:text> <xsl:value-of select="foo:func_1()"/> <xsl:text>&#xA;Call of func_1: </xsl:text> <xsl:value-of select="foo:func_1()"/> <xsl:text>&#xA;Call of func_1: </xsl:text> <xsl:value-of select="foo:func_1()"/> <xsl:text>&#xA;Call of func_2: </xsl:text> <xsl:value-of select="foo:func_2()"/> </xsl:template> <xsl:function name="foo:func_1" as="xs:string"> <!-- do some other stuff --> <xsl:value-of select="foo:func_2()"/> </xsl:function> <xsl:function name="foo:func_2" as="xs:string"> <xsl:variable name="node"> <xsl:comment/> </xsl:variable> <xsl:sequence select="generate-id($node)"/> </xsl:function> </xsl:stylesheet> 

Description

foo:func_1 is a wrapper function that returns the value of the second function + doing other things that can be ignored. This function concept calls another function required!

foo:func_2 generates a unique identifier for an element. This item is created in a local cloud variable named "node".

Various results based on Saxon versions

Expected Result:

 Call of func_1: d2 Call of func_1: d3 Call of func_1: d4 Call of func_2: d5 

Saxon-EE 9.6.0.7/Saxon-EE 9.6.0.5 result

 Call of func_1: d2 Call of func_1: d2 Call of func_1: d2 Call of func_2: d3 

Saxon-HE 9.6.0.5/Saxon-PE 9.6.0.5/Saxon-EE 9.5.1.6/Saxon-HE 9.5.1.6 result

 like expected 

Question / in more detail

I debugged the problem myself as much as I could. IF I change the xsl:value-of function in the "func_1" function to xsl:sequence , the results will be the same for all versions [as expected]. But this is not my intention!

I want to understand what is the difference between xsl:value-of and xsl:sequence in Saxon versions. Is there hidden caching? What is the correct way to work with xsl:sequence and xsl:value-of in my case. [btw: I already know, value-of creates node text with the result of select-statement. the sequence can be a reference to a node or an atomic value. don't solve my afaik problem]

+8
xml xpath xslt saxon
source share
1 answer

This is a long and rather deep problem. In a pure functional language, calling a pure function twice with the same arguments always gives the same result. This makes many optimizations possible, such as disabling a function call from a loop if the arguments are invariant, or embedding a function call if it is not recursive. Unfortunately, the XSLT and XQuery functions are not entirely functional: in particular, they are defined so that if a function creates new nodes, then calling the function calls different nodes twice ( f() is f() returns false ).

The Saxon optimizer is quite difficult to optimize as much as possible in these constraints, in particular by recognizing functions that create new nodes and avoiding aggressive optimization of such functions.

But the specification itself is not 100% prescriptive. For example, if in your example there is a local variable without dependencies on the function arguments, I think that the specification gives a license for implementation regarding whether the variable value is the same node for each evaluation or is it a new node.

As Martin says, the new XSLT 3.0 attribute every time is an attempt to get it under control: if you really want a new node with every function call, you must specify new-each-time="yes" .

Note:

The specific optimization that happens here (which you can see using the -explain option) is that func_2 is built in first, and then its body is extracted into a global variable. Some releases do this, while others do not - it can be very sensitive to minor changes. The best advice is not to depend on features that have such a side effect. This will help if you explain your real problem, then perhaps we can find an approach that is not so sensitive to edge cases in the semantics of the language.

+2
source share

All Articles