ElementTree XPath - выбор элемента на основе атрибута - PullRequest
41 голосов
/ 21 октября 2008

У меня проблемы с использованием атрибута XPath Selector в ElementTree, что я должен делать в соответствии с Документацией

Вот пример кода

XML

<root>
 <target name="1">
    <a></a>
    <b></b>
 </target>
 <target name="2">
    <a></a>
    <b></b>
 </target>
</root>

Python

def parse(document):
    root = et.parse(document)
    for target in root.findall("//target[@name='a']"):
        print target._children

Я получаю следующее исключение:

expected path separator ([)

Ответы [ 2 ]

34 голосов
/ 21 октября 2008

Синтаксис, который вы пытаетесь использовать, новый в ElementTree 1.3 .

Такая версия поставляется с Python 2.7 или выше. Если у вас есть Python 2.6 или ниже, у вас все еще есть ElementTree 1.2.6 или меньше.

18 голосов
/ 19 апреля 2013

В этом коде есть несколько проблем.

  1. Встроенное в Python ElementTree (для краткости ET) не имеет реальной поддержки XPATH; только ограниченное подмножество. Например, он не поддерживает выражения find-from-root , такие как //target.

    Примечание: документация упоминает " // ", но только для детей: так что выражение как .//target действителен; //... нет!

    Существует альтернативная реализация: lxml , которая более богата. Похоже, что документация используется для встроенного кода. Это не соответствует / работает.

  2. В нотации @name выбираются атрибуты xml- ; выражение key=value в теге xml.

    Так что имя-значение должно быть 1 или 2, чтобы выбрать что-то в данном документе. Или можно искать цели с дочерним элементом 'a' : target[a] (no @).

Для данного документа, проанализированного с помощью встроенного ElementTree (v1.3) в root, следующий код корректен и работает:

  • root.findall(".//target") Найти обе цели
  • root.findall(".//target/a") Найти два элемента a
  • root.findall(".//target[a]") Это снова находит оба target-элемента, так как оба имеют a-element
  • root.findall(".//target[@name='1']") Найдите только цель first . Обратите внимание, что кавычки около 1 необходимы; иначе возникает ошибка синтаксиса
  • root.findall(".//target[a][@name='1']") Также действует; чтобы найти эту цель
  • root.findall(".//target[@name='1']/a") Находит только один a-элемент; ...
...