Можете ли вы определить пользовательскую сортировку с помощью функции в XSLT?

#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. Это был действительно хороший ответ — намного проще, чем все другие варианты.