Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How I can repeat an action X times with XSLT

Tags:

forms

xml

xslt

I've to populate a total of 20 elements with XSLT. In my XML code I have a <select> with the values, there is anyway to not to write 20 forms?

My XML:

<output>
    <select>
        <id>1</id>
        <name>One</name>
    </select>
    <select>
        <id>2</id>
        <name>Two</name>
    </select>
    <select>
        <id>3</id>
        <name>Three</name>
    </select>
    <!-- An more -->
</output>

My XSLT:

<?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>
        <select name="values[]">
            <option value="0"> </option>
            <xsl:for-each select="output/select">
                <option>
                    <xsl:attribute name="value"><xsl:value-of select="id"></xsl:attribute>
                    <xsl:value-of select="name" />
                </option>
            </xsl:for-each>
        </select>
            </body>

        </html>
    </xsl:template>
</xsl:stylesheet>

Desired output:

<html>
    <body>

        <select name="values[]">
            <option value="0"> </option>
            <option value="1">One</option>
            <option value="2">Two</option>
            <option value="3">Three</option>
        </select>
        <!-- But 20 times -->   

    </body>
</html>
like image 934
ipalaus Avatar asked Sep 27 '10 08:09

ipalaus


People also ask

How to do loop in XSLT?

You can format your XSLT stylesheet to go to a specific node, and then loop through the given node set. You create an XSLT loop with the <xsl:for-each> tag. The value of the select attribute in this tag is an XPath expression that allows you to specify the data element to loop through.

Which element allows you to do looping in XSLT?

The <xsl:for-each> element allows you to do looping in XSLT.


2 Answers

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>
like image 200
Oded Avatar answered Oct 18 '22 05:10

Oded


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>
like image 34
Dimitre Novatchev Avatar answered Oct 18 '22 03:10

Dimitre Novatchev