2009-02-03 10 views
5

J'ai un XML simple avec deux niveaux (en-tête et ligne) de balises telles que: lignesXSLT Groupement

<?xml version="1.0"?> 
<Header> 
    <line>Line 1</line> 
    <line>Line 2</line> 
    <line>Line 3</line> 
    <line>Line 4</line> 
    <line>Line 5</line> 
    <line>Line 6</line> 
    <line>Line 7</line> 
    <line>Line 8</line> 
    <line>Line 9</line> 
</Header> 

J'ai besoin de regrouper les lignes sur des ensembles de X (X = 3 par exemple) pour que ma sortie est la suivante:

<?xml version="1.0"?> 
<Header> 
    <set> 
     <line>Line 1</line> 
     <line>Line 2</line> 
     <line>Line 3</line> 
    </set> 
    <set> 
     <line>Line 4</line> 
     <line>Line 5</line> 
     <line>Line 6</line> 
    </set> 
    <set> 
     <line>Line 7</line> 
     <line>Line 8</line> 
     <line>Line 9</line> 
    </set> 
</Header> 

Comment puis-je écrire un XSLT qui peut faire ce genre de transformation?

Merci!

O

+0

@otavio Vous utilisez probablement un buggy, un processeur XSLT non conforme, ou, plus probablement, a changé le document XML source ou changé le code. - Dimitre Novatchev (0 secondes il y a) –

Répondre

4

La transformation suivante produit le résultat requis:

<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="vN" select="3"/> 

    <xsl:template match="/*"> 
    <xsl:copy> 
     <xsl:apply-templates 
      select="line[position() mod $vN = 1]"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="line"> 
    <set> 
     <xsl:apply-templates mode="copy" select= 
     ". 
     | 
     following-sibling::line[position() &lt; $vN]"/> 
    </set> 
    </xsl:template> 

    <xsl:template match="line" mode="copy"> 
     <xsl:copy-of select="."/> 
    </xsl:template> 
</xsl:stylesheet> 

Lorsqu'il est appliqué sur le document XML fourni:

<Header> 
    <line>Line 1</line> 
    <line>Line 2</line> 
    <line>Line 3</line> 
    <line>Line 4</line> 
    <line>Line 5</line> 
    <line>Line 6</line> 
    <line>Line 7</line> 
    <line>Line 8</line> 
    <line>Line 9</line> 
</Header> 

le résultat est:

<Header> 
    <set> 
    <line>Line 1</line> 
    <line>Line 2</line> 
    <line>Line 3</line> 
    </set> 
    <set> 
    <line>Line 4</line> 
    <line>Line 5</line> 
    <line>Line 6</line> 
    </set> 
    <set> 
    <line>Line 7</line> 
    <line>Line 8</line> 
    <line>Line 9</line> 
    </set> 
</Header> 

Prenez note de ce qui suit:

  1. L'utilisation du XPath mod opérateur pour trouver le premier élément line dans chaque groupe de vN éléments.

  2. L'utilisation des modes, afin de pouvoir traiter différents éléments line par différents modèles

+0

il a travaillé après avoir changé à Otavio

+0

Vous avez raison Dimitre! J'ai juste trouvé mon erreur et mis en application le même concept dans mon vrai problème et cela semble fonctionner correctement. Merci encore! (Je vais supprimer le commentaire précédent) – Otavio

1

En général XSLT si vous voulez créer une liste à partir d'une hiérarchie, vous pouvez utiliser des preceding-sibling et les mots clés following-sibling. Ceci est simpliste s'il y a une entrée de marqueur entre les ensembles.

Comme vous n'avez pas de marqueur en tant que tel dans ce cas j'imagine qu'une solution pourrait impliquer le mot-clé suivant-sibling et l'opérateur mod. Le mod fournissant la division entre les ensembles.

Je ne l'ai pas essayé mais ce serait mon premier départ.

xslt est normalement un bon point de départ pour comprendre les différents mots-clés.

0

Cela devrait être possible. A la sortie désirée:

<?xml version='1.0' encoding='UTF-8'?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       version="1.0"> 

    <xsl:template match="/Header"> 
    <Header> 
     <xsl:for-each select="line"> 
     <xsl:if test="not(number()=0) and position() mod 3 = 0"> 
      <set> 
      <xsl:variable name="pos" select="position()"/> 
      <line><xsl:value-of select="../line[position()=($pos -2)]"/></line> 
      <line><xsl:value-of select="../line[position()=($pos -1)]"/></line> 
      <line><xsl:value-of select="text()"/></line> 
      </set> 
     </xsl:if> 

     </xsl:for-each> 
    </Header> 
    </xsl:template> 

</xsl:stylesheet> 

(La chose est pas très joli pos-2 pos-1 $, $)

1

http://www.xml.com/pub/a/2003/11/05/tr.html montre d'une manière un peu moins laid de le faire en utilisant XSLT 2.0.L'élément clé est celui-ci:

<xsl:for-each-group select="*" group-ending-with="*[position() mod 3 = 0]">