我无法理解为什么XSLT(Saxon 9.1和9.5)在使用包含排序序列的变量时的工作方式。
这是我的程序的输出,其中嵌入了我的三个问题:
<?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()?
这是我的输入XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<contribution e="4"/>
<contribution e="1"/>
<contribution e="2"/>
<contribution e="8"/>
</root>
......还有我的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>
答案 0 :(得分:2)
通过执行$sorted-list/@e
的步骤,/@e
将选择所有@e
属性并按文档顺序排序,因此如果您有已排序的序列并想要输出@e
属性按顺序排列,您无法使用$sorted-list/@e
,而是必须使用for $item in $sorted-list return $item/@e
。
请参阅http://www.w3.org/TR/xpath20/#id-path-expressions说明:
每个操作E1 / E2的评估如下:......如果每次评估 E2返回一个(可能是空的)节点序列,这些序列 组合,并根据节点消除重复节点 身份。生成的节点序列按文档顺序返回。
如果您使用Saxon 9.5的商业版本,那么您还应该能够使用http://www.w3.org/TR/xpath-30/#id-map-operator和$sorted-list ! @e
来保留订单。