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

Cómo puedo agrupar mis elementos por el nombre del grupo en xslt 1.0. la salida:Agrupación de nodos xml por valor de un elemento secundario en 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> 

¿Alguna idea?

+0

por la manera en que su XML no es válido dar gracias primera – lweller

+0

Iweller :) –

+0

todavía no válida primera :) –

Respuesta

14

Este es un trabajo para Muenchian Grouping. Encontrará numerosos ejemplos dentro de la etiqueta XSLT aquí en StackOverflow.

En primer lugar, es necesario definir una clave para ayudarle a agrupar los grupos

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

Este buscará grupo elementos para un nombre de grupo dado.

A continuación, debe hacer coincidir todas las instancias de la primera instancia de cada nombre de grupo distintivo. Esto se hace con esta declaración miedo mirar

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

elementos del grupo del Partido es decir que resultan ser la primera aparición de ese elemento en la llave.

Cuando haya emparejado los nodos de grupo distinto, puede a continuación, recorrer todos los demás nodos de grupo con el mismo nombre (donde $ currentGroup es una variable que contiene el nombre del grupo actual)

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

Poner esto da por completo

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

Aplicando esto en su XML de ejemplo da el siguiente resultado

<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 Respuesta correcta. Pero el estilo es ... no estilo XSLT: debe agrupar 'element' por' name', y usar la regla de identidad 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

Estas plantillas generan un error en: match = "distinct-values ​​(group)" el ​​mensaje: final esperado de la expresión, found '('. Distinct-values ​​-> (<- group) –

+0

los valores distintivos() la función es parte de XPath 2 y no va a funcionar en un entorno XSLT 1.0 –

+0

lo siento @Nic Gibson tiene razón, la función distinct-values ​​() no está disponible en xslt 1.0. Intenté sugerir una variante que debería funcionar para xslt 1.0 – lweller

14

I. Aquí es una solución completa y muy corto XSLT 1.0:

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

cuando se aplica esta transformación en el documento XML proporcionado:

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

el, resultado correcto deseado se produce:

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

hacer la nota:

  1. El uso de la Muenchian method for grouping. Este es el método de agrupamiento más eficiente en XSLT 1.0.

  2. El uso de la AVT (Attribute Value Template) para especificar un elemento resultado literal y su variable - atributo de valor como un todo. El uso de AVT simplifica la codificación y produce un código más breve y comprensible.

II. Una solución XSLT 2.0 aún más corto:

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

cuando se aplica esta transformación en el mismo documento XML (arriba), el mismo resultado correcto se produce de nuevo.

hacer la nota:

.1. El uso de la instrucción <xsl:for-each-group> XSLT 2.0.

.2. El uso del estándar XSLT 2.0 Funciones current-group() y current-grouping-key()

+0

Thax Dimitre Novatchev :) –

+0

@Haroldis: De nada. ¿Tus "gracias" se traducen en un voto positivo y/o aceptación? :) –

+0

+1. Voto ascendente tarde por el bien de la equidad. – Flack

Cuestiones relacionadas