为什么 index-of() 在应用于唯一节点序列时会返回多个值?
我使用 xpath2 的索引值来返回已排序的节点序列中 current() 的索引。使用 SAXON,排序的节点序列是唯一的,但 index-of 返回两个值的序列。
这种情况不会一直发生,只是偶尔发生,但我找不到任何原因。有人可以解释一下发生了什么事吗?
我根据例程给出的这种奇怪行为的数据示例编写了一个最小的示例。
源数据是:
<data>
<student userID="1" userName="user1"/>
<session startedOn="01/16/2012 15:01:18">
</session>
<session startedOn="11/16/2011 13:31:33">
</session>
</data>
我的 xsl 文档将会话节点放入根模板最顶部的排序序列 $orderd 中:
<xsl:template match="/">
<xsl:variable name="nodes" as="node()*" select="/data/session"></xsl:variable>
<xsl:variable name="orderd" as="node()*">
<xsl:for-each select="$nodes">
<xsl:sort select="xs:dateTime(xs:dateTime(concat(substring(normalize-space(@startedOn),7,4),'-',substring(normalize-space(@startedOn),1,2),'-',substring(normalize-space(@startedOn),4,2),'T',substring(normalize-space(@startedOn),12,8)))
)" order="ascending"/>
<xsl:sequence select="."/>
</xsl:for-each>
</xsl:variable>
由于节点已按 @startOn 排序,但顺序相反,因此序列 $orderd 应该相同作为文档排序序列 $nodes,除了相反的顺序。
当我使用 for-each 语句创建输出时,我发现在使用 index-of 测试时,两个节点在某种程度上被视为相同。
下面的代码用于输出数据(紧接在上面的块之后):
<output>
<xsl:for-each select="$nodes">
<xsl:sort select="position()" order="descending"></xsl:sort>
<xsl:variable name="index" select="index-of($orderd,current())" as="xs:integer*"></xsl:variable>
<xsl:variable name="pos" select="position()"></xsl:variable>
<session reverse-documentOrder="{$pos}" sortedOrder="{$index}"/>
</xsl:for-each>
</output>
正如输出(如下所示)所示,index-of 函数返回序列 (1,2),这意味着它将两个节点视为相同的。我已经检查了用于对值进行排序的表达式,它生成了独特且格式良好的日期时间字符串。
<output>
<session reverse=documentOrder="1"
sortedOrder="1 2"/>
<session reverse-documentOrder="2"
sortedOrder="1 2"/>
</output>
I'm using xpath2's index-of value to return the index of current() within a sorted sequence of nodes. Using SAXON, the sorted sequence of nodes are unique, yet index-of returns a sequence of two values.
This does not happen all the time, just very occasionally, but not for any reason I can find. Can someone please explain what is going on?
I have worked up a minimal example based on an example of data that routines gives this odd behavior.
The source data is:
<data>
<student userID="1" userName="user1"/>
<session startedOn="01/16/2012 15:01:18">
</session>
<session startedOn="11/16/2011 13:31:33">
</session>
</data>
My xsl document puts the session nodes into a sorted sequence $orderd at the very top of the root template:
<xsl:template match="/">
<xsl:variable name="nodes" as="node()*" select="/data/session"></xsl:variable>
<xsl:variable name="orderd" as="node()*">
<xsl:for-each select="$nodes">
<xsl:sort select="xs:dateTime(xs:dateTime(concat(substring(normalize-space(@startedOn),7,4),'-',substring(normalize-space(@startedOn),1,2),'-',substring(normalize-space(@startedOn),4,2),'T',substring(normalize-space(@startedOn),12,8)))
)" order="ascending"/>
<xsl:sequence select="."/>
</xsl:for-each>
</xsl:variable>
Since the nodes were already ordered by @startOn but in the opposite order, the sequence $orderd should be the same as document-ordered sequence $nodes, except in reverse order.
When I create output using a for-each statement, I find that somehow the two nodes are seen as identical when tested using index-of.
The code below is used to output data (and comes immediately after the chunk above):
<output>
<xsl:for-each select="$nodes">
<xsl:sort select="position()" order="descending"></xsl:sort>
<xsl:variable name="index" select="index-of($orderd,current())" as="xs:integer*"></xsl:variable>
<xsl:variable name="pos" select="position()"></xsl:variable>
<session reverse-documentOrder="{$pos}" sortedOrder="{$index}"/>
</xsl:for-each>
</output>
As the output (shown below) indicates, the index-of function is returning the sequence (1,2), meaning that it sees both nodes as identical. I have checked the expression used to sort the values, and it produces distinct and well-formed date-Time strings.
<output>
<session reverse=documentOrder="1"
sortedOrder="1 2"/>
<session reverse-documentOrder="2"
sortedOrder="1 2"/>
</output>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不依赖于
generate-id()
函数(它是 XSLT 函数,而不是 XPath 函数),可以编写一个简单的index-of()
函数对节点标识进行操作:当此转换应用于以下 XML 文档时:
返回所需的正确结果:
解释 :使用
is
运算符。Not relying on the
generate-id()
function, which is XSLT function, but not XPath function, one can write a simpleindex-of()
function that operates on node identity:when this transformation is applied on the following XML document:
the wanted, correct result is returned:
Explanation: Use of the
is
operator.文档 http://www.w3.org/TR/xpath-
index-of
的functions/#func-index-of 表示“序列 $seqParam 中的项目根据 eq 运算符的规则与 $srchParam 进行比较。类型的值xs:untypedAtomic 的比较就像它们是 xs:string 类型一样。”。因此,您尝试比较非类型化元素节点,这意味着它们将作为字符串进行比较,并且两个session
元素具有相同的空格(仅字符串内容)。这样,两者就被视为相等。我不确定该建议什么,因为我不确定您想要实现什么,但我希望上述内容解释了您得到的结果。
The documentation http://www.w3.org/TR/xpath-functions/#func-index-of of
index-of
says "The items in the sequence $seqParam are compared with $srchParam under the rules for the eq operator. Values of type xs:untypedAtomic are compared as if they were of type xs:string.". So you are trying to compare untyped element nodes and that means they are compared as strings and bothsession
elements have the same white space only string contents. That way both are compared as equal.I am not sure what to suggest as I am not sure what you want to achieve but I hope the above explains the result you get.