I'm having trouble understanding why XSLT (Saxon 9.1 and 9.5) is working the way it does when using a variable containing a sorted sequence.
Here is the output of my program with my three questions embedded:
<?xml version="1.0" encoding="UTF-8"?>
The following sequence is unsorted...
sequence $list = (<contribution e="4"/><contribution e="1"/><contribution e="2"/><contribution e="8"/>)
It is, as I expected, in document order.
The following sequence is explicitly sorted...
sequence $sorted-list = (<contribution e="8"/><contribution e="4"/><contribution e="2"/><contribution e="1"/>)
It is, as I expected, sorted in descending numerical @e order.
In the following output, I expect for the @e values from $list to be in document order,
and for the @e values from $sorted-list to be in descending numerical order...
value-of $list/@e = (4 1 2 8)
value-of $sorted-list/@e = (4 1 2 8)
But both are in document order.
Specifically, the $sorted-list/@e values are NOT listed in descending numerical @e order.
(Question 1: ...By the way, why can't I use 'xsl:sequence select="$list/@e"' here?)
Next, here's the real work that I'm interested in. It is a function that computes a running
subtotal of the elements passed in. Order is critical here. I expect for my sorted list to provide
@e values to the function in the order that I explicitly put them in the definition of $sorted-list.
So, in the following call, I send in the sequence that I think SHOULD have been sorted...
sequence f($sorted-list/@e) = (0 4 5 7 15)
But my result set is a list of running subtotals that are obviously not correctly ordered.
Question 2: Is this a bug, or evidence of a gap in my comprehension?
In the following call, I send a sequence that's explicitly ordered...
sequence f(for...$sorted-list[$i]/@e) = (0 8 12 14 15)
...and I receive the sequence I need. I can use this as a workaround.
Question 3: Why is it that I must explicitly [re-]sort the $sorted-list sequence as I pass it to util:f()?
Here's my input XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<contribution e="4"/>
<contribution e="1"/>
<contribution e="2"/>
<contribution e="8"/>
</root>
...And my XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:util="http://www.method-r.com/util"
exclude-result-prefixes="xs util"
version="2.0">
<xsl:template match="/">
The following sequence is unsorted...
sequence $list = (<xsl:sequence select="$list"/>)
It is, as I expected, in document order.
The following sequence is explicitly sorted...
sequence $sorted-list = (<xsl:sequence select="$sorted-list"/>)
It is, as I expected, sorted in descending numerical @e order.
In the following output, I expect for the @e values from $list to be in document order,
and for the @e values from $sorted-list to be in descending numerical order...
value-of $list/@e = (<xsl:value-of select="$list/@e"/>)
value-of $sorted-list/@e = (<xsl:value-of select="$sorted-list/@e"/>)
But both are in document order.
Specifically, the $sorted-list/@e values are NOT listed in descending numerical @e order.
(Question 1: ...By the way, why can't I use 'xsl:sequence select="$list/@e"' here?)
Next, here's the real work that I'm interested in. It is a function that computes a running
subtotal of the elements passed in. Order is critical here. I expect for my sorted list to provide
@e values to the function in the order that I explicitly put them in the definition of $sorted-list.
So, in the following call, I send in the sequence that I think SHOULD have been sorted...
sequence f($sorted-list/@e) = (<xsl:sequence select="util:f(0, $sorted-list/@e)"/>)
But my result set is a list of running subtotals that are obviously not correctly ordered.
Question 2: Is this a bug, or evidence of a gap in my comprehension?
In the following call, I send a sequence that's explicitly ordered...
sequence f(for...$sorted-list[$i]/@e) = (<xsl:sequence select="util:f(0, for $i in 1 to count($sorted-list) return $sorted-list[$i]/@e)"/>)
...and I receive the sequence I need. I can use this as a workaround.
Question 3: Why is it that I must explicitly [re-]sort the $sorted-list sequence as I pass it to util:f()?
<xsl:text/>
</xsl:template>
<xsl:variable name="list" as="element()*" select="//contribution"/>
<xsl:variable name="sorted-list" as="element()*">
<xsl:perform-sort select="$list">
<xsl:sort select="number(@e)" order="descending"/>
</xsl:perform-sort>
</xsl:variable>
<xsl:function name="util:f" as="xs:double*">
<xsl:param name="sum0" as="xs:double"/>
<xsl:param name="list" as="xs:double*"/>
<xsl:sequence select="util:cumulative-list-2((), $list)"/>
</xsl:function>
<xsl:function name="util:cumulative-list-2" as="xs:double*">
<xsl:param name="list" as="xs:double*"/>
<xsl:param name="list-remainder" as="xs:double*"/>
<xsl:choose>
<xsl:when test="not(exists($list-remainder))">
<xsl:sequence select="$list"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="util:cumulative-list-2(
if (empty($list)) then
(0, $list-remainder[1])
else
($list, $list[last()] + $list-remainder[1]),
remove($list-remainder, 1)
)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
</xsl:stylesheet>