Как выбрать последние N элементов с помощью XPath?
Я поддерживаю веб-сайт, который генерирует XML-контент, который затем транслируется на веб-страницы с использованием XSLT. Меня попросили создать новую таблицу стилей, которая преобразует вывод страницы "архив" в Atom для синдикации. Проблема, с которой я сталкиваюсь, заключается в том, что страница архива содержит довольно большое количество элементов - 142 и подсчет - и в фиде никогда не должно быть более тридцати элементов.
В настоящее время вывод с страницы архива выглядит примерно так:
<archive>
<year>
<month>
<day>
<day>
...
</month>
...
</year>
...
</archive>
Теги year
и month
используются преобразованием HTML, но совершенно неактуальны для фида Atom. Я надеялся, что использование функции position()
с осью потомка будет работать (//day[position()>last()-30]
), но это выбирает последние 30 дней каждого месяца, что совсем не то, что мне нужно.: -)
Есть ли способ сделать это с помощью XSLT или XPath? Необходимость модифицировать генератор XML для добавления, скажем, атрибута feed="true"
за последние тридцать дней, кажется довольно неприятным kludge.
Ответы
Ответ 1
position()/last() возвращает позицию/последнюю позицию в текущем контексте, поэтому, когда навигатор помещается за один месяц > , позиция() вернет < день > в течение этого месяца и last() вернет последний < день > в течение этого месяца, но я думаю, вы это знаете.
Следовательно, что вы можете сделать, это сгладить все <day> в массиве и поместить в переменную до выбора так же, как вы делали раньше.
<xsl:variable name="days" select="//day"/>
<xsl:apply-templates select="$days[position()>last()-30]" />
Ответ 2
Просматривая XSLT spec сегодня, я нашел примечание, которое объясняет, почему //
ведет себя следующим образом:
//
не подходит для /descendant-or-self::node()/
. Например, //para
является коротким для /descendant-or-self::node()/child::para
и поэтому выберет любой элемент para
в документе (даже элемент para
, который является элементом документа, будет выбран //para
, поскольку элемент документа node является потомком корня node); div//para
сокращен для div/descendant-or-self::node()/child::para
и поэтому выберет всех para
потомков дочерних div.
ПРИМЕЧАНИЕ. Путь местоположения //para[1]
не означает то же, что и путь местоположения /descendant::para[1]
. Последний выбирает первый элемент потомка para
; первый выбирает все дочерние элементы para
, которые являются первыми детьми para
их родителей.
Другими словами, при использовании //
, position()
вычисляется вдоль оси child
, а не оси descendant-or-self
. Указание descendant
или descendant-or-self
позволяет вам получить первые/последние n узлов, как вы ожидали:
<xsl:apply-templates select="descendant::day[position()>last()-30]"/>