XSLT循环在XML范围内

时间:2014-11-28 10:36:49

标签: loops xslt

假设我有以下xml文件:

<root>
    <header>
        <headernodes1/>
        <headernodes2/>
    </header>
    <items>
        <itemno>1</itemno>
        <itemtext>first item</itemtext>
        <loop>
            <range>
                <rangefrom>4711</rangefrom>
                <rangeto>4713</rangeto>
            </range>
            <content>content in the first loop</content>
        </loop>
        <loop>
            <range>
                <rangefrom>4715</rangefrom>
                <rangeto>4718</rangeto>
            </range>
            <content>content in the second loop</content>
        </loop>
    </items>
    <footernodes/>
</root>

<item>之前的<loop>中的页眉,页脚和节点应该被复制。

如果未显示<rangeto>,则只需复制<loop>段。否则,如果确实出现,则复制<loop>段,如下例所示:

<loop>
    <range>
        <rangefrom>4711</rangefrom>
    </range>
    <content>content in the first loop</content>
</loop>
<loop>
    <range>
        <rangefrom>4712</rangefrom>
    </range>
    <content>content in the first loop</content>
</loop>
<loop>
    <range>
        <rangefrom>4713</rangefrom>
    </range>
    <content>content in the first loop</content>
</loop>
<loop>
    <range>
        <rangefrom>4715</rangefrom>
    </range>
    <content>content in the second loop</content>
</loop>
<loop>
    <range>
        <rangefrom>4716</rangefrom>
    </range>
    <content>content in the second loop</content>
</loop>
<loop>
    <range>
        <rangefrom>4717</rangefrom>
    </range>
    <content>content in the second loop</content>
</loop>
<loop>
    <range>
        <rangefrom>4718</rangefrom>
    </range>
    <content>content in the second loop</content>
</loop>

XSLT 1.0中是否有解决方案?

非常感谢你的帮助和帮助。咨询。

来自德国的问候, →

2 个答案:

答案 0 :(得分:0)

XSLT没有循环,因为它没有可写变量(即不能有循环计数器)。

但它还有别的东西:递归!

<!-- process <loop> without <rangeto> directly as single item -->
<xsl:template match="loop[range/rangefrom and not(range/rangeto)]">
  <xsl:apply-templates select="." mode="single" />
</xsl:template>

<!-- process <loop> with <rangefrom>/<rangeto> as a succession of single items -->
<xsl:template match="loop[range/rangefrom &lt;= range/rangeto]">
  <xsl:param name="i" select="range/rangefrom" />

  <xsl:apply-templates select="." mode="single">
    <xsl:with-param name="i" select="$i" />
  </xsl:apply-templates>

  <xsl:if test="$i &lt; range/rangeto">
    <!-- recursive step: same node, incremented index -->
    <xsl:apply-templates select=".">
      <xsl:with-param name="i" select="$i + 1" />
    </xsl:apply-templates>
  </xsl:if>
</xsl:template>

<!-- single item: outputs its index as <rangefrom> --> 
<xsl:template match="loop" mode="single">
  <xsl:param name="i" select="range/rangefrom" />

  <xsl:copy>
    <range>
      <rangefrom><xsl:value-of select="$i" /></rangefrom>
    </range>
    <xsl:copy-of select="content" />
  </xsl:copy>
</xsl:template>

现代XSLT引擎将此识别为尾递归并将其优化为迭代,因此您不会看到长循环的“递归太深”错误。

答案 1 :(得分:0)

试试以下

  <xsl:template match="/root">
    <good>
      <header>
        <xsl:apply-templates select="header"/>
      </header>
      <footernodes>
        <xsl:apply-templates select="footernodes"/>
      </footernodes>
      <xsl:for-each select="items/loop">
        <xsl:if test="range/rangeto!=''">
          <xsl:call-template name="range">
            <xsl:with-param  name="rangedata" select="range"/>
            <xsl:with-param  name="contentdata" select="content"/>
            <xsl:with-param  name="vardata" select="range/rangefrom"/>
          </xsl:call-template>
        </xsl:if>
      </xsl:for-each>
    </good>
  </xsl:template>
  <xsl:template match="header">
    <xsl:copy-of select="."/>
  </xsl:template>
  <xsl:template match="footernodes">
    <xsl:copy-of select="."/>
  </xsl:template>
  <xsl:template name="range">
    <xsl:param name="rangedata"/>
    <xsl:param name="contentdata"/>
    <xsl:param name="vardata"/>
    <xsl:if test="$vardata &lt;=$rangedata/rangeto">
      <loop>
        <range>
          <rangefrom>
            <xsl:value-of select="$vardata"/>
          </rangefrom>
          <content>
            <xsl:value-of select="$contentdata"/>
          </content>
        </range>
      </loop>
      <xsl:call-template name="range">
        <xsl:with-param  name="rangedata" select="$rangedata"/>
        <xsl:with-param  name="contentdata" select="$contentdata"/>
        <xsl:with-param  name="vardata" select="$vardata+1"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

你可以使用递归来实现你想要的东西