How I can repeat an action X times with XSLT

前端 未结 5 1545
囚心锁ツ
囚心锁ツ 2021-02-04 07:47

I\'ve to populate a total of 20 elements with XSLT. In my XML code I have a

提交评论

  • 2021-02-04 08:18

    One way to solve this is by loading the option settings into a variable using the XPath document() function and then using a recursive template:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
      <xsl:variable name="options" select="document('options.xml')" />
    
      <xsl:template match="/">
        <html>
          <body>
            <xsl:call-template name="InsertOptions">
              <xsl:with-param name="count" select="20" />
            </xsl:call-template>
          </body>
        </html>
      </xsl:template>
    
      <xsl:template name="InsertOptions">
        <xsl:param name="index" select="1"/>
        <xsl:param name="count" select="1"/>
    
        <xsl:if test="$index &lt;= $count">
          <select name="{concat('values', count, '[]')}">
            <option value="0"> </option>
            <xsl:for-each select="$options/output/select">
              <option value="{id}"><xsl:value-of select="name" /></option>
            </xsl:for-each>
          </select>
          <xsl:call-template name="InsertOptions">
            <xsl:with-param name="index" select="$index + 1" />
            <xsl:with-param name="count" select="$count" />
          </xsl:call-template>
        </xsl:if>
      </xsl:template>
    </xsl:stylesheet>
    
    0 讨论(0)
  • 2021-02-04 08:21

    Other solution with "you-will-go-to-hell-if-you-use-this-pattern":

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:template match="/">
            <xsl:variable name="vChilds" select="node()"/>
            <xsl:variable name="vStylesheet" select="document('')"/>
            <html>
                <body>
                    <xsl:for-each select="($vStylesheet//node()|
                                           $vStylesheet//@*|
                                           $vStylesheet//namespace::*)
                                           [21 > position()]">
                        <xsl:apply-templates select="$vChilds"/>
                    </xsl:for-each>
                </body>
            </html>
        </xsl:template>
        <xsl:template match="output">
            <select name="values[]">
                <option value="0"></option>
                <xsl:apply-templates/>
            </select>
        </xsl:template>
        <xsl:template match="select">
            <option value="{id}">
                <xsl:value-of select="name"/>
            </option>
        </xsl:template>
    </xsl:stylesheet>
    
    0 讨论(0)
  • 2021-02-04 08:24

    First, use templates instead of for-each, then you can use a recursive template call to emulate a for loop (as seen here):

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">   
        <xsl:template match="/">
            <html>
            <body>
    
                <xsl:call-template name="selects">
                   <xsl:with-param name="i">1</xsl:with-param>
                   <xsl:with-param name="count">20</xsl:with-param>
                </xsl:call-template> 
    
            </body>    
            </html>
        </xsl:template>
    
        <xsl:template name="selects">
            <xsl:param name="i" />
            <xsl:param name="count" />
    
            <xsl:if test="$i &lt;= $count">
              <select name="values[]">
                <xsl:apply-template select="output/select" />
              </select>
            </xsl:if>
    
            <!--begin_: RepeatTheLoopUntilFinished-->
            <xsl:if test="$i &lt;= $count">
                <xsl:call-template name="selects">
                    <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:template match="output/select">
          <option>
            <xsl:attribute name="value">
                <xsl:value-of select="id">
            </xsl:attribute>
            <xsl:value-of select="name" />
          </option>
        </xsl:template>
    </xsl:stylesheet>
    
    0 讨论(0)
  • 2021-02-04 08:24

    I. XSLT 1.0 solution:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:template match="/">
      <html>
        <body>
          <xsl:apply-templates select="*" mode="iter">
           <xsl:with-param name="pCount" select="20"/>
          </xsl:apply-templates>
        </body>
      </html>
     </xsl:template>
    
     <xsl:template match="/*" mode="iter">
      <xsl:param name="pCount" select="0"/>
    
      <xsl:if test="$pCount > 0">
          <select name="values[]">
          <xsl:apply-templates/>
          </select>
        <xsl:apply-templates select="." mode="iter">
          <xsl:with-param name="pCount" select="$pCount -1"/>
        </xsl:apply-templates>
      </xsl:if>
     </xsl:template>
    
     <xsl:template match="select">
      <option value="{id}"><xsl:value-of select="name"/></option>
     </xsl:template>
    </xsl:stylesheet>
    

    This is a specific, recursive solution.

    When applied to the following XML document:

    <output>
        <select>
            <id>0</id>
            <name> </name>
        </select>
        <select>
            <id>1</id>
            <name>One</name>
        </select>
        <select>
            <id>2</id>
            <name>Two</name>
        </select>
        <select>
            <id>3</id>
            <name>Three</name>
        </select>
    </output>
    

    the wanted, correct result is produced.

    II. XSLT 2.0 solution using the f:repeat() function of FXSL:

    <xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     xmlns:f="http://fxsl.sf.net/"
     exclude-result-prefixes="f xs"
     >
     <xsl:import href="../f/func-repeat.xsl"/>
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:variable name="vSelects" as="element()">
       <select name="values[]">
        <xsl:apply-templates select="/*/select"/>
       </select>
     </xsl:variable>
    
      <xsl:template match="/">
        <html>
          <body>
           <xsl:sequence select="f:repeat($vSelects, 20)"/>
          </body>
        </html>
      </xsl:template>
    
     <xsl:template match="select">
      <option value="{id}"><xsl:value-of select="name"/></option>
     </xsl:template>
    </xsl:stylesheet>
    

    Here we use a very generic function that will repeat its first argument N (the value of its second argument) times.

    The function f:repeat() itself is very simple:

    <xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     xmlns:f="http://fxsl.sf.net/"
     exclude-result-prefixes="xs f"
    >
    
      <xsl:function name="f:repeat" as="item()+">
        <xsl:param name="pThis" as="item()"/>
        <xsl:param name="pTimes" as="xs:integer"/>
    
        <xsl:for-each select="1 to $pTimes">
          <xsl:sequence select="$pThis"/>
        </xsl:for-each>
      </xsl:function>
    </xsl:stylesheet>
    
    0 讨论(0)
  • 提交回复
    热议问题