我正在使用xpath2的index-of value来返回已排序的节点序列中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>
当输出(如下所示)指示时,函数索引返回序列(1,2),这意味着它将两个节点视为相同。我检查了用于对值进行排序的表达式,它生成了明确且格式正确的日期时间字符串。
<output>
<session reverse=documentOrder="1"
sortedOrder="1 2"/>
<session reverse-documentOrder="2"
sortedOrder="1 2"/>
</output>
答案 0 :(得分:2)
不依赖于generate-id()
函数,即XSLT函数,而不依赖于XPath函数,可以编写一个简单的index-of()
函数来运行节点标识:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vNum3" select="/*/*[3]"/>
<xsl:variable name="vSeq" select="/*/*[1], /*/*[3], /*/*[3]"/>
<xsl:template match="/">
<xsl:sequence select="my:index-of($vSeq, $vNum3)"/>
</xsl:template>
<xsl:function name="my:index-of" as="xs:integer*">
<xsl:param name="pSeq" as="node()*"/>
<xsl:param name="pNode" as="node()"/>
<xsl:for-each select="$pSeq">
<xsl:if test=". is $pNode">
<xsl:sequence select="position()"/>
</xsl:if>
</xsl:for-each>
</xsl:function>
</xsl:stylesheet>
将此转换应用于以下XML文档:
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
返回想要的正确结果:
2 3
解释:使用is
运算符。
答案 1 :(得分:0)
index-of
的文档http://www.w3.org/TR/xpath-functions/#func-index-of说“序列$ seqParam中的项目与eq运算符的规则下的$ srchParam进行比较.xs:untypedAtomic类型的值被比较,好像它们是类型为xs:string。“因此,您尝试比较无类型的元素节点,这意味着它们将被比较为字符串,并且两个session
元素仅具有相同的空格字符串内容。这样两者的比较都是平等的。
我不知道该建议什么,因为我不确定你想要达到什么目的但我希望上面解释你得到的结果。