77

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

4

10 回答 10

62

没有parent属性形式的直接支持,但您也许可以使用此处描述的模式来实现所需的效果。建议使用以下单行代码(从链接到的帖子更新到 Python 3.8)使用以下方法为整个树创建子到父映射xml.etree.ElementTree.Element.iter

parent_map = {c: p for p in tree.iter() for c in p}
于 2010-01-31T08:04:25.593 回答
30

Vinay 的答案应该仍然有效,但对于 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
于 2013-11-21T21:31:37.460 回答
22

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

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

xml.findall('.//child[@id="123"]...')
>> [<Element 'parent'>]
于 2015-10-22T12:18:20.943 回答
9

使用 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>

于 2015-11-24T22:19:25.007 回答
5

在此处粘贴我来自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())
于 2019-03-01T11:46:52.770 回答
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

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

于 2018-07-04T07:56:12.977 回答
2

得到了答复

https://towardsdatascience.com/processing-xml-in-python-elementtree-c8992941efd2

提示:在 XPath 中使用“...”返回当前元素的父元素。


for object_book in root.findall('.//*[@name="The Hunger Games"]...'):
    print(object_book)
于 2021-01-03T21:27:52.303 回答
1

如果您使用的是 lxml,我可以通过以下方式获取父元素:

parent_node = next(child_node.iterancestors())

StopIteration如果元素没有祖先,这将引发异常 - 因此,如果您可能遇到这种情况,请准备好捕捉它。

于 2014-12-04T04:04:37.947 回答
-1

如果只想要单个子元素的父元素并且还知道子元素的 xpath,则另一种方法。

parentElement = subElement.find(xpath+"/..")
于 2014-02-23T02:41:36.057 回答
-2

查看 19.7.2.2。部分:支持的 XPath 语法...

使用路径查找节点的父节点:

parent_node = node.find('..')
于 2017-12-13T23:29:22.220 回答