2011-01-24 14 views
5

Me gustaría ordenar un archivo XML con una transformación XSL.Ordenando XML en XSLT basado en una lista de valores

<root> 
    <element> 
     <name>A</name> 
    </element> 
    <element> 
     <name>B</name> 
    </element> 
    <element> 
     <name>C</name> 
    </element> 
</root> 

, que deben seleccionarse por la siguiente lista de nombres: C, A, B, de manera que el XML resultante es:

<root> 
     <element> 
      <name>C</name> 
     </element> 
     <element> 
      <name>A</name> 
     </element> 
     <element> 
      <name>B</name> 
     </element> 
    </root> 

Obviamente, la lista de valores a ser una especie de debe ser muy dinámica (parámetro del XSLT, otro archivo XML ...). ¿Alguna idea de cómo hacer eso en el XSLT?

Gracias, Christophe

+0

Buena pregunta, 1. Vea mi respuesta para una solución completa y breve, más explicaciones exhaustivas. –

Respuesta

8

Esta transformación:

<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:param name="pSortingValues" select="'C,A,B'"/> 
<xsl:variable name="vSortingValues" select= 
    "concat(',', $pSortingValues, ',')"/> 

    <xsl:template match="node()|@*"> 
     <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="/*"> 
     <xsl:copy> 
     <xsl:apply-templates select="@*"/> 
     <xsl:apply-templates select="*"> 
     <xsl:sort data-type="number" select= 
     "string-length(substring-before($vSortingValues,concat(',',name,',')))"/> 
     </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

cuando se aplica en el documento XML proporcionado:

<root> 
    <element> 
     <name>A</name> 
    </element> 
    <element> 
     <name>B</name> 
    </element> 
    <element> 
     <name>C</name> 
    </element> 
</root> 

produce los resultados deseados, corregir:

<root> 
    <element> 
     <name>C</name> 
    </element> 
    <element> 
     <name>A</name> 
    </element> 
    <element> 
     <name>B</name> 
    </element> 
</root> 

hacer la nota:

  1. La lista de valores ordenados deseado es el parámetro global pSortingValues, que puede ser proporcionada externamente a la transformación.

  2. La regla de identidad se utiliza para copiar todos los nodos "tal cual".

  3. La regla de identidad se anula para el elemento superior. El elemento superior se copia parcialmente, se copian sus atributos y luego se aplican las plantillas a todos los elementos hijos con una instrucción infantil <xsl:sort>, que especifica la clave de clasificación exacta que se utilizará; cómo el pSortingValues valora el nombre del element el niño es.

ACTUALIZACIÓN: Como se ha señalado por @Alejandro, esto:

 <xsl:sort data-type="number" select= 
     "string-length(substring-before($vSortingValues,concat(',',name,',')))"/> 

puede simplificarse a esto:

 <xsl:sort data-type="number" select= 
     "substring-before($vSortingValues,concat(',',name,','))"/> 
+0

+1. Truco de clasificación elegante. – Flack

+1

@Dimitre: +1 Buena respuesta. Como tipos de datos de cadena, la subcadena anterior también funciona de la misma manera. –

+1

@Alejandro: Gracias. I * estoy * usando 'substring-before()'. –