Получить родительский элемент после использования метода find (xml.etree.ElementTree)

Я работаю с огромным xml-файлом и пытаюсь извлечь информацию из разных элементов.

import xml.etree.ElementTree as ET
tree = ET.parse('t.xml')
root = tree.getroot()

Чтобы найти элементы, я использую метод find:

elm = root.find('.//Element[@elmid="1234"]')

Из этого я извлекаю информацию и, кроме того, мне нужна информация из родительского элемента. Но elm.find('..') только возвращается None как описано здесь: https://docs.python.org/3/library/xml.etree.elementtree.html

Теперь я использую следующие:

prt = root.find('.//Element[@elmid="1234"]/..')     
elm = prt.find('/Element[@elmid="1234"]')

Это выглядит немного неестественно для меня, но работает.

Знаете ли вы лучший способ сделать это? Ты знаешь почему только None возвращается?

1 ответ

Решение

xml.etree API поддерживает только ограниченную версию XPath. xml.etree документы для .. Состояние выражения XPath:

Выбирает родительский элемент. Возвращает None, если путь пытается достичь предков начального элемента (был вызван поиск элемента).

Непосредственное получение родительского элемента не поддерживается в xml.etree API. Поэтому я бы рекомендовал использовать lxml где вы можете просто использовать getparent() чтобы получить родительский элемент:

elm = root.find('.//Element[@elmid="1234"]')
elm.getparent()

lxml также имеет полную реализацию XPath 1.0, поэтому elem.xpath('..') будет работать так же.

У меня была похожая проблема, и я стал немного креативным. Оказывается, ничто не мешает нам самим добавлять информацию о происхождении. Позже мы можем лишить его, когда он нам больше не нужен.

def addParentInfo(et):
    for child in et:
        child.attrib['__my_parent__'] = et
        addParentInfo(child)

def stripParentInfo(et):
    for child in et:
        child.attrib.pop('__my_parent__', 'None')
        stripParentInfo(child)

def getParent(et):
    if '__my_parent__' in et.attrib:
        return et.attrib['__my_parent__']
    else:
        return None

tree = ...
addParentInfo(tree.getroot())
el = tree.findall(...)[0]
parent = getParent(el)
while parent:
    ...
    parent = getParent(parent)
...
stripParentInfo(tree.getroot())
Другие вопросы по тегам