XSLT - 在嵌套for-each中找到position()

时间:2014-07-15 13:01:36

标签: xml xslt foreach position xslt-2.0

我正在使用XSLT对一些相当复杂的XML执行转换。为了实现我需要的输出,我必须创建一个嵌套的for循环,如下所示:

源XML

<root>
  <element1>
    <child>
      <aaa></aaa>
      <bbb></bbb>
    </child>
  </element1>
  <element2/>
  <element3/>
  <element3/>
  <element3/>
</root>

XSLT

<xsl:for-each select="element3">
  <!-- Do some stuff -->

  <xsl:for-each select="../element1/child/*">
    <!-- Do some more stuff -->
  </xsl:for-each>
</xsl:for-each>

问题

我在这里尝试做的是在我的嵌套循环中(在../element1/child/*上) - 我想知道:

  1. 我正在循环的元素的位置 - 例如,如果我当前专注于<bbb>那么这个位置(我认为)将是'1'
  2. 父循环的位置(在element3上) - 所以,例如,如果我在<element3>的第三个实例上然后循环../element1/child/*并专注于{ {1}} - 我将追求的两个值是'2'和'0'。
  3. 理想情况下,我希望能够将这些值分配给变量。我尝试使用如下所示的<aaa>符号,但这似乎不起作用。

    position()

    如果有人对如何实现这一点有任何想法,将不胜感激!我正在使用XSLT 2.0,但如果需要,我可以使用XSLT 1.0开放解决方案。提前谢谢。

3 个答案:

答案 0 :(得分:7)

您应该尝试将输入修改为:

<root>
  <element1>
    <child>
      <aaa>1a</aaa>
      <bbb>2a</bbb>
    </child>
  </element1>
  <element2/>
  <element3>3a</element3>
  <element3>3b</element3>
  <element3>3c</element3>
</root>

然后看看你得到了什么:

<xsl:template match="/">
    <test>
        <xsl:for-each select="root/element3">
        <xsl:variable name="parent-position" select="position()" />
        <xsl:variable name="parent-value" select="." />
            <xsl:for-each select="../element1/child/*">
                <item value="{.}" parent-value="{$parent-value}" parent-position="{$parent-position}" position="{position()}"/>
            </xsl:for-each>
        </xsl:for-each>    
    </test>
</xsl:template>

答案 1 :(得分:0)

我已经为您的输入添加了一些id属性,因此您可以看到哪个节点正在处理,因此我的输入如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <element1 id="e1-1">
        <child>
            <aaa id="e1-a"></aaa>
            <bbb id="e1-b"></bbb>
        </child>
    </element1>
    <element2 id="e2-1"/>
    <element3 id="e3-1"/>
    <element3 id="e3-2"/>
    <element3 id="e3-3"/>
</root>

此样式表执行我认为您尝试执行的操作 - 它处理每个element3并处理每个../element1/child/*的所有element3个节点:

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

    <xsl:output indent="yes"/>
    <xsl:template match="root">
        <tests>
            <xsl:apply-templates select="element3"/>
        </tests>
    </xsl:template>

    <xsl:template match="element3">
        <xsl:apply-templates select="../element1/child/*">
            <xsl:with-param name="parent-pos" select="position() - 1"/>
            <xsl:with-param name="parent-id" select="@id"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="element1/child/*">
        <xsl:param name="parent-pos"/>
        <xsl:param name="parent-id"/>
        <xsl:variable name="current-pos" select="position()"/>

        <test parent-id="{$parent-id}" current-id="{@id}" parent-pos="{$parent-pos}" current-pos="{$current-pos}"/>

    </xsl:template>

</xsl:stylesheet>

结果是:

<tests>
   <test parent-id="e3-1" current-id="e1-a" parent-pos="0" current-pos="1"/>
   <test parent-id="e3-1" current-id="e1-b" parent-pos="0" current-pos="2"/>
   <test parent-id="e3-2" current-id="e1-a" parent-pos="1" current-pos="1"/>
   <test parent-id="e3-2" current-id="e1-b" parent-pos="1" current-pos="2"/>
   <test parent-id="e3-3" current-id="e1-a" parent-pos="2" current-pos="1"/>
   <test parent-id="e3-3" current-id="e1-b" parent-pos="2" current-pos="2"/>
</tests>

希望有所帮助

答案 2 :(得分:0)

您可以在内部使用添加的@position属性重建节点,并在重建树上循环。对于这个exsl:node-set(或其他专有衍生物)是必需的。

获取原始的source.xml(不变!)和此XSLT脚本:


<xsl:template match="/*">

<xsl:variable name="CopiedTree">
  <xsl:call-template name="copy-with-position"/>
</xsl:variable>

<xsl:for-each select="exsl:node-set($CopiedTree)//element3">
  <xsl:element name="E3">
    <xsl:comment>Do some stuff</xsl:comment>
    <xsl:variable name="E3pos" select="@position()" />

    <xsl:for-each select="../element1/child/*">
      <xsl:element name="E1C">
        <xsl:attribute name="name"><xsl:value-of select="name()" /></xsl:attribute>
        <xsl:attribute name="positions"><xsl:value-of select="concat($E3pos, ' - ', @position)" /></xsl:attribute>
        <xsl:comment>Do some more stuff</xsl:comment>
      </xsl:element>
      
    </xsl:for-each>
  </xsl:element>
</xsl:for-each>

</xsl:template>





    
<xsl:template name="copy-with-position">

  <xsl:element name="{name()}">
    <xsl:copy-of select="(@*)" />
    <xsl:attribute name="position"><xsl:value-of select="position()" /></xsl:attribute>
    <xsl:for-each select="./*">
      <xsl:call-template name="copy-with-position">
        <xsl:with-param name="position" select="position()" />
      </xsl:call-template>
    </xsl:for-each>
  </xsl:element>

</xsl:template>

输出为:

<?xml version="1.0" encoding="UTF-8"?>
<E3>
  <!--Do some stuff-->
  <E1C name="aaa" positions="3 - 1">
    <!--Do some more stuff-->
  </E1C>
  <E1C name="bbb" positions="3 - 2">
    <!--Do some more stuff-->
  </E1C>
</E3>
<E3>
  <!--Do some stuff-->
  <E1C name="aaa" positions="4 - 1">
    <!--Do some more stuff-->
  </E1C>
  <E1C name="bbb" positions="4 - 2">
    <!--Do some more stuff-->
  </E1C>
</E3>
<E3>
  <!--Do some stuff-->
  <E1C name="aaa" positions="5 - 1">
    <!--Do some more stuff-->
  </E1C>
  <E1C name="bbb" positions="5 - 2">
    <!--Do some more stuff-->
  </E1C>
</E3>