XSLT如何为x到y循环做经典之作?

时间:2014-02-14 12:18:43

标签: xslt xslt-1.0

我需要为i = 0到N循环做一个经典,怎么能在xstl 1.0中完成?

感谢。

<xsl:for-each select="¿¿¿$i=0..5???">
    <fo:block>
        <xsl:value-of select="$i"/>
    </fo:block>
</xsl:for-each>

举个例子,我有

<foo>
    <bar>Hey!</bar>
</foo>

想要输出

Hey!
Hey!

3 个答案:

答案 0 :(得分:6)

XSLT是一种功能性编程语言,因此它与您已经知道的任何过程语言非常不同。

尽管在XSLT中可能存在for循环,但它们并没有利用XSLT(以及通常的函数式编程)的固有优势。

for循环经常被误用来解决用函数方法最好解决的问题(即匹配模板)。换句话说,循环在XSLT中并不是真正的“经典”。

因此,您可能需要加倍,找出您面临的问题,而不是讨论您的解决方案。然后,XSLT社区可能会建议一个更具功能性的解决方案。可能是你已成为XY problem的受害者。


现在,XSLT本质上是的东西是递归。通常,使用XSLT中的递归模板解决过程语言中的循环解决的问题。

<xsl:template name="recursive-template">
   <xsl:param name="var" select="5"/>
   <xsl:choose>
     <xsl:when test="$var > 0">
       <xsl:value-of select="$var"/>
       <xsl:call-template name="recursive-template">
         <xsl:with-param name="var" select="$var - 1"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise/>
   </xsl:choose>
</xsl:template>

总结一下,我建议你看看“经典”递归而不是“经典”for循环。您可以在IBM文章here中找到有关此主题的更多信息。


编辑作为对您编辑过的问题的回复。如果您的问题真的归结为输出文本内容两次:

<?xml version="1.0" encoding="utf-8"?>

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

   <xsl:output method="text"/>

   <xsl:template match="/foo">
      <xsl:apply-templates select="bar"/>
      <xsl:apply-templates select="bar"/>
   </xsl:template>

</xsl:stylesheet>

当然,对于动态的迭代次数,这是不可行的。

答案 1 :(得分:2)

使用带参数$ i和$ n的命名模板;使用参数{$ i = 0,$ N = 5}调用模板;使用参数{$ i + 1,$ N}以递归方式调用模板,直到$ i&gt; $ N

示例:

<xsl:template match="/">
<output>
    <!-- stuff before -->
    <xsl:call-template name="block-generator">
        <xsl:with-param name="N" select="5"/>
    </xsl:call-template>
    <!-- stuff after -->
</output>
</xsl:template>

<xsl:template name="block-generator">
    <xsl:param name="N"/>
    <xsl:param name="i" select="0"/>
    <xsl:if test="$N >= $i">
        <!-- generate a block -->
        <fo:block>
            <xsl:value-of select="$i"/>
        </fo:block>     
        <!-- recursive call -->
        <xsl:call-template name="block-generator">
            <xsl:with-param name="N" select="$N"/>
            <xsl:with-param name="i" select="$i + 1"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

答案 2 :(得分:1)

XSLT 2.0具有<xsl:for-each select="0 to 5">但在XSLT 1.0中,您只能for-each超过节点集,而不是原子值序列。我发现解决这个问题的最简单方法是使用某种足够通用的选择器表达式,它至少匹配你想要迭代的节点,例如。

<xsl:for-each select="/descendant::node()[position() &lt; 7]">
    <fo:block>
        <xsl:value-of select="position() - 1"/>
    </fo:block>
</xsl:for-each>

或者如果您不一定知道输入文档中至少有6个节点,那么您可以使用document('')将样式表本身视为另一个输入文档。

<xsl:for-each select="document('')/descendant::node()[position() &lt; 7]">

在这两种情况下,for-each都会更改上下文节点,因此如果您需要在for-each正文中访问它,则需要将外部上下文保存在变量中

<xsl:variable name="dot" select="." />