2011-01-24 8 views
5

Desidero ordinare un file XML con una trasformazione XSL.Ordinamento di XML in XSLT in base a un elenco di valori

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

Deve essere ordinato secondo il seguente elenco di nomi: C, A, B in modo che l'XML risultante è:

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

Ovviamente l'elenco dei valori da ordinamento dovrebbe essere abbastanza dinamico (parametro dell'XSLT, un altro file XML ...). Qualche idea su come farlo nell'XSLT?

Grazie, Christophe

+0

Buona domanda, +1. Vedi la mia risposta per una soluzione completa e breve, oltre a spiegazioni esaustive. –

risposta

8

Questa trasformazione:

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

quando applicato sul documento XML fornito:

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

produce i desiderati risultati corretti,:

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

nota impegno:

  1. L'elenco valori filtrate desiderato è la pSortingValues parametro globale, che può essere fornito esternamente alla trasformazione.

  2. La regola di identità viene utilizzata per copiare tutti i nodi "così com'è".

  3. La regola di identità viene sostituita per l'elemento superiore. L'elemento superiore viene parzialmente copiato, i suoi attributi vengono copiati, i modelli vengono applicati su tutti gli elementi figlio con un'istruzione figlio <xsl:sort>, che specifica la chiave di ordinamento esatta da utilizzare: in che modo davanti ai valori pSortingValues il nome dello element il bambino è

UPDATE: Come notato da @Alejandro, questo:

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

può essere semplificata a questo:

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

+1. Fancy sorting trick. – Flack

+1

@Dimitre: +1 buona risposta. Come tipi di dati stringa, anche la sottostringa prima funziona allo stesso modo. –

+1

@ Alejandro: Grazie. Io * sto * usando 'sottostringa-prima()'. –

Problemi correlati