【问题标题】:Remove a node from etree but leaving child从 etree 中删除一个节点但留下子节点
【发布时间】:2014-06-23 06:50:17
【问题描述】:

我正在遍历一棵 XML 树,但我从树中提取一个节点并留下它们的内部节点时遇到了一些麻烦。

例如:

<xml>
    <letter name="B">
        <letter name="D">
            <letter name="E">
                <letter name="F">
                    <letter name="G">

                    </letter>
                </letter>
            </letter>
        </letter>
    </letter>
</xml>

我需要这样的东西:

<xml>
    <letter name="B">
        <letter name="D">
                <letter name="F">
                    <letter name="G">

                    </letter>
                </letter>
        </letter>
    </letter>
</xml>

但如果不删除所有 E 孩子,我就无法做到这一点。

干杯!

【问题讨论】:

    标签: python xml elementtree


    【解决方案1】:

    这个想法是从父元素中找到带有name="E"get it's parentremove the elementletter 元素,并使用元素的子元素扩展父元素:

    import xml.etree.ElementTree as etree
    
    data = """
    <xml>
        <letter name="B">
            <letter name="D">
                <letter name="E">
                    <letter name="F">
                        <letter name="G">
    
                        </letter>
                    </letter>
                </letter>
            </letter>
        </letter>
    </xml>
    """
    
    XPATH = './/letter[@name="E"]'
    
    tree = etree.fromstring(data)
    letter = tree.find(XPATH)
    parent = tree.find(XPATH + '/..')
    
    parent.remove(letter)
    parent.extend(letter)
    
    print etree.tostring(tree)
    

    打印出来:

    <xml>
        <letter name="B">
            <letter name="D">
                <letter name="F">
                        <letter name="G">
    
                        </letter>
                    </letter>
                </letter>
        </letter>
    </xml>
    

    UPD(使用迭代方法):

    def iterparent(tree):
        for parent in tree.getiterator():
            for child in parent:
                yield parent, child
    
    tree = etree.fromstring(data)
    for parent, child in iterparent(tree):
        if child.tag == "letter" and child.attrib.get('name') == "E":
            parent.remove(child)
            parent.extend(child)
    
    print etree.tostring(tree)
    

    iterparent() 函数取自文档中的Accessing Parents 段落。

    【讨论】:

    • 我会使用parent.extend(letter) 而不是for child in letter.getchildren(): parent.append(child)
    • 实际上我找不到要删除的元素(确实很好),因为我需要做一些额外的验证,有时可能是“E”,有时是其他字母,在我的情况下需要做这样的事情: for elem in tree.iter(): if (elem.tag == "letter" and elem.attrib[name] == "E"): #save elem child #remove elem #append child to elem父母但我不能得到这个工作干杯!
    • @alecxe 我还有一些问题,我需要创建解决方案树,但我无法从原始树创建树。
    【解决方案2】:

    另一件事,

    有可能做这样的事情吗??

    初始 XML

    <xml>
        <letter name="B">
            <letter name="D">
                <letter name="E">
                    <letter name="F">
                        <letter name="G">
    
                        </letter>
                    </letter>
                </letter>
                <letter name="H">
                    <letter name="I">
    
                    </letter>
                </letter>
            </letter>
        </letter>
    </xml>
    

    然后输出一个包含两棵树的列表,如下所示:

    <xml>
        <letter name="B">
            <letter name="E">
                <letter name="F">
                    <letter name="G">
    
                    </letter>
                </letter>
            </letter>
        </letter>
    </xml>
    
    
    <xml>
        <letter name="B">
                <letter name="H">
                    <letter name="I">
    
                    </letter>
                </letter>
        </letter>
    </xml>
    

    正如你所看到的@falsetru 和@alecxe,我刚刚删除了 D 并且每棵树只留下一个孩子。

    谢谢!!!!

    【讨论】:

      【解决方案3】:

      我刚做完,我只需要在删除之前复制树,否则会修改原始对象..

      这里是解决方案。 顺便说一句!,非常感谢!!!!呵呵

      def remove_letter(tree_original, letter):
          tree= copy.deepcopy(tree_original)
          for parent in tree.getiterator():
              for child in parent:
                  if child.attrib.get('name') == letter:
                      parent.remove(child)
                      parent.extend(child)
                      print etree.tostring(parent)
                      return parent   
      
      def get_next_trees(tree):
          my_trees = []
          for parent in tree.getiterator():
              if child.attrib.get('name') == "D":
                  for child in parent:
                      my_trees.append(remove_letter(tree)
                  return my_trees 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-11
        • 1970-01-01
        • 1970-01-01
        • 2020-08-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多