XSLT pour transformer une liste en table avec des colonnes déterminées dynamiquement

StackOverflow https://stackoverflow.com/questions/1634269

  •  06-07-2019
  •  | 
  •  

Question

J'ai besoin de ce XML,

<list columns="3">
  <item>martin</item>
  <item>donald</item>
  <item>whistler</item>
  <item>mother</item>
  <item>carl</item>
  <item>liz</item>
  <item>cosmo</item>
</list>

ressembler à ceci:

<table>
  <tr>
    <td>martin</td>
    <td>donald</td>
    <td>whistler</td>
  </tr>
  <tr>
    <td>mother</td>
    <td>carl</td>
    <td>liz</td>
  </tr>
  <tr>
    <td>cosmo</td>
    <td></td>
    <td></td>
  </tr>
</table>

Lorsque columns = "4" , il devrait ressembler à ceci:

<table>
  <tr>
    <td>martin</td>
    <td>donald</td>
    <td>whistler</td>
    <td>mother</td>
  </tr>
  <tr>
    <td>carl</td>
    <td>liz</td>
    <td>cosmo</td>
    <td></td>
  </tr>
</table>

Avez-vous des indications sur l'aspect du fichier XSLT? Quoique je sache, cela nécessite une sorte de boucle (récursivité?), Mais je ne suis pas sûr qu’il existe un moyen plus élégant.

Était-ce utile?

La solution

L’approche que j’adopterais consiste à faire correspondre les éléments des première, quatrième et septième positions en utilisant la fonction 'mod' de la position () sur chaque élément.

Après avoir mis en correspondance chacun de ces éléments, parcourez les frères et soeurs suivants en fonction du nombre de colonnes.

Pour la dernière ligne, où le nombre d'éléments peut être insuffisant, il existe un modèle récursif à ajouter dans les cellules vides en fonction du nombre d'éléments présents dans la dernière ligne.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

   <!-- Global variable to get column count -->
   <xsl:variable name="columns" select="number(/list/@columns)"/>

   <!-- Match the root node -->
   <xsl:template match="list">
      <table>
         <!-- Match items in the 1st, 4th, 7th positions, etc (or whatever the column variable holds) -->
         <xsl:apply-templates select="item[position() mod $columns = 1]"/>
      </table>
   </xsl:template>

   <xsl:template match="item">
      <tr>
         <!-- Output the current item -->
         <td>
            <xsl:value-of select="."/>
         </td>
         <!-- Output the following items based on the number of required columns -->
         <xsl:for-each select="following-sibling::item[position() &lt; $columns]">
            <td>
               <xsl:value-of select="."/>
            </td>
         </xsl:for-each>
         <!-- Add in any empty cells if numberof following items is not sufficient -->
         <xsl:call-template name="emptycell">
            <xsl:with-param name="cellcounter" select="count(following-sibling::item[position() &lt; $columns]) + 1" />
         </xsl:call-template>
      </tr>
   </xsl:template>

   <!-- Recursive template to add in empty cells when there are not enough items to complete a row -->
   <xsl:template name="emptycell">
      <xsl:param name="cellcounter" />
      <xsl:if test="$cellcounter &lt; $columns">
         <td></td>
         <xsl:call-template name="emptycell">
            <xsl:with-param name="cellcounter" select="$cellcounter + 1" />
         </xsl:call-template>
      </xsl:if>   
   </xsl:template>

</xsl:stylesheet>

Autres conseils

Quelque chose qui fonctionne mais qui semble un peu moche: position abusive ().

<xsl:param name="columns">4</xsl:param>
<xsl:template match="list">
  <xsl:variable name="theList" select="."/>
  <xsl:for-each select="//*[position()<(count(item) / $columns)]>
    <xsl:variable name="idx" select="position()"/>
    <tr>
    <xsl:for-each select="//*[position()<$columns]">
       <td><xsl:value-of select="$theList/item[position() + $idx * $columns]"/></td>
    </xsl:for-each>
    </tr>
  </xsl:for-each>
</xsl:template>

Il existe d'autres moyens: par exemple, sélectionnez d'abord tous les nœuds qui se divisent avec le reste 0 par les colonnes de la liste, puis passez au-dessus de ceux-ci.

Voir http://www.ibm.com/developerworks/library/ x-tipnodst.html pour une description plus détaillée de la technique ci-dessus.

Je suggère d'utiliser les colonnes CSS3 . La spécification deviendra bientôt une recommandation candidate (étape d’appel pour les implémentations) et est déjà implémentée dans Gecko et WebKit (Firefox, Safari, Chrome), avec des préfixes de fournisseur.

Code:

ul { -moz-column-count: 3; -webkit-column-count: 3; }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top