【问题标题】:access ElementTree node parent node访问 ElementTree 节点父节点
【发布时间】:2011-01-11 08:28:39
【问题描述】:

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

【问题讨论】:

标签: python elementtree


【解决方案1】:

得到了答复

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

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


for object_book in root.findall('.//*[@name="The Hunger Games"]...'):
    print(object_book)

【讨论】:

【解决方案2】:

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

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

【讨论】:

  • 语法更新,2017 / python3 parent_map = {(c,p) for p in tree.iter( ) for c in p}
  • 更正:parent_map = {c:p for p in root.iter( ) for c in p}
  • 如果不能一次性读取整个 XML 文件,而必须使用 iter() 遍历文件怎么办?
【解决方案3】:

在这里粘贴我来自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())

【讨论】:

    【解决方案4】:

    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
    

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

    【讨论】:

      【解决方案5】:

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

      parent_node = next(child_node.iterancestors())
      

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

      【讨论】:

        【解决方案6】:

        看看 19.7.2.2。部分:Supported XPath syntax ...

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

        parent_node = node.find('..')
        

        【讨论】:

        • 你测试过这个吗?如果您能够使其工作,请发布一个完整的代码示例来演示它。看到这条评论:stackoverflow.com/questions/2170610/…
        • Python 3 文档说:“如果路径试图到达起始元素的祖先(元素 find 被调用),则返回 None。” (docs.python.org/3/library/…)。
        • 为我工作。最好和最简洁的答案。
        【解决方案7】:

        Get parent element after using find method (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/../..')&lt;Element 'a' at 0x00XXXXXX&gt;

        【讨论】:

          【解决方案8】:

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

          <parent>
               <child id="123">data1</child>
          </parent>
          
          xml.findall('.//child[@id="123"]...')
          >> [<Element 'parent'>]
          

          【讨论】:

          • 这是一个很棒的解决方案,如果你知道你只需要一个元素,它也可以与 find() 一起使用。像这样:root.find(".//*[@testname='generated_sql']...")
          • 我找不到关于这个... XPath 语法的任何信息。它有什么作用?上面有文档吗?
          • @raphinesse ... 表达式来自 XPath 1.0。 Python Std Library 对 XPath 表达式的支持有限,lxml 支持更多。
          • 答案中的代码确实有效,但我在任何地方都找不到对这种“三点”语法的任何引用。 XPath 1.0 建议中没有提到它。
          • @ioannis-filippidis 哦,您只需要一个有效的 XPath 后跟一个 ... 您可以使用任何属性 所有子项:xml.findall('.//child...') 其他一些属性:xml.findall('.//child[@other="123"]...')
          【解决方案9】:

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

          parentElement = subElement.find(xpath+"/..")
          

          【讨论】:

          • 对我不起作用,我得到“无” - 如果我只使用 subElement.find('..') 也是一样。
          • 假设一个名为xpath的变量已经存在,所以它对大多数人没有帮助。
          【解决方案10】:

          Vinay's answer 应该仍然可以工作,但对于 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
          

          【讨论】:

          • 如果您无法访问树怎么办?就像在 .find() 之后
          • 如果您没有保存对根节点的引用,我不知道有任何方法可以获取根节点(以及父节点/祖先节点)。但我不明白.find() 与此有何关系。
          • 我只是用.find()作为一个示例函数,它只返回一个元素
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-07
          • 1970-01-01
          • 2019-01-21
          • 2019-03-08
          • 1970-01-01
          相关资源
          最近更新 更多