XSLT How to do a classic for x to y loop?

时间秒杀一切 提交于 2019-12-11 01:53:27

问题


I need to do a classic for i=0 to N loop, how can it be done in xstl 1.0?

thanks.

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

To give an example, I have

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

And want an output of

Hey!
Hey!

回答1:


XSLT is a functional programming language and as such it is very different to any procedural languages you already know.

Although for loops are possible in XSLT, they do not make use of the inherent strengths of XSLT (and functional programming in general).

for loops are routinely misused to address problems that are best solved with a functional approach instead (that is, matching templates). In other words, a loop is not really a "classic" in XSLT.

So, you might have to double back, identify the problem you are facing instead of discussion your solution. Then, the XSLT community might be able to suggest a solution that is more functional in nature. It might be that you've fallen victim to the XY problem.


Now, among the things XSLT is inherently good at is recursion. Often, problems that are solved with loops in procedural languages are solved with recursive templates in 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>

To summarize, I suggest you look at "classic" recursion instead of "classic" for loops. You find more information about exactly this topic in an IBM article here.


EDIT as a response to your edited question. If your problem really boils down to outputting text content twice:

<?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>

This is not feasible of course for a dynamic number of iterations.




回答2:


Use a named template with parameters $i and $n; call the template with parameters {$i = 0, $N = 5}; have the template call itself recursively with parameters {$i + 1, $N} until $i > $N.

Example:

<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>



回答3:


XSLT 2.0 has <xsl:for-each select="0 to 5"> but in XSLT 1.0 you can only for-each over node sets, not sequences of atomic values. The easiest way I've found to get around this is to use some kind of sufficiently generic selector expression that will match at least as many nodes as you want iterations, e.g.

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

or if you don't necessarily know there will be at least 6 nodes in the input document then you can use document('') to treat the stylesheet itself as another input document.

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

In both cases the for-each will change the context node, so you'll need to save the outer context in a variable if you need to access it inside the for-each body

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


来源:https://stackoverflow.com/questions/21779239/xslt-how-to-do-a-classic-for-x-to-y-loop

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!