#xml #xslt
#xml #xslt
Вопрос:
Я хотел бы иметь возможность сортировать некоторые элементы сначала по имени некоторых их дочерних элементов, а затем по атрибуту.
Вот пример. Я упростил его по сравнению с моим фактическим требованием, так что, надеюсь, это не вызовет еще большей путаницы, которую оно решает. Реальное требование имеет ряд других элементов, как родных братьев и сестер, Animals
с их собственными требованиями к сортировке, но этот фрагмент, в частности, доставляет мне огорчение.
Перед преобразованием
<Animals>
<Animal Value="20160.17">
<Identifier id="1" />
<Pig><!-- more elements inside here--></Pig>
</Animal>
<Animal Value="5000.40">
<Identifier id="2" />
<Cow><!-- more elements inside here--></Cow>
</Animal>
<Animal Value="63.44">
<Identifier id="3" />
<Pig><!-- more elements inside here--></Pig>
</Animal>
<Animal Value="4800.40">
<Identifier id="4" />
<Cow><!-- more elements inside here--></Cow>
</Animal>
</Animals>
Требуемое преобразование
Я бы хотел, чтобы каждый Animal
элемент сортировался так, чтобы все Animal
s с Cow
дочерним элементом были первыми, а затем все Animal
s с Pig
дочерним элементом. В каждой из этих категорий они должны быть отсортированы численно по атрибуту Animal
‘s Value
.
После преобразования
<Animals>
<Animal Value="4800.40">
<Identifier id="4" />
<Cow><!-- more elements inside here--></Cow>
</Animal>
<Animal Value="5000.40">
<Identifier id="2" />
<Cow><!-- more elements inside here--></Cow>
</Animal>
<Animal Value="63.44">
<Identifier id="3" />
<Pig><!-- more elements inside here--></Pig>
</Animal>
<Animal Value="20160.17">
<Identifier id="1" />
<Pig><!-- more elements inside here--></Pig>
</Animal>
</Animals>
Попытка
Я довольно новичок в XSL, и моя лучшая попытка до сих пор, похоже, не учитывает элементы Cow / Pig. Он сортирует только по Value
атрибуту:
<xsl:template match="Animals">
<xsl:copy>
<xsl:apply-templates select="Animal">
<xsl:sort select="name(*) = 'Cow'" />
<xsl:sort select="name(*) = 'Pig'" />
<xsl:sort select="@Value" data-type="number" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
Ответ №1:
Ваша инструкция:
<xsl:sort select="name(*) = 'Cow'" />
ничего не делает, потому что выражение:
name(*)
возвращает имя первого дочернего элемента, которое является «Идентификатором» для всех Animal
узлов.
Попробуйте, возможно:
<xsl:sort select="name(*[2]) = 'Cow'" order="descending"/>
(Порядок должен быть descending
таким, потому что в алфавитном порядке «true» идет после false».)
Кроме того, вы можете просто применять шаблоны отдельно для каждой категории:
<xsl:template match="Animals">
<xsl:copy>
<xsl:apply-templates select="Animal[Cow]">
<xsl:sort select="@Value" data-type="number" />
</xsl:apply-templates>
<xsl:apply-templates select="Animal[Pig]">
<xsl:sort select="@Value" data-type="number" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
Комментарии:
1. спасибо, я выбрал второй вариант separate
apply-templates
, поскольку порядок дочерних элементов не гарантируется. я действительно пробовал что-то подобное ранее, но неправильно определил значениеselect
атрибута. похоже, мне нужно поработать над своими навыками xpath, а не над своими навыками xslt…