5 votes

Comment utiliser la boucle for en xslt ?

Mode d'emploi xsl:for-each en xslt pour obtenir une valeur itérativement à partir d'un fichier xml et la distribuer dans une table à partir de ce fichier.

Par exemple, le fichier xml est le suivant

<order>
  <item name ="a"/>
  <item name ="b"/>  
  <item name ="c"/>
  <item name ="d"/>
  <item name ="e"/>
  <item name ="f"/>
  <item name ="g"/>
</order>

et la sortie devrait être

  a    b    c   d

  e    f    g

la boucle doit compter l'élément et si celui-ci est divisible par 4, elle

doit fermer la rangée actuelle et ajouter une nouvelle rangée, et ainsi de suite

J'utilise le xslt suivant pour cela

mais je ne peux pas l'afficher en format tableau

   <xsl:template match="/">
    <html>
    <body>
     <xsl:call-template name ="incr">
        <xsl:with-param name ="value">1</xsl:with-param>
        <xsl:with-param name ="limit">
          <xsl:value-of select ="count(//item)"/>
        </xsl:with-param>
      </xsl:call-template>
  </body>
</html>
</xsl:template >
<xsl:template name="incr">
  <xsl:param name="value"/>
  <xsl:param name ="limit"/>
  <xsl:if test ="$value!=$limit+1">
    <xsl:value-of select ="//item[$value]/@name"/>
    <xsl:if test ="$value mod 4 =0">
      <br/>
      <br/>
    </xsl:if>
    <xsl:call-template name ="incr">
      <xsl:with-param name ="value" select ="$value+1"/>
      <xsl:with-param name ="limit" select ="$limit"/>
    </xsl:call-template>
  </xsl:if>

</xsl:template>

S'il vous plaît, aidez-moi à le faire

Merci d'avance

8voto

Dimitre Novatchev Points 147842

Cette transformation :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vNumCols" select="4"/>

 <xsl:template match="/*">
  <table>
   <xsl:for-each select=
     "item[position() mod $vNumCols = 1]">

     <tr>
       <xsl:for-each select=
       ". | following-sibling::*
                 [not(position() >= $vNumCols)]">
        <td><xsl:value-of select="@name"/></td>
       </xsl:for-each>
     </tr>
   </xsl:for-each>
  </table>
 </xsl:template>
</xsl:stylesheet>

lorsqu'il est appliqué sur le document XML fourni, produit les résultats corrects souhaités :

<table>
   <tr>
      <td>a</td>
      <td>b</td>
      <td>c</td>
      <td>d</td>
   </tr>
   <tr>
      <td>e</td>
      <td>f</td>
      <td>g</td>
   </tr>
</table>

8voto

Robert Rossney Points 43767

La façon de penser aux problèmes de toute complexité en XSLT n'est pas "comment écrire un programme pour produire Y, avec X en entrée", mais plutôt "étant donné la sortie Y, quel X vais-je transformer pour la produire". Ce n'est pas un principe facile à saisir (ou à articuler), mais une fois que vous l'avez compris, ce qui semble être des problèmes difficiles en XSLT devient trivial.

Si la sortie est une série de tr éléments, comme ceci :

<tr>
   <td>a</td><td>b</td><td>c</td>
</tr>
<tr>
   <td>d</td><td>e</td><td>f</td>
</tr>
<tr>
   <td>g</td><td>h</td><td>i</td>
</tr>
<tr>
   <td>j</td><td/><td/>
</tr>

il y a, en fait, quatre éléments de sortie. Il doit donc y avoir quatre éléments d'entrée.

La première question est : quels sont les quatre ? Il est clair que ce seront les 1er, 4e, 7e et 10e éléments, c'est-à-dire les trois éléments, en commençant par le premier. Votre point de départ est donc de transformer ces quatre éléments :

<xsl:apply-templates select="/order/item[position() mod 3 = 1]"/>

Ok, et maintenant que nous avons sélectionné chaque troisième élément, comment allons-nous créer un tr et les éléments juste après ? En utilisant le following-sibling axe :

<xsl:template match="item">
   <tr>
      <td><xsl:value-of select="@name"/></td>
      <td><xsl:value-of select="following-sibling::item[1]/@name"/></td>
      <td><xsl:value-of select="following-sibling::item[2]/@name"/></td>
   </tr>
</xsl:template>

C'est bien, pour autant que ça aille. Mais il y a une bonne quantité de code dupliqué, et beaucoup de choses à modifier si vous voulez (disons) changer le nombre de colonnes de 3 à 6. Vous pouvez éliminer le code dupliqué en créant un autre modèle :

<xsl:template match="item">
   <tr>
      <xsl:apply-templates select="@name | following-sibling::item[position() &lt;= 3]/@name"/>
   </tr>
</xsl:template>

<xsl:template match="@name">
   <td><xsl:value-of select="."/></td>
</xsl:template>

Et vous pouvez paramétrer le nombre de colonnes en le mettant dans une variable, comme l'a fait Dimitre dans son exemple.

-1voto

Cagdas Points 401

Je ne suis pas sûr à 100% mais le code ci-dessous devrait le faire :

<table>
    <tr>
    <xsl:for-each select="//order/item">
        <td>
        <xsl:value-of select ="current()/@name"/>
        </td>
    <xsl:if test="position() mod 4 = 0">
    <xsl:text disable-output-escaping="yes"><![CDATA[</tr><tr>]]></xsl:text>
    </xsl:if>
    </xsl:for-each>
    <xsl:variable name="item_count_mod4" select="count(//order/item) mod 4"/>
    <xsl:choose>
      <xsl:when test="$item_count_mod4 = 1">
        <td></td><td></td><td></td>
      </xsl:when>
      <xsl:when test="$item_count_mod4 = 2">
        <td></td><td></td>
      </xsl:when>
      <xsl:when test="$item_count_mod4 = 3">
        <td></td>
      </xsl:when>
      <xsl:otherwise>
      </xsl:otherwise>
    </xsl:choose>
    </tr>
</table>

-4voto

Thorin Oakenshield Points 3418
<table> 
 <tr> 
  <xsl:for-each select="//order/item"> 
   <td> 
    <xsl:value-of select ="current()/@name"/> 
   </td> 
   <xsl:if test="position() mod 4 = 0"> 
    <xsl:text disable-output-escaping="yes"><![CDATA[</tr><tr>]]></xsl:text> 
   </xsl:if> 
  </xsl:for-each> 
 </tr> 
</table>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X