2011-01-17 13 views
14
<root> 
<element> 
<id>1</id> 
<group>first</group> 
</element> 

<element> 
<id>2</id> 
<group>second</group> 
</element> 


<element> 
<id>3</id> 
<group>first</group> 
</element> 
... 
<root> 

Come posso raggruppare i miei elementi in base al nome del gruppo in xslt 1.0. l'output:Raggruppamento di nodi xml in base al valore di un figlio in Xsl

<root> 
<group name="first"> 
<element> 
    <id>1</id> 
    <group>first</group> 
</element> 
<element> 
    <id>3</id> 
    <group>first</group> 
</element> 
</group> 
<group name="second"> 
<element> 
    <id>2</id> 
    <group>second</group> 
    </element> 
</group> 
</root> 

Qualche idea?

+0

da parte del modo in cui il XML non è valido thanx primo – lweller

+0

Iweller :) –

+0

ancora valida primo :) –

risposta

14

Questo è un lavoro per il gruppo di Muenchian. Ne troverai numerosi esempi all'interno del tag XSLT qui su StackOverflow.

In primo luogo, è necessario definire una chiave per aiutare a raggruppare i gruppi

<xsl:key name="groups" match="group" use="."/> 

Questo cercherà gruppo elementi per un determinato nome del gruppo.

Successivamente, è necessario abbinare tutte le occorrenze della prima istanza di ciascun nome di gruppo distinto. Questo viene fatto con questa affermazione spaventoso guardare

<xsl:apply-templates select="element/group[generate-id() = generate-id(key('groups', .)[1])]"/> 

elementi del gruppo cioè Partita che capita di essere la prima occorrenza di tale elemento nella nostra chiave.

Dopo aver abbinato i nodi gruppo distinto, è possibile scorrere tutti gli altri nodi del gruppo con lo stesso nome (dove $ currentGroup è una variabile che tiene il nome del gruppo corrente)

<xsl:for-each select="key('groups', $currentGroup)"> 

Mettendo questo dà tutto

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

    <xsl:key name="groups" match="group" use="."/> 

    <xsl:template match="/root"> 
     <root> 
     <xsl:apply-templates select="element/group[generate-id() = generate-id(key('groups', .)[1])]"/> 
     </root> 
    </xsl:template> 

    <xsl:template match="group"> 
     <xsl:variable name="currentGroup" select="."/> 
     <group> 
     <xsl:attribute name="name"> 
      <xsl:value-of select="$currentGroup"/> 
     </xsl:attribute> 
     <xsl:for-each select="key('groups', $currentGroup)"> 
      <element> 
       <id> 
        <xsl:value-of select="../id"/> 
       </id> 
       <name> 
        <xsl:value-of select="$currentGroup"/> 
       </name> 
      </element> 
     </xsl:for-each> 
     </group> 
    </xsl:template> 

</xsl:stylesheet> 

l'applicazione di questo sul tuo XML di esempio ha pronunciato la seguente risultato

<root> 
    <group name="first"> 
     <element> 
     <id>1</id> 
     <name>first</name> 
     </element> 
     <element> 
     <id>3</id> 
     <name>first</name> 
     </element> 
    </group> 
    <group name="seccond"> 
     <element> 
     <id>2</id> 
     <name>seccond</name> 
     </element> 
    </group> 
</root> 
+1

+1 Risposta corretta, ma lo stile è ... non stile XSLT: dovresti raggruppare 'element' di' name', e usare la regola di identità o 'xsl: copy-of'. –

2
<xsl:template match="group[not(.=preceding::group)]"> 
    <xsl:variable name="current-group" select="." /> 
    <xsl:for-each select="//root/element[group=$current-group]"> 
    <group> 
     <id><xsl:value-of select="id"/></id> 
    </group> 
    </xsl:for-each> 
</xsl:template> 
+0

Questi template generano errori in: match = "valori distinti (gruppo)" il messaggio: Fine prevista dell'espressione, trovato "(". Distinct-values ​​-> (<- group) –

+0

i valori distinti() la funzione fa parte di XPath 2 e non funzionerà in un ambiente XSLT 1.0 –

+0

sorry @Nic Gibson ha ragione, la funzione distinct-values ​​() non è disponibile in xslt 1.0. Ho provato a suggerire una variante che dovrebbe funzionare per xslt 1.0 – lweller

14

I. Ecco un completo e molto breve XSLT 1.0 soluzione:

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


<xsl:key name="kElsByGroup" match="element" use="group"/> 

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

<xsl:template match= 
    "element[generate-id()=generate-id(key('kElsByGroup',group)[1])]"> 

    <group name="{group}"> 
    <xsl:copy-of select="key('kElsByGroup',group)"/> 
    </group> 
</xsl:template> 

<xsl:template match= 
    "element[not(generate-id()=generate-id(key('kElsByGroup',group)[1]))]"/> 

</xsl:stylesheet> 

quando tale trasformazione viene applicato sul documento XML fornito:

<root> 
    <element> 
     <id>1</id> 
     <group>first</group> 
    </element> 
    <element> 
     <id>2</id> 
     <group>second</group> 
    </element> 
    <element> 
     <id>3</id> 
     <group>first</group> 
    </element> 
</root> 

The Wanted, risultato corretto è prodotto:

<root> 
    <group name="first"><element> 
     <id>1</id> 
     <group>first</group> 
    </element><element> 
     <id>3</id> 
     <group>first</group> 
    </element></group> 
    <group name="second"><element> 
     <id>2</id> 
     <group>second</group> 
    </element></group> 
</root> 

Do atto:

  1. L'uso del Muenchian method for grouping. Questo è il metodo di raggruppamento più efficiente in XSLT 1.0.

  2. L'uso di AVT (Attribute Value Template) per specificare un elemento risultato letterale e il variabile - attributo valore come un tutto. L'utilizzo di AVT semplifica la codifica e produce codice più breve e più comprensibile.

II. Una soluzione ancora più breve XSLT 2.0:

<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="/*"> 
    <root> 
     <xsl:for-each-group select="element" group-by="group"> 
     <group name="{current-grouping-key()}"> 
     <xsl:copy-of select="current-group()"/> 
     </group> 
     </xsl:for-each-group> 
    </root> 
</xsl:template> 
</xsl:stylesheet> 

quando questa trasformazione viene applicata sullo stesso documento XML (sopra), lo stesso risultato corretto viene nuovamente prodotta.

Do atto:

.1. L'uso dell'istruzione <xsl:for-each-group> XSLT 2.0.

.2. L'uso del XSLT 2.0 standard funzioni current-group() e current-grouping-key()

+0

Thax Dimitre Novatchev :) –

+0

@Haroldis: prego. I tuoi "ringraziamenti" si traducono in un upvote e/o accettazione? :) –

+0

+1. Voto tardivo per motivi di equità. – Flack

Problemi correlati