Принятый ответ исправляет ошибку, но на самом деле не объясняет, почему исходное выражение пути пошло не так.
Ваше первое выражение выглядит так:
//table[//b[contains(@class, "2")]]
Он имеет два предиката, один из которых вложен в другой:
//table[//b[contains(@class, "2")]]
^---------------------^ inner predicate
^--------------------------^ outer predicate
Думайте о предикатах как о фильтрах, которые применяются к левому контексту предиката. В крайних случаях такой предикат отбрасывает либо ни один, либо все узлы промежуточных результатов.
Каждый узел промежуточного результата сохраняется только в том случае, если предикат справа от него оценивается как true
. В случае внутреннего предиката:
//b[contains(@class, "2")]
//b
дает набор промежуточных узлов элементов b
(все узлы элементов b
во всем документе), которые затем фильтруются предикатом [contains(@class, "2")]
. Учитывая входной XML-документ, выражение внутри предиката возвращает true
только для одного из b
элементов.
Но //b[contains(@class, "2")]
, в свою очередь, служит содержанием внешнего предиката:
//table[outer predicate]
Теперь //table
выбирает в качестве промежуточного результата все table
узлов-элементов во всем документе, и для каждого из них проверяется выражение внутри предиката.
Важно, что внешний предикат //b[contains(@class, "2")]
вернет true
для обоих table
элементов. Это потому, что для них обоих верно, что где-то во всем документе есть элемент b
, чей атрибут class
содержит 2
.
Что вы на самом деле хотели сделать, так это: оценить выражение внешнего предиката с точки зрения каждого элемента table
- и принятый ответ показывает, как это сделать. А именно, используя .//
вместо //
в предикате.
person
Mathias Müller
schedule
10.02.2016