Xslt XSL:cicling的问题

Xslt XSL:cicling的问题,xslt,Xslt,我知道作为一种函数式语言,XSL不像传统的for循环(而是for each) 我试图创建一个固定数量(7)的表,从可变数量的元素开始。一句话,我有 <items> <item /> <item /> <item /> </item> 我怎样才能把它变成 <table> <tr><item /></tr> <tr><item /

我知道作为一种函数式语言,XSL不像传统的for循环(而是for each)

我试图创建一个固定数量(7)的表,从可变数量的元素开始。一句话,我有

<items>
    <item />
    <item />
    <item />
</item>

我怎样才能把它变成

<table>
    <tr><item /></tr>
    <tr><item /></tr>
    <tr><item /></tr>
    <tr></tr>
    <tr></tr>
    <tr></tr>
    <tr></tr>
</table>

??使用
count()
可以很容易地计算出我还需要4个空的,但是如何做到这一点呢?使用for循环,我可以很容易地解决这个问题,或者修改
向其中添加4个空元素,但是,作为xsl的新手,我甚至不能这样做


谢谢

您正在寻找递归解决方案。解决方案包括编写一个模板,当传入的计数小于需要该模板运行的次数时,该模板会调用自身

IBM发布了一个很好的示例,网址为:

您的代码可能看起来像:

<xsl:template name="itemLoop">

  <xsl:param name="count" select="0"/>

  <xsl:if test="$count &lt; 7">
    <tr><xsl:apply-templates select="/items/item[$count]"/></tr>
    <xsl:call-template name="itemLoop">
      <xsl:with-param name="count" select="$count + 1"/>
    </xsl:call-template>
  </xsl:if>

</xsl:template>

您应该在此处查看此问题:


这里也讨论了同样的问题(标题没有提到这一点),关于如何解决这个问题,有很多很好的答案。

下面是一个示例表,它可以满足您的需要。我使用
count
计算出有多少项,然后需要创建多少空行。我使用for_循环模板

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

    <xsl:template match="/">
        <table>
            <xsl:for-each select="//items/item">
                <tr><item/></tr>
            </xsl:for-each>

            <xsl:variable name="itemCount" as="xs:integer" select="count(//items/item)" />
            <xsl:call-template name="for_loop">
                <xsl:with-param name="i">
                    <xsl:value-of select="0" />
                </xsl:with-param>
                <xsl:with-param name="count">
                    <xsl:value-of select="7-$itemCount" />
                </xsl:with-param>
            </xsl:call-template>

        </table>
    </xsl:template>

    <xsl:template name="for_loop">
        <xsl:param name="i" />
        <xsl:param name="count" />
        <xsl:if test="$i &lt; $count">
            <tr></tr>
        </xsl:if>
        <xsl:if test="$i &lt; $count">
            <xsl:call-template name="for_loop">
                <xsl:with-param name="i">
                    <xsl:value-of select="$i + 1" />
                </xsl:with-param>
                <xsl:with-param name="count">
                    <xsl:value-of select="$count" />
                </xsl:with-param>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

如果可能,最好总是避免递归

在XSLT 2.0中,只需编写:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:param name="pNumRows" select="7"/>
    <xsl:variable name="vDoc" select="/"/>

 <xsl:template match="items">
     <table>
       <xsl:for-each select="1 to $pNumRows">
        <tr><xsl:copy-of select="$vDoc/items/item[current()]"/></tr>
       </xsl:for-each>
     </table>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的XML文档时:

<items>
    <item />
    <item />
    <item />
</items>
<table>
   <tr>
      <item/>
   </tr>
   <tr>
      <item/>
   </tr>
   <tr>
      <item/>
   </tr>
   <tr/>
   <tr/>
   <tr/>
   <tr/>
</table>

生成所需的正确结果:

<items>
    <item />
    <item />
    <item />
</items>
<table>
   <tr>
      <item/>
   </tr>
   <tr>
      <item/>
   </tr>
   <tr>
      <item/>
   </tr>
   <tr/>
   <tr/>
   <tr/>
   <tr/>
</table>

很少有人知道,在很多情况下,XSLT 1.0中也可以避免递归:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:param name="pNumRows" select="7"/>
 <xsl:param name="vDoc" select="/"/>


 <xsl:template match="items">
     <table>
       <xsl:for-each select=
             "(document('')//node())[not(position() > $pNumRows)]">
         <xsl:variable name="vPos" select="position()"/>

         <tr><xsl:copy-of select="$vDoc/items/item[position()=$vPos]"/></tr>
       </xsl:for-each>
   </table>
 </xsl:template>
</xsl:stylesheet>

这被称为Piez方法,人们可以了解它


记住:递归比简单迭代慢得多——如果列表有相当长的长度(大约1000或更多),并且没有采取特殊的编程措施,它也会因堆栈溢出而崩溃。

好问题,+1。请参阅我的答案,了解解决问题的两种不同的非递归方法。正如我在回答中所解释的,非递归解决方案应该优先于递归解决方案