访问ElementTree节点父节点

hoj*_*oju 55 python elementtree

我正在使用内置的Python ElementTree模块.访问子节点很简单,但父节点或兄弟节点呢? - 这可以在不遍历整棵树的情况下有效地完成吗?

Vin*_*jip 45

没有以parent属性的形式直接支持,但您可以使用此处描述的模式来实现所需的效果.建议使用以下单行(从链接到帖子)为整个树创建子到父映射:

parent_map = dict((c, p) for p in tree.getiterator() for c in p)
Run Code Online (Sandbox Code Playgroud)

  • 更正:`parent_map = {c:p表示root中的p,iter()表示p中的c}` (5认同)
  • 语法更新,2017 / python3`parent_map = {(tree中的p的((c,p))。p中的c的iter()})` (4认同)

sup*_*gra 21

Vinay的答案应该仍然有效,但对于Python 2.7+和3.2+,建议采用以下方法:

parent_map = {c:p for p in tree.iter() for c in p}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • 如果您无权访问树怎么办?就像在 .find() 之后 (2认同)

jos*_*ven 10

您可以...在ElementTree中使用xpath 表示法.

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

xml.findall('.//child[@id="123"]...')
>> [<Element 'parent'>]
Run Code Online (Sandbox Code Playgroud)

  • **注意:** 此代码只需 **两个** 点即可完美运行。不存在“三点语法”这样的东西。正如其他人提到的那样,它不是[在文档中](https://docs.python.org/3/library/xml.etree.elementtree.html#supported-xpath-syntax)。它只是“.”(选择当前节点)和“..”(获取父节点)的组合。 (5认同)
  • 我找不到关于这个 `...` XPath 语法的任何信息。它有什么作用?有相关的文档吗? (2认同)

Vaa*_*sha 5

使用查找方法(xml.etree.ElementTree)后获取父元素中所述,您将不得不间接搜索父对象。具有xml:

<a>
 <b>
  <c>data</c>
  <d>data</d>    
 </b>
</a>
Run Code Online (Sandbox Code Playgroud)

假设您已将etree元素创建为xml变量,则可以使用:

 In[1] parent = xml.find('.//c/..')
 In[2] child = parent.find('./c')
Run Code Online (Sandbox Code Playgroud)

导致:

Out[1]: <Element 'b' at 0x00XXXXXX> 
Out[2]: <Element 'c' at 0x00XXXXXX>
Run Code Online (Sandbox Code Playgroud)

较高的家长会被发现为:secondparent=xml.find('.//c/../..')存在<Element 'a' at 0x00XXXXXX>


jla*_*ens 5

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
Run Code Online (Sandbox Code Playgroud)

最后一个答案打破了所有的希望......


sas*_*alm 5

在这里粘贴我来自/sf/answers/3846077231/ 的回答:

我有一个类似的问题,我有点创意。事实证明,没有什么可以阻止我们自己添加亲子信息。一旦我们不再需要它,我们就可以稍后剥离它。

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())
Run Code Online (Sandbox Code Playgroud)