Bug #6660
openProblem with `xsl:number level="any"` when count pattern uses `current()`
0%
Description
I tried to use
<xsl:template match="g:prodrecap">
<xsl:number level="any" count="g:prodrecap[@ref = current()/@ref]"/>
and it gave strange results.
Working to produce a repro.
Updated by Michael Kay 1 day ago
Repro constructied in mike/bugs/2025/6660-Kay.
Running with 12.x, command line
Transform -xsl:assemble-spec.xsl -s:xquery-preprocessed.xml -t -o:out.xml
At assemble-spec#165 I am doing
<xsl:variable name="duplicate" as="xs:integer"
select="xs:integer(count(preceding::prodrecap[@ref=current()/@ref]) + 1)"/>
<xsl:variable name="duplicate2" as="xs:integer">
<xsl:number level="any" count="prodrecap[@ref=current()/@ref]"/>
</xsl:variable>
<xsl:message expand-text="1">*** Duplicate {$duplicate} vs {$duplicate2} at {path(.)} ***</xsl:message>
I would expect the two variables to have the same value, but this is not the case.
The -explain output shows
<nodeNum role="value" level="any">
<dot role="select" type="1NE nQ{}prodrecap" flags="a"/>
<p.withCurrent role="count">
<p.withPredicate>
<p.nodeTest test="NE nQ{}prodrecap"/>
<gc10 op="="
cardinality="many-to-many (1.0)"
comp="GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint">
<axis name="attribute" nodeTest="NA nQ{}ref"/>
<docOrder intra="1">
<slash>
<varRef name="Q{http://www.w3.org/2005/xpath-functions}current" slot="3"/>
<axis name="attribute" nodeTest="NA nQ{}ref"/>
</slash>
</docOrder>
</gc10>
</p.withPredicate>
</p.withCurrent>
</nodeNum>
which looks reasonable -- except that it made me realise there is code running in 1.0 compatibility mode.
Changing this doesn't materially affect the result - the explain output now shows a <vc>
instruction in place of a <gc10>
.
Updated by Michael Kay 1 day ago
Navigator.getNumberAny()
is being called with the argument hasVariablesInPatterns
set to false, which means that the function uses memoization, which means that it works by search back to the last numbered/matching node and adding 1 to the number. This optimization is inappropriate when the pattern has a reference to current()
.
Updated by Michael Kay 1 day ago
I think this is a user error.
In the construct
<xsl:number level="any" count="g:prodrecap[@ref = current()/@ref]"/>
The function current()
does not return the node being numbered, it returns the node being matched against the count()
pattern, which is a different node each time. The spec says:
If the current function is used within a pattern, its value is the item that is being matched against the pattern.
Changing the code to
<xsl:variable name="this" select="."/>
<xsl:number level="any" count="prodrecap[@ref=$this/@ref]"/>
However, it's not optimised so it has quadratic performance -- and gives no benefit over count(preceding::prodrecap[....])
A more efficient solution would probably be to compute the numbers while the nodes are being generated in the previous pass.
Please register to edit this issue