XPath - все последующие братья и сестры, кроме первых определенных элементов - PullRequest
9 голосов
/ 29 ноября 2010

Допустим, я запрашиваю документ xhtml и хочу запросить всех братьев и сестер после таблицы с id='target'. Кроме того, я не хочу ни первого <table> родного брата, ни первого <ol> родного брата этого конкретного элемента. Вот лучшее, что я мог придумать:

//table[@id='target']/following-sibling::*[not(self::table[1]) and not(self::ol[1])]

Однако, это не возвращает никаких результатов, когда это необходимо. Очевидно, я не понимаю некоторые синтаксис для этого (я не мог найти хороший источник информации). Я, конечно, был бы признателен, если бы кто-то, кто более опытен с синтаксисом XPath, мог бы помочь мне. Кроме того, для чисто академических целей мне было бы любопытно, что на самом деле делает вышеперечисленное.

UPDATE:
См. Ответ LarsH для объяснения того, почему мой XPath не работал, и посмотрите ответ Dimitre для принятого решения.

Ответы [ 3 ]

14 голосов
/ 29 ноября 2010

Использовать :

 /table[@id='target']/following-sibling::*[not(self::table) and not(self::ol)] 
| 
 /table[@id='target']/following-sibling::table[position() > 1]
|
 /table[@id='target']/following-sibling::ol[position() > 1]

Выбирает всех следующих братьев и сестер таблицы, которые не являются table и не ol, и всех следующих братьев и сестер table спозиция 2 или выше и все последующие ol братья и сестры с позицией 2 или выше.

Это именно то, что вам нужно : все последующие братья и сестры, за исключением первых table следующихродной брат и первые ol следующие родные братья.

Это чистый XPath 1.0 и не использует никаких функций XSLT.

2 голосов
/ 29 ноября 2010

Отвечая сначала на второй вопрос: вышеописанное выбирает всех следующих братьев и сестер, которые не являются ни элементами table, ни ol.

Вот почему: self::table[1] выбирает собственный узел контекста (если он проходит проверку имени элемента table) и фильтрует, чтобы выбрать только первый узел вдоль оси self ::. На self :: axis проходит не более одного узла, проходящего проверку имени элемента, поэтому [1] является избыточным. self::table[1] выбирает узел контекста, когда он является элементом таблицы, независимо от его положения среди его братьев и сестер. Так что not(self::table[1]) возвращает false всякий раз, когда узел контекста является элементом таблицы, независимо от его положения среди братьев и сестер.

Аналогично для self::ol[1].

Как сделать то, что вы пытаетесь сделать: @ Джон Кугельман ответил почти правильно, но упускает из виду тот факт, что мы должны игнорировать элементы одного и того же уровня, включая table[@id='target']. Я не думаю, что это возможно сделать правильно в чистом XPath 1.0. У вас есть возможность использовать XPath 2.0? Если вы работаете в браузере, ответ, как правило, нет.

Некоторые обходные пути:

  • Пропускать первого брата по таблице и первого брата по таблице путем фильтрации на некоторой другой основе, например, их атрибутах;
  • Выберите //table[@id='target'] в качестве набора узлов, верните его в среду хоста (т.е. вне XPath, например, в JavaScript), выполните цикл по этому набору узлов; внутри цикла: выберите following-sibling::* через XPath, итерируйте по , который вне XPath, и протестируйте каждый результат (вне XPath), чтобы увидеть, является ли это первая таблица или ол.
  • Выберите //table[@id='target'] в качестве набора узлов, верните его в среду хоста (т.е. вне XPath, например, в JavaScript), выполните цикл по этому набору узлов; внутри цикла: выберите generate-id(following-sibling::table[1]) и generate-id(following-sibling::ol[1]) через XPath, получите эти значения в переменные JS t1id и o1id и создайте строку для выражения XPath, используя форму 'following-sibling::*[generate-id() != ' + t1id + ' and generate-id() != ' + o1id + ']'. Выберите эту строку в XPath, и у вас есть свой ответ! : -Р

Обновление: Решение возможно в XSLT 1.0 - см. @ Dimitre's.

1 голос
/ 29 ноября 2010

При использовании оси self:: будет только один узел, поэтому я считаю, что self::*[1] всегда будет истинным. Каждый узел будет первым (и единственным) узлом на собственной оси self::. Это означает, что ваше выражение в скобках эквивалентно [not(self::table) and not(self::ol)], что означает, что все таблицы и списки отфильтрованы.

У меня нет настроенной тестовой среды, но, возможно, это будет лучше:

/table[@id='target']/following-sibling::*
    [not(self::table and not(preceding-sibling::table)) and
     not(self::ol    and not(preceding-sibling::ol))]

Потребуется некоторая настройка, но идея состоит в том, чтобы отфильтровать table s, у которых нет предшествующего брата table s, и ol s, у которых нет предшествующего брата ol s.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...