2010-06-08 23 views
1

I ont le code XML suivant (il est simplifié et la plupart des attributs sont omis):XSLT1.0 séquence de rendu de différents éléments stockés dans une variable tableau M x N

<Document> 
    <Transfer Name="" From="" To=""/> 
    <Transfer Name="" From="" To=""/> 
    <OtherElement/> 
    <OtherElement/> 
    <Flight AirLina="" From="" To=""/> 
    <Flight AirLina="" From="" To=""/> 
    <OtherElement/> 
    <Hotel Name="" Duration=""/> 
    <Hotel Name="" Duration=""/> 
    <OtherElement/> 
    <OtherElement/> 
    <Extras Name="" Price=""/> 
    <Extras Name="" Price=""/> 
    <Extras Name="" Price=""/> 
    <Extras Name="" Price=""/> 
    <Extras Name="" Price=""/> 
    <Extras Name="" Price=""/> 
    <OtherElement/> 
    <OtherElement/> 
</Document> 

j'ai une variable contenant différents éléments:

<xsl:variable name="packageElements" 
select="/Document/Transfer | /Document/Coach | /Document/Flight | /Document/Hotel | /Document/Extras" /> 

Je voudrais afficher ces données dans une table avec 2 colonnes. J'utilise le processeur XSLT1.0 et MSXSL.

J'ai essayer avec la solution la plus simple que je pouvais penser:

<table> 
    <tbody> 
    <xsl:for-each select="$packageElements[position() mod 2 = 1]"> 
     <tr> 
     <td> 
      <!-- current element --> 
      <xsl:value-of select="local-name()"/> 
     </td> 
     <td> 
      <!-- element following the current in the $packageElements variable --> 
      <!-- Here is where I'm stuck, I can't figure out how to correctly pick it up :(--> 
     </td> 
     </tr> 
    </xsl:for-each> 
    </tbody> 
</table> 

apprécierions vraiment aucune aide.

+0

Sans montrer votre XML, c'est difficile à dire. – Tomalak

+0

@Tomalak: désolé, ajout d'une structure de document XML simplifiée. J'espère que cela a du sens. – DashaLuna

+0

Bonne question (+1). Voir ma réponse pour une solution complète. :) –

Répondre

1

D'accord,

J'ai combiné idée des réponses de ce poste de @Dimitre Novatchev et @ Tomalak de ce poste [XSLT]: Rendering a node sequence as M x N table. J'ai vraiment aimé la solution @ Tomalak avec la variable $perRow et le modèle <xsl:template name="filler"> pour faire face aux cellules vides. Avec l'idée tirée de @Dimitre Novatchev réponse, je tiens à $trStartPos. Je calcule ensuite $lowerBoundry et $upperBoundry qui sont utilisés pour accumuler tous les éléments qui devraient apparaître dans une rangée. Il pourrait y avoir une façon plus élégante de faire ce calcul - s'il vous plaît laissez-moi savoir si vous venez avec un, je l'apprécierais vraiment!

XSLT Transformation

<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="*"/> 

<!-- Select only required elements --> 
<xsl:variable name="tableData" 
    select="/nums/A | /nums/B | /nums/C | /nums/D | /nums/E "/> 
<xsl:variable name="perRow" select="2"/> 

<xsl:template match="/"> 
    <table border="1"> 
     <tbody> 
      <xsl:apply-templates 
       select="$tableData[position() mod $perRow = 1]" mode="tr"/> 
     </tbody>    
    </table> 
</xsl:template> 


<xsl:template match="nums/*" mode="tr"> 
    <xsl:variable name="trStartPos" select="position()" /> 
    <xsl:variable name="upperBoundry" select="$trStartPos * $perRow" /> 
    <xsl:variable name="lowerBoundry" select="$upperBoundry - $perRow" /> 

    <tr> 
     <xsl:variable name="tdsData" 
      select="$tableData[(position() &gt; $lowerBoundry) and (position() &lt;= $upperBoundry)]" /> 
     <xsl:apply-templates select="$tdsData" mode="td"/> 
     <!-- fill up the last row - @Tomalak's solution --> 
     <xsl:if test="count($tdsData) &lt; $perRow"> 
      <xsl:call-template name="filler"> 
       <xsl:with-param name="rest" select="$perRow - count($tdsData)" /> 
      </xsl:call-template> 
     </xsl:if> 
    </tr> 
</xsl:template> 


<!-- Templates for specific elements could be easily added with appropriate info to 
    be displayed depending on the element. This one is general just to display 
    elements' name and value --> 
<xsl:template match="nums/*" mode="td"> 
    <td> 
     El. name: <xsl:value-of select="local-name()"/> - 
     El. value: <xsl:value-of select="."/> 
    </td> 
</xsl:template> 

<!-- @Tomalak solution (please read beginning of this answer for reference) --> 
<xsl:template name="filler"> 
    <xsl:param name="rest" select="0" /> 
    <xsl:if test="$rest"> 
     <td>&#160;</td> 
     <xsl:call-template name="filler"> 
      <xsl:with-param name="rest" select="$rest - 1" /> 
     </xsl:call-template> 
    </xsl:if> 
</xsl:template> 
</xsl:stylesheet> 

appliqué sur le code XML suivant

<nums> 
    <A>A-01</A> 
    <num>02</num> 
    <num>03</num> 
    <num>04</num> 
    <B>B-05</B> 
    <num>06</num> 
    <num>07</num> 
    <C>C-08</C> 
    <num>09</num> 
    <D>D-10</D> 
    <num>11</num> 
    <num>12</num> 
    <num>13</num> 
    <E>E-14</E> 
    <num>15</num> 
</nums> 

résultats dans la sortie suivante

<table border="1"> 
    <tbody> 
     <tr> 
      <td> 
       El. name: A - 
       El. value: A-01 
      </td> 
      <td> 
       El. name: B - 
       El. value: B-05 
      </td> 
     </tr> 
     <tr> 
      <td> 
       El. name: C - 
       El. value: C-08 
      </td> 
      <td> 
       El. name: D - 
       El. value: D-10 
      </td> 
     </tr> 
     <tr> 
      <td> 
       El. name: E - 
       El. value: E-14 
      </td> 
      <td> </td> 
     </tr> 
    </tbody> 
</table> 
1

Je pense que la complexité est ici:

élément suivant l'courant dans les packageElements variable $

C'est un nœud dans l'ensemble de nœuds $ packageElements avec une position() supérieur au nœud actuel. Mais, quelle est la position du nœud actuel dans $ packegeElements node-set?

Vérifiez this. Dimitre construit une expression qui est le nombre d'intersection entre les noeuds précédents (dans le document) du noeud courant et l'ensemble de noeuds.

1

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:strip-space elements="*"/> 

<xsl:variable name="vData" select="/*/*"/> 

<xsl:template match="/"> 
    <table border="1"> 
    <xsl:apply-templates select="$vData[position() mod 2 = 1]"/> 
    </table> 
</xsl:template> 

<xsl:template match="nums/*"> 
    <xsl:variable name="vPos" select="position()"/> 

    <tr> 
    <td><xsl:value-of select="name()"/></td> 
    <td><xsl:value-of select="$vData[position() = 2*$vPos]"/></td> 
    </tr> 
</xsl:template> 
</xsl:stylesheet> 

lorsqu'il est appliqué sur ce document XML:

<nums> 
    <A>01</A> 
    <num>02</num> 
    <B>03</B> 
    <num>04</num> 
    <C>05</C> 
    <num>06</num> 
    <D>07</D> 
    <num>08</num> 
    <E>09</E> 
    <num>010</num> 
</nums> 

produit le résultat souhaité, correct:

<table border="1"> 
    <tr> 
     <td>A</td> 
     <td>02</td> 
    </tr> 
    <tr> 
     <td>B</td> 
     <td>04</td> 
    </tr> 
    <tr> 
     <td>C</td> 
     <td>06</td> 
    </tr> 
    <tr> 
     <td>D</td> 
     <td>08</td> 
    </tr> 
    <tr> 
     <td>E</td> 
     <td>010</td> 
    </tr> 
</table> 
+0

Ceci ne gère pas (c'est-à-dire "ignorer") les nœuds '' qui ne sont pas souhaités dans la sortie. Il gère tous les nœuds '/ */*' comme contigus, mais en fait ils ne le sont pas. J'avoue que l'entrée XML est plutôt sous-optimale pour commencer ... – Tomalak

+0

Merci pour la réponse, c'était un coup d'envoi pour ma solution. @Tomalak: J'ai pensé que cette réponse ne tenait pas compte du fait que je voulais seulement que les éléments sélectionnés forment du XML original. J'ai utilisé votre solution pour le message "[XSLT]: Rendu d'une séquence de nœuds en tant que table M x N" sur http://stackoverflow.com/questions/2355952/xslt-rendering-a-node-sequence-as-mxn-table C'est très élégant, j'ai appris quelque chose de nouveau - merci beaucoup! – DashaLuna

+0

@Tomalak: Eh bien, que faire quand je ne comprends absolument pas (encore) son XML? C'est pourquoi j'ai fourni mon document XML - pour démontrer l'idée - elle peut probablement l'attraper et faire le reste elle-même ... –