如何在Python ElementTree中获取元素的所有祖先列表?

2 投票
3 回答
4022 浏览
提问于 2025-04-15 23:58

我需要一个叫“get_ancestors_recursively”的函数。
一个示例运行可以是:

>>> dump(tr)
<anc1>
  <anc2>
    <element> </element>
  </anc2>
</anc1>
>>> input_element = tr.getiterator("element")[0]
>>> get_ancestors_recursively(input_element)
['anc1', 'anc2']

有人能帮我吗?

3 个回答

0

经过大量搜索,我发现了这个小宝贝(http://elmpowered.skawaii.net/?p=74

parent = root.findall(".//{0}/..".format(elem.tag))

这里的root是你树形结构的根节点。elem是你在遍历时得到的实际元素对象。

这需要你知道根节点是什么,这可能意味着你需要稍微调整一下XML解析的设置,但这只是小事而已。

3

另一个选择是 LXML,它为内置的 ElementTree API 提供了一些实用的扩展。如果你愿意安装一个外部模块,它有一个很不错的 Element.getparent() 函数,你可以简单地递归调用这个函数,直到找到 ElementTree.getroot()。这可能是最快和最优雅的解决方案,因为 lxml.etree module 引入了指向父元素的指针属性,这样就不需要在整个树中搜索合适的 parent/child 配对了。

2

在最新版本的ElementTree(v1.3或更高版本)中,你可以简单地这样做

input_element.find('..')

以递归的方式。不过,Python自带的ElementTree并没有这个功能,我也没看到Element类里有什么可以向上查找的东西。

我认为这意味着你得走一些弯路:通过对元素树进行全面搜索。

def get_ancestors_recursively(e, b):
    "Finds ancestors of b in the element tree e."
    return _get_ancestors_recursively(e.getroot(), b, [])

def _get_ancestors_recursively(s, b, acc):
    "Recursive variant. acc is the built-up list of ancestors so far."
    if s == b:
        return acc
    else:
        for child in s.getchildren():
            newacc = acc[:]
            newacc.append(s)
            res = _get_ancestors_recursively(child, b, newacc)
            if res is not None:
                return res
        return None

这样做会比较慢,因为它使用了深度优先搜索(DFS),而且会产生很多列表需要进行垃圾回收,但如果你能接受这些,应该就没问题。

撰写回答