Как выбрать последние N элементов с XPath? - PullRequest
11 голосов
/ 19 января 2009

Я поддерживаю веб-сайт, который генерирует контент 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" к последним тридцати дням, кажется довольно неприятным препятствием.

Ответы [ 2 ]

10 голосов
/ 19 января 2009

position () / last () возвращает позицию / последнюю позицию в текущем контексте, поэтому, когда навигатор позиционируется в одном , position () вернет в течение этого месяца, а last () вернет последний в этом месяце, но я думаю, вы это знаете.

Следовательно, все, что вы можете сделать, это сгладить все в массиве и вставить переменную, прежде чем выбирать, как вы делали раньше.

<xsl:variable name="days" select="//day"/>
<xsl:apply-templates select="$days[position()>last()-30]" />
4 голосов
/ 31 марта 2009

Просматривая XSLT-спецификацию сегодня, я обнаружил заметку, объясняющую, почему // ведет себя так:

// это сокращение от /descendant-or-self::node()/. Например, //para является сокращением от /descendant-or-self::node()/child::para и поэтому выберет любой элемент para в документе (даже элемент para, который является элементом документа, будет выбран //para, так как узел элемента документа является дочерний узел корневого узла); 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]"/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...