Я пытаюсь отсортировать кучу записей в файле XML. Хитрость в том, что мне нужно сортировать, используя разные элементы для разных узлов. Чтобы дать самый простой пример, Ключом сортировки является фамилия, если она присутствует, в противном случае это псевдоним, если он присутствует, и имя в противном случае.
У меня возникли трудности, поскольку использование переменных в качестве ключей xsl: sort , по-видимому, недопустимо .
Мой лучший лучший вариант - это двухэтапное преобразование: добавить специальный тег в каждая запись с использованием этой таблицы стилей
И затем сортировка полученного XML
Хотя это двухступенчатое преобразование работает, мне интересно, есть ли более элегантный способ сделать это за один раз?
Вы можете использовать функцию XPath concat
:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/buddies">
<xsl:apply-templates>
<xsl:sort select="concat(last,nick,first)"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="person">
<xsl:value-of select="concat(normalize-space(concat(first,
' ',
nick,
' ',
last)),
'
')"/>
</xsl:template>
</xsl:stylesheet>
Можете ли вы попробовать, если этот шаблон дает ожидаемый результат? Для вашего простого примера он дает правильный ответ, но могут быть угловые случаи, которые не будут работать. Normalize-space используется здесь для удаления начальных и конечных пробелов, если один из элементов отсутствует.
<xsl:template match="/buddies">
<xsl:for-each select="person">
<xsl:sort select="normalize-space(concat(last, ' ', nick, ' ', first))"/>
<xsl:if test="first">
<xsl:value-of select="first" />
<xsl:text> </xsl:text>
</xsl:if>
<xsl:if test="nick">
<xsl:value-of select="nick" />
<xsl:text> </xsl:text>
</xsl:if>
<xsl:value-of select="last" />
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>