Essence of the problem (see Error during transformation in Saxon 9.7, thread on forum):
$N[@x castable as xs:date][xs:date(@x) gt xs:date("2000-01-01")]
$N[xs:date(@x) gt xs:date("2000-01-01")][@x castable as xs:date]
@x
xs:date
To avoid a potential problem one should rewrite the expression like this: $N[if (@x castable as xs:date) then xs:date(@x) gt xs:date("2000-01-01") else false()].
$N[if (@x castable as xs:date) then xs:date(@x) gt xs:date("2000-01-01") else false()]
Please note that the following rewrite will not work: $N[(@x castable as xs:date) and (xs:date(@x) gt xs:date("2000-01-01"))], as arguments of and expression can be evaluated in any order, and error that occurs during evaluation of any argument may be propageted.
$N[(@x castable as xs:date) and (xs:date(@x) gt xs:date("2000-01-01"))]
and
With these facts we faced a task to check our code base and to fix possible problems.
A search has brought ~450 instances of XPath expessions that use two or more consequtive predicates. Accurate analysis limited this to ~20 instances that should be rewritten. But then, all of sudden, we have decided to commit an experiment. What if we split XPath expression in two sub expressions. Can error still resurface?
Consider:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xsl:variable name="elements" as="element()+"><a/><b value="c"/></xsl:variable> <xsl:template match="/"> <xsl:variable name="a" as="element()*" select="$elements[self::d or self::e]"/> <xsl:variable name="b" as="element()*" select="$a[xs:integer(@value) = 1]"/> <xsl:sequence select="$b"/> </xsl:template> </xsl:stylesheet>
As we expected Saxon 9.7 internally assembles a final XPath with two predicates and reorders them. As result we get an error:
Error at char 20 in xsl:variable/@select on line 8 column 81 of Saxon9.7-filter_speculation.xslt: FORG0001: Cannot convert string "c" to an integer
This turn of events greately complicates the code review we have to commit.
Michiel Kay's answer to this example:
I think your argument that the reordering is inappropriate when the expression is written using variables is very powerful. I shall raise the question with my WG colleagues.
In fact we think that either: reordering of predicates is inappropriate, or (weaker, to allow reordering) to treat an error during evaluation of predicate expression as false(). This is what is done in XSLT patterns. Other solutions make XPath less intuitive.
false()
In other words we should use XPath (language) to express ideas, and engine should correctly and efficiently implement them. So, we should not be forced to rewrite expression to please implementation.