доступ к родительскому узлу узла ElementTree - PullRequest
55 голосов
/ 31 января 2010

Я использую встроенный модуль Python ElementTree. Доступ к дочерним элементам прост, но как насчет родительских или родственных узлов? - можно ли сделать это эффективно, не обходя все дерево?

Ответы [ 9 ]

43 голосов
/ 31 января 2010

Прямой поддержки в виде атрибута parent нет, но, возможно, вы можете использовать шаблоны, описанные здесь , для достижения желаемого эффекта. Предлагается следующий однострочный (из связанного с постом) создания дочернего к родительскому отображению для всего дерева:

parent_map = dict((c, p) for p in tree.getiterator() for c in p)
20 голосов
/ 22 ноября 2013

Ответ Винэя должен все еще работать, но для Python 2.7+ и 3.2+ рекомендуется следующее:

parent_map = {c:p for p in tree.iter() for c in p}

getiterator() устарела в пользу iter(), и было бы хорошо использовать новый dict конструктор понимания списка.

Во-вторых, при создании документа XML возможно, что у ребенка будет несколько родителей, хотя это удаляется после сериализации документа. Если это имеет значение, вы можете попробовать это:

parent_map = {}
for p in tree.iter():
    for c in p:
        if c in parent_map:
            parent_map[c].append(p)
            # Or raise, if you don't want to allow this.
        else:
            parent_map[c] = [p]
            # Or parent_map[c] = p if you don't want to allow this
9 голосов
/ 22 октября 2015

Вы можете использовать нотацию xpath ... в ElementTree.

<parent>
     <child id="123">data1</child>
</parent>

xml.findall('.//child[@id="123"]...')
>> [<Element 'parent'>]
5 голосов
/ 25 ноября 2015

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

<a>
 <b>
  <c>data</c>
  <d>data</d>    
 </b>
</a>

Предполагая, что вы создали элемент etree в переменной xml, вы можете использовать:

 In[1] parent = xml.find('.//c/..')
 In[2] child = parent.find('./c')

В результате:

Out[1]: <Element 'b' at 0x00XXXXXX> 
Out[2]: <Element 'c' at 0x00XXXXXX>

Старший родитель будет найден как: secondparent=xml.find('.//c/../..'), являющийся <Element 'a' at 0x00XXXXXX>

3 голосов
/ 04 июля 2018

Селектор XPath '..' нельзя использовать для извлечения родительского узла в 3.5.3 или 3.6.1 (по крайней мере, в OSX), например, в интерактивном режиме:

import xml.etree.ElementTree as ET
root = ET.fromstring('<parent><child></child></parent>')
child = root.find('child')
parent = child.find('..') # retrieve the parent
parent is None # unexpected answer True

Последний ответ разбивает все надежды ...

2 голосов
/ 23 февраля 2014

Другой способ, если вам просто нужен родительский элемент отдельного элемента, а также известен xpath этого элемента.

parentElement = subElement.find(xpath+"/..")
1 голос
/ 01 марта 2019

Вставьте сюда мой ответ от https://stackoverflow.com/a/54943960/492336:

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

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

# Example usage

tree = ...
addParentInfo(tree.getroot())
el = tree.findall(...)[0]
parent = getParent(el)
while parent:
    doSomethingWith(parent)
    parent = getParent(parent)
stripParentInfo(tree.getroot())
1 голос
/ 04 декабря 2014

Если вы используете lxml, я смог получить родительский элемент со следующим:

parent_node = next(child_node.iterancestors())

Это вызовет исключение StopIteration, если у элемента нет предков - поэтому будьте готовы поймать это, если вы можете столкнуться с этим сценарием.

0 голосов
/ 14 декабря 2017

Посмотрите на 19.7.2.2. раздел: Поддерживаемый синтаксис XPath ...

Найти родителя узла, используя путь:

parent_node = node.find('..')
...