如何删除重复的节点xml Python

时间:2015-08-10 07:43:33

标签: python xml parsing

我有一个特殊情况xml文件结构类似于:

<Root>
    <parent1>
         <parent2>
             <element id="Something" >
         </parent2>
     </parent1>
     <parent1>
         <element id="Something">
     </parent1>
</Root>

我的用例是删除重复的元素,我想删除具有相同Id的元素。我尝试了以下代码,没有任何积极的结果(它没有找到重复的节点)

import xml.etree.ElementTree as ET

path = 'old.xml'

tree = ET.parse(path)
root = tree.getroot()
prev = None

def elements_equal(e1, e2):
    if type(e1) != type(e2):
        return False
    if e1.tag != e1.tag: return False
    if e1.text != e2.text: return False
    if e1.tail != e2.tail: return False
    if e1.attrib != e2.attrib: return False
    if len(e1) != len(e2): return False
    return all([elements_equal(c1, c2) for c1, c2 in zip(e1, e2)])

for page in root:                     # iterate over pages
elems_to_remove = []
for elem in page:
   for insideelem in page:
       if elements_equal(elem, insideelem) and elem != insideelem:
           print("found duplicate: %s" % insideelem.text)   # equal function works well
           elems_to_remove.append(insideelem)
           continue

for elem_to_remove in elems_to_remove:
    page.remove(elem_to_remove)
# [...]
tree.write("out.xml")

有人可以帮助我让我知道如何解决它。我对python很新,几乎没有经验。

1 个答案:

答案 0 :(得分:1)

首先,您所做的是您正在使用的库中的一个难题,请参阅此问题:How to remove a node inside an iterator in python xml.etree.ElemenTree

解决方法是使用lxml“实现相同的API但具有其他增强功能”。然后你可以做以下修复。

您似乎只遍历XML树中的第二级节点。你得到root,然后带着孩子走路。这样您就可以从第一页获得parent2,从第二页获得element。此外,你不会在这里比较各页:

您的比较只会在同一页面中找到第二级重复项。

使用适当的遍历功能(例如iter

)选择正确的元素集
# Use a `set` to keep track of "visited" elements with good lookup time.
visited = set()
# The iter method does a recursive traversal
for el in root.iter('element'):
    # Since the id is what defines a duplicate for you
    if 'id' in el.attr:
        current = el.get('id')
        # In visited already means it's a duplicate, remove it
        if current in visited:
            el.getparent().remove(el)
        # Otherwise mark this ID as "visited"
        else:
            visited.add(current)