XPath - все следующие братья и сестры, кроме первых конкретных элементов
предположим, я запрашиваю документ xhtml, и я хочу запросить всех братьев и сестер после таблицы с id='target'
. Кроме того, я не хочу первый <table>
брат ни первый <ol>
брат этого конкретного элемента. Вот лучшее, что я мог придумать:
//table[@id='target']/following-sibling::*[not(self::table[1]) and not(self::ol[1])]
однако это не возвращает никаких результатов, когда это должно. Очевидно, я не понимаю некоторые синтаксиса для этого (я не мог найти хороший источник информации). Я был бы очень признателен если бы кто-то более опытный в синтаксисе XPath мог мне помочь. Кроме того, для чисто академических целей, мне было бы любопытно, что выше на самом деле делает.
обновление:
См. ответ Ларша для объяснения того, почему мой XPath не работал, и см. ответ Дмитрия для принятого решения.
3 ответов
использовать:
/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.
отвечая на второй вопрос во-первых: то, что выше делает, это выбор всех следующих братьев и сестер, которые не являются ни table
, ни ol
элементы.
вот почему: self::table[1]
выбирает сам контекстный узел (если он передает table
имя элемента test) и фильтры, чтобы выбрать только первый узел вдоль оси self::. Существует не более одного узла на оси self::, проходящей тест имени элемента, поэтому [1]
избыточна. self::table[1]
выбирает контекстный узел всякий раз, когда это элемент таблицы, независимо от своего положения среди своих братьев и сестер. Так что not(self::table[1])
возвращает false, когда контекстный узел является элементом таблицы, независимо от его позиции среди братьев и сестер.
аналогично self::ol[1]
.
как сделать то, что вы пытаетесь сделать:
Ответы @Джон Kugelman-это почти правильно, но не факт, что мы должны игнорировать элементов до и включая table[@id='target']
. Я не думаю, что это возможно сделать правильно в чистом XPath 1.0. у вас есть возможность использования XPath 2.0? если вы работаете в браузере, ответ, как правило, нет.
некоторые обходные пути были бы:
- пропустите первую следующую таблицу sibling и первую следующую ol sibling путем фильтрации на какой-либо другой основе, например, их атрибуты;
- выберите
//table[@id='target']
в качестве nodeset верните его в среду хоста (т. е. вне XPath, например, в JavaScript), выполните цикл через этот nodeset; внутри цикла: выберитеfollowing-sibling::*
через XPath, повторите через это вне XPath и проверьте каждый результат (вне XPath), чтобы увидеть, является ли это первой таблицей или ol. - выберите
//table[@id='target']
в качестве nodeset верните его в среду хоста (т. е. вне XPath, например, в JavaScript), выполните цикл через этот nodeset; внутри цикла: выберите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, и у вас есть ответ! :- p
обновление: решение и возможно в XSLT 1.0 - смотри @Dimitre это.
есть только один узел, когда вы используете self::
axis, поэтому я считаю 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))]
нужно кое-что подправить, но идея фильтра вон!--5-->s, которые не имеют предыдущего брата table
S и ol
s, которые не имеют предыдущего брата ol
s.