#xslt #xslt-2.0
#xslt #xslt-2.0
Вопрос:
Я хотел бы определить порядок строк, используемых в определенном элементе. Например, <класс> Старший</класс> <класс> Младший </класс> <класс> Второкурсник </класс> <класс> Первокурсник<класс> описал бы разумный порядок в классе.
Есть ли способ с помощью <xsl:sort select=’class’>, который бы сортировал по порядку, указанному выше?
Заранее спасибо.
Комментарии:
1. Вы используете XSLT 1.0 или 2.0? Является ли Saxon вариантом для вас?
2. Я использую Saxon и могу использовать любую версию 🙂 Обычно я использую 3
Ответ №1:
Что вы могли бы сделать в своем XSLT, так это определить переменную для представления вашего пользовательского порядка, например
<xsl:variable name="inline-array">
<class sort="1">Senior</class>
<class sort="2">Junior</class>
<class sort="3">Sophomore</class>
<class sort="4">Freshman</class>
</xsl:variable>
Затем для доступа к этому «массиву» вы можете определить другую переменную для ссылки на сам документ XSLT:
<xsl:variable name="array"
select="document('')/*/xsl:variable[@name='inline-array']/*" />
Теперь это позволяет вам искать атрибут сортировки для данного имени класса при сортировке (где current() представляет текущий сортируемый узел)
<xsl:sort select="$array[. = current()/@class]/@sort" />
В качестве примера, вот полный XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="inline-array">
<class sort="1">Senior</class>
<class sort="2">Junior</class>
<class sort="3">Sophomore</class>
<class sort="4">Freshman</class>
</xsl:variable>
<xsl:variable name="array"
select="document('')/*/xsl:variable[@name='inline-array']/*"/>
<xsl:template match="/objects">
<xsl:copy>
<xsl:apply-templates select="object">
<xsl:sort select="$array[. = current()/@class]/@sort" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Когда вы применяете это к следующему образцу XML…
<objects>
<object id="2" name="Junior Jo" class="Junior" />
<object id="1" name="Senior Sue" class="Senior" />
<object id="4" name="Freshman Frank" class="Freshman" />
<object id="3" name="Sophie Sophomore" class="Sophomore" />
</objects>
Возвращается следующее
<objects>
<object id="1" name="Senior Sue" class="Senior"></object>
<object id="2" name="Junior Jo" class="Junior"></object>
<object id="3" name="Sophie Sophomore" class="Sophomore"></object>
<object id="4" name="Freshman Frank" class="Freshman"></object>
</objects>
Комментарии:
1. Отличное решение, но я надеялся на что-то более простое. Я надеялся, что смогу определить функцию xsl:, которая будет сравнивать два значения класса (например, старший и младший) и возвращать значение, указывающее, является ли gt, lt или eg .
Ответ №2:
Вы изучали пользовательские расширения сортировки Saxon?
Например,
<xsl:variable name="rules" select="'amp;< Freshman amp;< Sophomore
amp;< Junior amp;< Senior'" />
При этом используется формат RuleBasedCollator из класса Java с таким именем.
Чтобы использовать ее в своей сортировке (используя полезный пример ввода XML и таблицы стилей Тима Си):
<xsl:apply-templates select="object">
<xsl:sort select="@class"
collation="http://saxon.sf.net/collation?rules={encode-for-uri($rules)}"/>
</xsl:apply-templates>
Это дает те же результаты, что и решение Тима С. (Протестировано с использованием Saxon PE 9.3.0.5.)
Это не функция xsl:, но она дает вам немного больше гибкости, чем массив, и, возможно, более сжата. AFAICT нет способа создать пользовательскую сортировку с помощью пользовательской функции XSLT. Поскольку вы не говорите, зачем вам нужен an xsl:function
, трудно предположить, какие альтернативы будут соответствовать вашим потребностям.
Для полной гибкости, подобной xsl: function, вы можете определить свой собственный collator на Java; см. http://www.saxonica.com/documentation/extensibility/collation.xml о реализации java.util.Интерфейс компаратора и указание вашего компаратора в class
атрибуте.
Комментарии:
1. Я думал, что использование функции будет единственным выходом, но это служит той же цели для меня — не нужно спускаться на уровень ниже и использовать Java. Спасибо.
2. Это был действительно хороший ответ — намного проще, чем все другие варианты.