On December, 30 we have opened a thread in Saxon help forum that shows a stylesheet generating an error. This is the stylesheet:
<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:sequence select="$elements[self::d or self::e][xs:integer(@value) = 1]"/> </xsl:template> </xsl:stylesheet>
We get an error:
Error at char 47 in xsl:sequence/@select on line 7 column 83 of Saxon9.7-filter_speculation.xslt: FORG0001: Cannot convert string "c" to an integer Exception in thread "main" ; SystemID: .../Saxon9.7-filter_speculation.xslt; Line#: 7; Column#: 47 ValidationException: Cannot convert string "c" to an integer at ...
It's interesting that error happens in Saxon 9.7 but not in earlier versions.
The answer we got was expected but disheartening:
The XPath specification (section 2.3.4, Errors and Optimization) explicitly allows the predicates of a filter expression to be reordered by an optimizer. See this example, which is very similar to yours: The expression in the following example cannot raise a casting error if it is evaluated exactly as written (i.e., left to right). Since neither predicate depends on the context position, an implementation might choose to reorder the predicates to achieve better performance (for example, by taking advantage of an index). This reordering could cause the expression to raise an error. $N[@x castable as xs:date][xs:date(@x) gt xs:date("2000-01-01")]
The expression in the following example cannot raise a casting error if it is evaluated exactly as written (i.e., left to right). Since neither predicate depends on the context position, an implementation might choose to reorder the predicates to achieve better performance (for example, by taking advantage of an index). This reordering could cause the expression to raise an error. $N[@x castable as xs:date][xs:date(@x) gt xs:date("2000-01-01")]
The expression in the following example cannot raise a casting error if it is evaluated exactly as written (i.e., left to right). Since neither predicate depends on the context position, an implementation might choose to reorder the predicates to achieve better performance (for example, by taking advantage of an index). This reordering could cause the expression to raise an error.
$N[@x castable as xs:date][xs:date(@x) gt xs:date("2000-01-01")]
Following the spec, Michael Kay advices us to rewrite XPath:
$elements[self::d or self::e][xs:integer(@value) = 1]
like this:
$elements[if (self::d or self::e) then xs:integer(@value) = 1 else false()]
Such subtleties make it hard to reason about and to teach XPath. We doubt many people will spot the difference immediately.
We think that if such optimization was so much important to spec writers, then they had to change filter rules to treat failed predicates as false(). This would avoid any obscure differences in these two, otherwise equal, expressions. In fact something similar already exists with templates where failed evaluation of pattern is treated as un-match.
false()