2011-07-22 8 views
3

je xml qui contient quelques documents:groupement positionnel utilisant XSLT

<document> 
    <line id="0"> 
     <field id="0"><![CDATA[H:doc1]]></field> 
    </line> 
    <line id="1"> 
     <field id="0"><![CDATA[L:1]]></field> 
    </line> 
    <line id="2"> 
     <field id="0"><![CDATA[L:2]]></field> 
    </line> 
    <line id="3"> 
     <field id="0"><![CDATA[L:3]]></field> 
    </line> 
    <line id="4"> 
     <field id="0"><![CDATA[H:doc2]]></field> 
    </line> 
    <line id="5"> 
     <field id="0"><![CDATA[L:1]]></field> 
    </line> 
</document> 

H = en-tête du document et L = élément de ligne. dans cet exemple, nous avons deux H qui signifient deux documents qui sont doc1 et doc2. doc1 comporte trois éléments de ligne et doc2 un élément de ligne.

comment convertir les données en utilisant la version xslt 1 pour obtenir ce résultat:

<documents> 
    <document> 
     <header> 
      <number>doc1</number> 
     </header> 
     <line-item> 
      <line-number>1</line-number> 
      <line-number>2</line-number> 
      <line-number>3</line-number> 
     </line-item> 
    </document> 
    <document> 
     <header> 
      <number>doc2</number> 
     </header> 
     <line-item> 
      <line-number>1</line-number> 
     </line-item> 
    </document> 
</documents> 
+1

Eh bien, qu'avez-vous essayé? Où avez-vous des problèmes? –

+0

Bonne question, +1. Voir ma réponse pour une solution XSLT 1.0 complète, courte et facile à l'aide de clés. :) –

+0

Également ajouté une solution XSLT 2.0 plus courte en utilisant '' –

Répondre

5

Cette XSLT 1.0 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:key name="kFollowing" 
    match="line[starts-with(field,'L:')]" 
    use="generate-id(preceding-sibling::line 
         [starts-with(field,'H:')] 
         [1] 
        )"/> 

<xsl:template match="/"> 
    <documents> 
     <xsl:apply-templates/> 
    </documents> 
</xsl:template> 

<xsl:template match="line[starts-with(field,'H:')]"> 
    <document> 
    <header> 
    <number><xsl:value-of select="substring-after(field,'H:')"/></number> 
    <line-item> 
    <xsl:apply-templates mode="inGroup" select= 
     "key('kFollowing', generate-id())"/> 
    </line-item> 
    </header> 
    </document> 
</xsl:template> 

<xsl:template match="line" mode="inGroup"> 
    <line-number> 
    <xsl:value-of select="substring-after(field,'L:')"/> 
    </line-number> 
</xsl:template> 
<xsl:template match="text()"/> 
</xsl:stylesheet> 

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

<document> 
    <line id="0"> 
     <field id="0"><![CDATA[H:doc1]]></field> 
    </line> 
    <line id="1"> 
     <field id="0"><![CDATA[L:1]]></field> 
    </line> 
    <line id="2"> 
     <field id="0"><![CDATA[L:2]]></field> 
    </line> 
    <line id="3"> 
     <field id="0"><![CDATA[L:3]]></field> 
    </line> 
    <line id="4"> 
     <field id="0"><![CDATA[H:doc2]]></field> 
    </line> 
    <line id="5"> 
     <field id="0"><![CDATA[L:1]]></field> 
    </line> 
</document> 

produit le résultat souhaité, correct:

<documents> 
    <document> 
     <header> 
     <number>doc1</number> 
     <line-item> 
      <line-number>1</line-number> 
      <line-number>2</line-number> 
      <line-number>3</line-number> 
     </line-item> 
     </header> 
    </document> 
    <document> 
     <header> 
     <number>doc2</number> 
     <line-item> 
      <line-number>1</line-number> 
     </line-item> 
     </header> 
    </document> 
</documents> 

Explication: Utiliser les touches pour sélectionner facilement et sélectionnez le groupe complet de lignes adjacentes « » après une « tête ».

+0

Merci pour la réponse. – Petras

+0

@Petras: Vous êtes les bienvenus - vous pouvez également être intéressé par ma deuxième réponse qui fournit une solution XSLT 2.0 plus courte. –

3

Voici également une solution XSLT 2.0, en utilisant <xsl:for-each-group starting-with="...">

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

<xsl:template match="/*"> 
    <documents> 
     <xsl:for-each-group select="*" 
      group-starting-with="line[starts-with(field,'H:')]"> 
      <document> 
      <header> 
      <number><xsl:value-of select="substring-after(field,'H:')"/></number> 
      <line-item> 
      <xsl:apply-templates select="current-group()[position() >1]"/> 
      </line-item> 
      </header> 
      </document> 
     </xsl:for-each-group> 
    </documents> 
</xsl:template> 

<xsl:template match="line"> 
    <line-number> 
    <xsl:value-of select="substring-after(field,'L:')"/> 
    </line-number> 
</xsl:template> 
</xsl:stylesheet> 

lorsqu'il est appliqué au document XML fourni:

<document> 
    <line id="0"> 
     <field id="0"><![CDATA[H:doc1]]></field> 
    </line> 
    <line id="1"> 
     <field id="0"><![CDATA[L:1]]></field> 
    </line> 
    <line id="2"> 
     <field id="0"><![CDATA[L:2]]></field> 
    </line> 
    <line id="3"> 
     <field id="0"><![CDATA[L:3]]></field> 
    </line> 
    <line id="4"> 
     <field id="0"><![CDATA[H:doc2]]></field> 
    </line> 
    <line id="5"> 
     <field id="0"><![CDATA[L:1]]></field> 
    </line> 
</document> 

le résultat recherché, correcte est produite:

<documents> 
    <document> 
     <header> 
     <number>doc1</number> 
     <line-item> 
      <line-number>1</line-number> 
      <line-number>2</line-number> 
      <line-number>3</line-number> 
     </line-item> 
     </header> 
    </document> 
    <document> 
     <header> 
     <number>doc2</number> 
     <line-item> 
      <line-number>1</line-number> 
     </line-item> 
     </header> 
    </document> 
</documents> 

Explication: <xsl:for-each-group>, son attribut group-starting-with, la fonction current-group().