2010-09-27 47 views
13

Tengo que completar un total de 20 elementos con XSLT. En mi código XML tengo un <select> con los valores, de todos modos hay que no escribir 20 formularios?Cómo puedo repetir una acción X veces con XSLT

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

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

salida deseada:

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

Buena pregunta (+1). Vea mi respuesta para una solución XSLT 1.0 específica y otra solución genérica XSLT 2.0. –

Respuesta

9

En primer lugar, el uso de plantillas en lugar de for-each, entonces se puede utilizar una llamada plantilla recursiva para emular un bucle for (como se ve 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> 
1

Una manera de resolver esto es mediante la carga de los valores de las opciones en una variable utilizando la función XPath document() y después usando una plantilla recursiva: solución

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

I. 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: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> 

Esta es una solución recursiva específica.

Cuando se aplica a la siguiente documento XML:

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

el resultado deseado, adecuados, se produce.

II. XSLT solución 2,0 mediante la función de f:repeat() de 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> 

Aquí se utiliza una función muy genérico que se repetirá su primer argumento N (el valor de su segundo argumento) veces.

La función f:repeat() sí es muy 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> 
3

Otra solución con "te-te-ir-a-infierno-si-usted-uso-este-patrón":

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