2011-01-17 18 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> 

W jaki sposób mogę pogrupować moje elementy według nazwy grupy w xslt 1.0. wyjście:Grupowanie węzłów XML według wartości elementu podrzędnego w 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> 

Jakieś pomysły?

+0

przy okazji swoją xml nie jest ważna thanx pierwszy – lweller

+0

Iweller :) –

+0

jeszcze nieważny pierwszy :) –

Odpowiedz

14

To jest praca dla grupy Muenchian. Będziesz mieć wiele przykładów tego w tagu XSLT tutaj na StackOverflow.

Po pierwsze, trzeba zdefiniować klucz, aby pomóc Ci GRUPY grupy

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

Pozwoli to spojrzeć grupie elementy dla danej nazwy grupy.

Następnie należy dopasować wszystkie wystąpienia pierwszego wystąpienia nazwy każdej grupy odnowienia. Odbywa się to z tym przerażającym patrząc rachunku

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

grupowych tj Mecz elementy, które stało się pierwsze wystąpienie tego elementu w naszym kluczem.

Po dopasowane odrębnych węzłów grupowych, można następnie pętli wszystkich innych węzłów grupowych o tej samej nazwie (gdzie $ currentGroup jest zmienna posiadających aktualną nazwę grupy)

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

Wyrażając to w sumie daje

<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> 

Stosując ten na próbki XML daje następujący wynik

<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 Prawidłowa odpowiedź, ale styl jest ... nie stylem XSLT: powinieneś zgrupować 'element' według' name', a następnie użyć reguły tożsamości lub '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

Szablon ten generuje błąd w: match = "distinct-values ​​(group)" komunikat: Oczekiwany koniec wyrażenia, znaleziony "(" różne wartości -> (<- grupa) –

+0

różne wartości() Funkcja jest częścią XPath 2 i nie będzie działać w środowisku XSLT 1.0 –

+0

sorry @Nic Gibson ma rację, funkcja distinct-values ​​() nie jest dostępna w xslt 1.0. Próbowałem zasugerować wariant, który powinien działać for xslt 1.0 – lweller

14

I. Powyżej znajduje się pełna i bardzo krótki XSLT 1.0 rozwiązanie:

<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> 

kiedy ta transformacja jest stosowane na dostarczonym dokumencie XML:

<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> 

poszukiwany, poprawny wynik jest produkowane:

<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> 

Należy pamiętać:

  1. The wykorzystanie Muenchian method for grouping. Jest to najbardziej wydajna metoda grupowania w XSLT 1.0.

  2. Zastosowanie AVT (Attribute Value Template) określenie dosłowne elementu wynik i jego zmienna - wartość atrybutu jako jedną całość. Korzystanie z AVT upraszcza kodowanie i zapewnia krótszy i bardziej zrozumiały kod.

II. Jeszcze krótsza XSLT 2.0 rozwiązanie:

<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> 

kiedy ta transformacja jest stosowane na tym samym dokumencie XML (powyżej), ten sam wynik jest poprawny znowu produkowane.

Należy pamiętać:

.1. Korzystanie z instrukcji XSLT 2.0.

.2. Zastosowanie standardowego XSLT 2.0 Funkcje current-group() i current-grouping-key()

+0

Thax Dimitre Novatchev :) –

+0

@Haroldis: Nie ma za co. Czy twoje "podziękowania" przekładają się na przegłosowanie i/lub akceptację? :) –

+0

+1. Późne przegłosowanie na rzecz sprawiedliwości. – Flack

Powiązane problemy