Xslt XSL:cicling的问题
我知道作为一种函数式语言,XSL不像传统的for循环(而是for each) 我试图创建一个固定数量(7)的表,从可变数量的元素开始。一句话,我有Xslt XSL:cicling的问题,xslt,Xslt,我知道作为一种函数式语言,XSL不像传统的for循环(而是for each) 我试图创建一个固定数量(7)的表,从可变数量的元素开始。一句话,我有 <items> <item /> <item /> <item /> </item> 我怎样才能把它变成 <table> <tr><item /></tr> <tr><item /
<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 < 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 < $count">
<tr></tr>
</xsl:if>
<xsl:if test="$i < $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。请参阅我的答案,了解解决问题的两种不同的非递归方法。正如我在回答中所解释的,非递归解决方案应该优先于递归解决方案