2011-01-24 1 views
5

Я хотел бы отсортировать один XML-файл с преобразованием XSL.Сортировка XML в XSLT на основе списка значений

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

должен быть отсортирован по следующему списку имен: C, A, B, так что результирующий XML является:

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

Очевидно, что список значений будет сортировать по должно быть достаточно динамичными (параметр XSLT, другой XML-файл ...). Любая идея, как это сделать в XSLT?

Спасибо, Christophe

+0

Хороший вопрос, +1. См. Мой ответ для полного и короткого решения, а также исчерпывающие объяснения. –

ответ

8

Это преобразование:

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

при нанесении на поставленном XML документа:

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

производит Wanted, правильные результаты:

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

Обратите внимание:

  1. Нужный список отсортированных значений является глобальным параметром pSortingValues, который может быть предусмотрен извне к трансформации.

  2. Правило идентификации используется для копирования всех узлов «как есть».

  3. Правило идентификации переоценивается для верхнего элемента. Верхний элемент частично скопирован, его атрибуты скопированы, затем шаблоны применяются ко всем дочерним элементам с дочерней инструкцией <xsl:sort>, которая указывает точный ключ сортировки, который будет использоваться - как перед знаками pSortingValues имя element ребенок есть.

ОБНОВЛЕНИЕ: Как было отмечено @Alejandro, это:

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

может быть упрощено к этому:

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

+1. Необычный сортировочный трюк. – Flack

+1

@ Dimitre: +1 Хороший ответ. Как и строковые типы данных, подстрока также работает аналогичным образом. –

+1

@Alejandro: Спасибо. I * am *, используя 'substring-before()'. –