Подтвердить что ты не робот

ElementTree XPath - выберите элемент на основе атрибута

У меня возникли проблемы с использованием атрибута 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 ([)
4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

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

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

Ответ 3

Похоже, что findall поддерживает только подмножество XPath. См. Обсуждение рассылки здесь