2009-08-17 6 views
3

Возможно ли в XSLT сортировать в алфавитном порядке, при этом 5 позиций являются «предпочтительными».XSLT Custom Sort

т.е. с учетом

<teams> 
<team id="142" name="Scotland" /> 
<team id="110" name="Liverpool" /> 
<team id="13" name="Manchester United" /> 
<team id="123" name="England" /> 
<team id="84" name="Chelsea" /> 
<team id="295" name="Wales" /> 
<team id="49" name="Arsenal" /> 
<team id="126" name="Northern Ireland" /> 
<team id="121" name="Republic of Ireland" /> 
<team id="42" name="Manchester City" /> 
<team id="298" name="Tottenham Hotspur" /> 
<team id="299" name="Bolton" /> 
</teams> 

Я требую национальных команд, которые будут отсортированы сначала в определенном порядке, а затем остальные в алфавитном порядке:

<teams> 
<team id="123" name="England" /> 
<team id="126" name="Northern Ireland" /> 
<team id="121" name="Republic of Ireland" /> 
<team id="142" name="Scotland" /> 
<team id="295" name="Wales" /> 
<team id="49" name="Arsenal" /> 
<team id="299" name="Bolton" /> 
<team id="84" name="Chelsea" /> 
<team id="110" name="Liverpool" /> 
<team id="42" name="Manchester City" /> 
<team id="13" name="Manchester United" /> 
<team id="298" name="Tottenham Hotspur" /> 
</teams> 

Я пытался, но терпит неудачу.

Есть ли опрятный способ сделать это, или вам нужно сортировать национальные команды индивидуально, а затем сортировку, которая исключает все национальные команды?

ответ

5

Вы можете сделать это:

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:my="http://tempuri.org" 
    exclude-result-prefixes="my" 
> 

    <xsl:output method="xml" indent="yes" /> 

    <my:data> 
    <my:nationalteams> 
     <my:team id="121" /><!-- Republic of Ireland --> 
     <my:team id="123" /><!-- England --> 
     <my:team id="126" /><!-- Northern Ireland --> 
     <my:team id="142" /><!-- Scotland --> 
     <my:team id="295" /><!-- Wales --> 
    </my:nationalteams> 
    </my:data> 

    <xsl:template match="teams"> 
    <xsl:copy> 
     <xsl:variable name="national" select=" 
     document('')/*/my:data/my:nationalteams/my:team 
     " /> 
     <!-- national teams preferred --> 
     <xsl:apply-templates select="team[@id = $national/@id]"> 
     <xsl:sort select="@name" /> 
     </xsl:apply-templates> 
     <!-- other teams after them --> 
     <xsl:apply-templates select="team[not(@id = $national/@id)]"> 
     <xsl:sort select="@name" /> 
     </xsl:apply-templates> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="team"> 
    <xsl:copy-of select="." /> 
    </xsl:template> 

</xsl:stylesheet> 

Всем <my:data> может быть перемещен на вторичный XML/конфигурационный файл, в котором вы можете оставить от «моих» пространства имен.

После этого одна строка потребуется небольшое изменение:

<xsl:variable name="national" select=" 
    document('config.xml')/data/nationalteams/team 
" /> 

Выход выше несколько неудивителен :-)

<teams> 
    <team id="123" name="England" /> 
    <team id="126" name="Northern Ireland" /> 
    <team id="121" name="Republic of Ireland" /> 
    <team id="142" name="Scotland" /> 
    <team id="295" name="Wales" /> 
    <team id="49" name="Arsenal" /> 
    <team id="299" name="Bolton" /> 
    <team id="84" name="Chelsea" /> 
    <team id="110" name="Liverpool" /> 
    <team id="42" name="Manchester City" /> 
    <team id="13" name="Manchester United" /> 
    <team id="298" name="Tottenham Hotspur" /> 
</teams> 
1

Вы видели XSL: своего рода элемент, вы можете создать два или более критериев сортировки путем объединения XSL: применять-шаблоны и XSL: сортировать

Indeeed, вот пример, когда некоторые страны приходит первым, в предопределенный заказ, , затем все остальные. Обратите внимание, что это элементы, а не атрибуты, как указано выше.

<xsl:sort select="not(CountryValue = 'Scotland')"/> 
<xsl:sort select="not(CountryValue = 'India')"/> 
<xsl:sort select="CountryValue"/> 

Пример результата:

Страна

Scotland 
Scotland 
Scotland 
India 
Afghanistan 
Afghanistan 
Afghanistan 
Afghanistan 
Afghanistan 
Afghanistan 
Albania 
Albania 
Albania 
Algeria 
1

В вашем XSLT, вы в состоянии использовать функции расширения?

Если это так, один из способов - изменить существующий список узлов в строке, создать новый набор узлов, но с дополнительным атрибутом «sortname» на каждом узле. Вы можете перебирать этот новый набор узлов, сортировка с помощью нового «sortname атрибут»:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="urn:schemas-microsoft-com:xslt"> 
    <xsl:output method="xml" /> 
    <xsl:template match="/teams"> 
     <xsl:variable name="extendedteams"> 
     <xsl:for-each select="team"> 
      <xsl:copy> 
       <xsl:copy-of select="@*" /> 
       <xsl:attribute name="sortname"> 
        <xsl:choose> 
         <xsl:when test="@name='England' or @name='Northern Ireland' or @name='Republic of Ireland' or @name='Scotland' or @name='Wales'">1</xsl:when> 
         <xsl:otherwise>2</xsl:otherwise> 
        </xsl:choose> 
        <xsl:value-of select="@name" /> 
       </xsl:attribute> 
      </xsl:copy> 
     </xsl:for-each> 
     </xsl:variable> 
     <xsl:copy> 
     <xsl:for-each select="exsl:node-set($extendedteams)/team"> 
      <xsl:sort select="@sortname" /> 

      <xsl:copy> 
       <xsl:copy-of select="@*[name() != 'sortname']" /> 
      </xsl:copy> 
     </xsl:for-each> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

В приведенном выше примере, я предварять «1» на национальную команду, и «2» на любом внутреннем команды, а затем выполните сортировку по этому новому атрибуту.

См. Информацию о Node Sets, чтобы узнать, какие XSLT-процессоры поддерживают расширения.

11

Tim C уже дал хороший ответ, но возможно, в вашем случае будет более простой способ. Вы можете просто указать два xsl:sort условия: первое сортировать по привилегированным/не-предпочтительным пунктам, второй в алфавитном порядке по имени:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="/teams"> 
    <teams> 
     <xsl:for-each select="team"> 
     <xsl:sort select="not(@name = 'England' or @name='Northern Ireland' 
          or @name='Republic of Ireland' 
          or @name='Scotland' or @name='Wales')" 
        data-type="number"/> 
     <xsl:sort select="@name"/> 
     <team> 
      <xsl:value-of select="@name"/> 
     </team> 
     </xsl:for-each> 
    </teams> 
    </xsl:template> 
</xsl:stylesheet> 

Пожалуйста, обратите внимание, что вы должны инвертировать первое условие, используя not().Причина в том, что логический результат вашего выражения преобразуется в число (0 - false, 1 - true), и, следовательно, элементы, оценивающие значение «false», будут перечислены первыми.

+0

Ваш ответ намного приятнее, чем мой. У вас нет необходимости в функции расширения! –

+0

Однако функция расширения дает вам большую гибкость IMHO. –