XSLT:从1到60循环

时间:2012-01-31 08:12:06

标签: xslt

在XSLT中从1到60循环的最佳方法是什么? 我在网上研究,有一些模板可以做到这一点,有没有其他方式,例如内置函数?

5 个答案:

答案 0 :(得分:45)

在XSLT 2.0中,

<xsl:for-each select="1 to 60">...</xsl:for-each>

但我猜你必须使用XSLT 1.0,否则你不会问。

在XSLT 1.0中,您应该使用递归:一个模板,它使用在每次调用时递增的计数器调用自身,并且在达到所需值时递归终止。

或者XSLT 1.0中有一种解决方法:如果你的源文档包含至少60个节点,你可以这样做

<xsl:for-each select="(//node())[60 >= position()]">...</xsl:for-each>

答案 1 :(得分:24)

处理长序列时简单递归的问题是,调用堆栈的空间通常不足,并且由于堆栈溢出而导致处理结束。这通常发生在序列长度> = 1000。

避免这种情况的一般技术(可以用任何XSLT处理器实现,即使它不能识别尾递归)是DVC(分而治之)样式递归

以下是成功打印1至1000000(1M)数字的转换示例:

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

     <xsl:template match="/">
      <xsl:call-template name="displayNumbers">
        <xsl:with-param name="pStart" select="1"/>
        <xsl:with-param name="pEnd" select="1000000"/>
      </xsl:call-template>
     </xsl:template>

     <xsl:template name="displayNumbers">
      <xsl:param name="pStart"/>
      <xsl:param name="pEnd"/>

      <xsl:if test="not($pStart > $pEnd)">
       <xsl:choose>
        <xsl:when test="$pStart = $pEnd">
          <xsl:value-of select="$pStart"/>
          <xsl:text>&#xA;</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:variable name="vMid" select=
           "floor(($pStart + $pEnd) div 2)"/>
          <xsl:call-template name="displayNumbers">
           <xsl:with-param name="pStart" select="$pStart"/>
           <xsl:with-param name="pEnd" select="$vMid"/>
          </xsl:call-template>
          <xsl:call-template name="displayNumbers">
           <xsl:with-param name="pStart" select="$vMid+1"/>
           <xsl:with-param name="pEnd" select="$pEnd"/>
          </xsl:call-template>
        </xsl:otherwise>
       </xsl:choose>
      </xsl:if>
     </xsl:template>
</xsl:stylesheet>

当应用于任何XML文档(未使用)时,此转换会生成所需结果 - 所有数字从1到1000000。

您可以对任何需要“做N次”的任务使用/调整此转换。

答案 2 :(得分:3)

在foreach循环中进行非常简单的检查

<xsl:if test="$maxItems > position()">
    do something
</xsl:if>

基于Dimitre Novatchev's回答。

示例:

<xsl:variable name="maxItems" select="10" />
<xsl:variable name="sequence" select="any-sequence"/>

<xsl:for-each select="$sequence">

    <!-- Maybe sort first -->
    <xsl:sort select="@sort-by" order="descending" />

    <!-- where the magic happens -->
    <xsl:if test="$maxItems > position()">
        do something
    </xsl:if>
</xsl:for-each>

答案 3 :(得分:0)

XSLT基于模板工作,你需要一个模板来运行该循环。

您需要构建一个接收开始值和结束值的模板,并在其中使用start + 1进行递归调用计算。当$ start等于$ end时,您将返回模板,而无需另外调用。

在实践中:http://www.ibm.com/developerworks/xml/library/x-tiploop/index.html

答案 4 :(得分:0)

使用递归的V1.0的基本示例如下:

<xsl:template match="/">
<Root>
      <!-- Main Call to MyTemplate -->
     <xsl:call-template name="MyTemplate" />
</Root>
</xsl:template>

<xsl:template name="MyTemplate">
  <xsl:param name="index" select="1" />
  <xsl:param name="maxValue" select="60" />

  <MyCodeHere>
     <xsl:value-of select="$index"/>
  </MyCodeHere>

  <!-- &lt; represents "<" for html entities -->
  <xsl:if test="$index &lt; $maxValue">
    <xsl:call-template name="MyTemplate">
        <xsl:with-param name="index" select="$index + 1" />
        <xsl:with-param name="total" select="$maxValue" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>