2010-09-27 8 views
13

Ich muss insgesamt 20 Elemente mit XSLT füllen. In meinem XML-Code habe ich eine <select> mit den Werten, gibt es sowieso keine 20 Formulare zu schreiben?Wie kann ich eine Aktion X-mal mit XSLT wiederholen

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

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

gewünschte Ausgabe:

<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

Gute Frage (+1). Siehe meine Antwort für eine bestimmte XSLT 1.0-Lösung und eine andere generische XSLT 2.0-Lösung. –

Antwort

9

Zuerst Vorlagen verwenden statt for-each, dann können Sie eine rekursive Template-Aufruf um eine for-Schleife zu emulieren (wie gesehen 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

Eine Möglichkeit, dies zu lösen, ist durch die Optionseinstellungen in eine Variable Laden der XPath document() Funktion und anschließend eine rekursive Vorlage:

<?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 Lösung:

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

Dies ist eine spezifische rekursive Lösung.

Wenn auf das folgende XML-Dokument angewandt:

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

das gewünschte, wird richtiges Ergebnis erzeugt.

II. XSLT 2.0-Lösung, die f:repeat() Funktion von FXSL mit:

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

Hier verwenden wir eine sehr generische Funktion, die ihr erstes Argument N (den Wert seines zweiten Arguments) mal wiederholt.

Die Funktion f:repeat() selbst ist sehr einfach:

<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

Andere Lösung mit "you-wird-go-to-hell-if-you-use-dieses-Muster":

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