所选节点的索引不基于其父节点

时间:2014-03-12 17:51:58

标签: xslt xpath

我有一个像这样的xml:

<?xml version="1.0" encoding="WINDOWS-1252" ?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<root>
    <something>
       <cd>a1</cd>
       <cd>a2</cd>
    </something>
    <another>
       <cd>b1</cd>
       <cd>b2</cd>
       <cd>b3</cd>
       <cd>b1</cd>
       <cd>b2</cd>
       <cd>b3</cd>
       <cd>b1</cd>
       <cd>b2</cd>       
    </another>
</root>

我正在选择所有的CD节点,并尝试以这种方式从10到10(第1,第11,第21 ......)获取cds:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="/">
       <html><body>
            <xsl:apply-templates select="//cd" />
       </body></html>
    </xsl:template>

    <xsl:template match="cd"/>

    <xsl:template match="cd[position() mod 10 = 1]">
        <div>
            pos:<xsl:value-of select="position()"/>;
            value:<xsl:value-of select="."/>
        </div>
    </xsl:template>

</xsl:stylesheet>

输出:

 pos:1; value:a1
pos:3; value:b3

预期的产出:

pos:1; value:a1
pos:11; value:b11

问题是匹配中的position() 是基于其父级的节点号。所以“{1}”的“b1”是1而不是3.是否有函数知道当前节点的索引?

提前致谢。

//编辑以扩展示例

3 个答案:

答案 0 :(得分:2)

模板过滤器“cd”的匹配中的position()基于其父级中的位置:

<xsl:template match="cd[position() mod (10) = 1]">

和模板定义中的position()

<div>pos:<xsl:value-of select="position()"/></div>

为您提供已申请模板的cd序列。

因此,“position()mod(10)= 1”只过滤那些父母的第1个,第11个,第21个等孩子的“cd”。

因此,您可以从xsl:template的匹配中删除过滤器并将其放入内部,如下所示:

<xsl:template match="cd">
    <div>pos:<xsl:if test="position() mod 10 = 1">
            <xsl:value-of select="position()"/>
        </xsl:if>
    </div>
</xsl:template>

答案 1 :(得分:2)

使用xsl:number

可以获得更准确的计数
<xsl:template match="cd">
    <div>pos: <xsl:number level="any"/></div>
</xsl:template>

您还可以计算前面的cd元素:

<xsl:template match="cd">
    <div>pos: <xsl:value-of select="count(preceding::cd)+1"/></div>
</xsl:template>

我更喜欢xsl:number,但我认为这取决于您使用该值的方式。如果你举一个更好的例子说明你想用这个号码做什么,我可以更新我的答案。

基于问题更新的示例:

<强>输入

<root>
    <something>
        <cd>a1</cd>
        <cd>a2</cd>
    </something>
    <another>
        <cd>b1</cd>
        <cd>b2</cd>
        <cd>b3</cd>
        <cd>b1</cd>
        <cd>b2</cd>
        <cd>b3</cd>
        <cd>b1</cd>
        <cd>b2</cd>       
    </another>
    <another>
        <cd>c1</cd>
        <cd>c2</cd>
        <cd>c3</cd>
        <cd>c1</cd>
        <cd>c2</cd>
        <cd>c3</cd>
        <cd>c1</cd>
        <cd>c2</cd>       
    </another>
</root>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="/">
        <html><body>
            <xsl:apply-templates select="//cd" />
        </body></html>
    </xsl:template>

    <xsl:template match="cd"/>

    <xsl:template match="cd[(count(preceding::cd)+1) mod 10 = 1]">
        <div>
            pos:<xsl:value-of select="position()"/>;
            value:<xsl:value-of select="."/>
        </div>
    </xsl:template>

</xsl:stylesheet>

<强>输出

<html>
   <body>
      <div>
         pos:1;
         value:a1
      </div>
      <div>
         pos:11;
         value:c1
      </div>
   </body>
</html>

答案 2 :(得分:1)

这将保存变量中的所有CD。在for-each中,上下文不依赖于父节点,因此您将获得所有CD中的位置:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:variable name="all-cds" select="//cd" />
    <xsl:template match="root">
        <xsl:for-each select="$all-cds">
            <div>pos: <xsl:value-of select="position()"/></div>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>