Двойная косая черта в предикате XPath работает так же, как и в самом пути

Я играл с различными запросами XPath с XPather (работает только со старыми версиями firefox) и заметил разницу между результатами следующих запросов

Это показывает некоторые результаты

//div[descendant::table/descendant::td[4]] 

этот список пустой список

//div[//table//td[4]]

они отличаются из-за некоторых правил или это просто неправильное поведение конкретной реализации интерпретатора XPath? (Похоже, используется из FF engine, XPather - это просто отличный простой графический интерфейс для querying)

2 ответов


С XPath 1.0 // это аббревиатура /descendant-or-self::node()/ Итак, первый путь-это /descendant-or-self::node()/div[descendant::table/descendant::td[4]] в то время как вторая довольно отличаться с /descendant-or-self::node()/div[/descendant-or-self::node()/table/descendant-or-self::node()/td[4]]. Таким образом, основное различие заключается в том, что внутри вашего первого предиката вы смотрите вниз для потомков относительно div элемент в то время как во втором предикате вы смотрите вниз для потомков из корневого узла / (также называемый узлом документа). Вы, возможно, захотите //div[.//table//td[4]] для второго выражения пути, чтобы приблизиться к первому один.

[редактирование] Вот пример:

<html>
  <body>
    <div>
      <table>
        <tbody>
          <tr>
            <td>1</td>
          </tr>
          <tr>
            <td>2</td>
          </tr>
          <tr>
            <td>3</td>
          </tr>
          <tr>
            <td>4</td>
          </tr>
        </tbody>
      </table>
    </div>
  </body>
</html>

С этим образцом путь //div[descendant::table/descendant::td[4]] выбирает div элемент, так как он имеет table ребенок, у которого есть четвертый td потомок.

вместе с //div[.//table//td[4]] мы ищем //div[./descendant-or-self::node()/table/descendant-or-self::node()/td[4]] что сокращенно от //div[./descendant-or-self::node()/table/descendant-or-self::node()/child::td[4]] и нет элемента, имеющего четвертый td дочерний элемент.

я надеюсь, что объясняет разницу, если вы используете //div[.//table/descendant::td[4]] тогда вы должны получить тот же результат, что и с вашим оригинальная форма.


в документе W3C на XPath есть важная заметка:

XML Path Language (XPath) версия 1.0
    2 Пути Расположения
        2.5 Сокращенный Синтаксис

Примечание: путь //para[1] не означает то же самое, что путь местоположения /descendant::para[1]. Последний выбирает первого потомка para элемент; первый выбирает всех потомков para элементы это первые дети своих родителей.

это означает, что двойной Слэш в пути-это не просто ярлык для /descendant-or-self::node()/ но также отправной точкой для следующего уровня итерации дерева XML, что подразумевает выражение шага справа от // повторно запускается для каждого потомка текущего контекстного узла.

Итак, точное значение сказуемого в этом пути

//div[ descendant::table/descendant::td[4] ]

- это:

  • построить последовательность все!--8--> узлы-потомки текущего <div>,
  • для каждого такого <table> построить последовательность всех потомков <td> элементов и объединить их в одну последовательность,
  • отфильтруйте эту последовательность для ее четвертого элемента.

наконец, путь возвращает все <div> элементы в документе, которые имеют не менее четырех ячеек данных во всех своих вложенных таблиц. И так как в документе есть таблицы, которые имеют 4 ячейки или больше (включая ячейки во вложенных таблицах, конечно), все выражение выбирает их соответствующие <div> предков.

С другой стороны предикат в

//div[ //table//td[4] ]

означает:

  • сканирование всего дерева документов для <table> элементы (точнее, проверьте корневой узел и потомок каждого корня, если он имеет <table> ребенок),
  • для каждой найденной таблицы сканируйте ее поддерево для элементов, имеющих четвертый <td> подэлемент (т. е. тест если таблица или любой из ее потомков имеет по крайней мере четыре <td> дети).

обратите внимание, что подвыражение предиката не зависит от узла контекста. Это глобальный путь, разрешающий некоторую последовательность узлов (возможно, пустую), поэтому логическое значение предиката зависит только от структуры документа. Если это правда, весь путь возвращает последовательность всех <div> элементы в документе, иначе пустая последовательность.

наконец предикат будет правда если бы в любой таблица, имеющая 4 (по крайней мере) ячейки данных.
И насколько я могу видеть все <tr> строки содержат две или три клетки - нет элемента с 4 или более <td> children, поэтому подвыражение предиката возвращает пустую последовательность en, предикат false и весь путь фильтруется. Результат: ничего (пустая последовательность).