【问题标题】:Python remove duplicate elements from xml treePython从xml树中删除重复元素
【发布时间】:2014-12-18 15:08:46
【问题描述】:

我有一个 xml 结构,其中包含一些不是唯一的元素。因此,我设法对子树进行了排序,并且可以过滤出不止一次的元素。但是删除功能似乎不适用。

我的 XML 结构看起来像这样简化:

<root>
  <page>
    <text>blabla blub unique</text>
    <text>blabla blub not unique</text>
    <text>blabla blub not unique</text><!-- line should be removed -->
    <text>blabla blub not unique</text><!-- line should be removed -->
    <text>blabla blub not unique</text><!-- line should be removed -->
    <text>blabla blub again unique</text>
  </page>
  <page>
    <text>2nd blabla blub unique</text>
    <text>2nd blabla blub not unique</text>
    <text>2nd blabla blub not unique</text><!-- line should be removed -->
    <text>2nd blabla blub again unique</text>
  </page>
</root>

我想删除每个页面上的双字符串,所以我在两个 for 循环中遍历页面和页面中的元素:(提取重要行,我希望没有忘记任何内容)

import xml.etree.ElementTree as ET
self.tree = ET.parse(path)
self.root = self.tree.getroot()
self.prev = None
# [...]
for page in self.root:                     # iterate over pages
    for elem in page:
        if elements_equal(elem, self.prev):
            print("found duplicate: %s" % elem.text)   # equal function works well
            page.remove(elem) # <---- removes just one line
            continue
        self.prev = elem
# [...]
self.tree.write("out.xml") # 2 duplicate lines still there....

更新:代码似乎可以工作,但它只删除了一个重复项,而不是全部

【问题讨论】:

  • 你试过用 root.remove(elem) 代替 page 吗?
  • 我认为这是一个列表;如果是这样,请尝试将其设置为一组并查看是否删除了重复项。我想它归结为如何为节点实现 eq 方法,如果有的话
  • 它应该是 xmlTree 对象的一个​​元素,但我不知道它是如何实现的。当我尝试从根目录中删除时,它说:ValueError: list.remove(x): x not in list
  • 如何制作成一套? eq方法是什么意思? @omu_negru
  • 好吧,只要做 set(your_list) 或任何迭代器就可以了。要检查 eq 方法是否正确实现,获取第二个和第三个节点并查看 second == third 是否返回 true(应该)

标签: python xml


【解决方案1】:

我不知道你如何定义elements_equal,但是(无耻地改编自Testing Equivalence of xml.etree.ElementTree)这对我有用:

编辑:在迭代 page 时存储要删除的每个元素的列表,然后删除它们,而不是在一个循环中进行删除。

编辑:在元素标签的比较中注意到代码中的一个小错字并更正它。

import xml.etree.ElementTree as ET

path = 'in.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 != e2.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:
        if elements_equal(elem, prev):
            print("found duplicate: %s" % elem.text)   # equal function works well
            elems_to_remove.append(elem)
            continue
        prev = elem
    for elem_to_remove in elems_to_remove:
        page.remove(elem_to_remove)
# [...]
tree.write("out.xml")

给予:

$ python undupe.py
found duplicate: blabla blub not unique
found duplicate: 2nd blabla blub not unique
$ cat out.xml
<root>
  <page>
    <text>blabla blub unique</text>
    <text>blabla blub not unique</text>
    <text>blabla blub again unique</text>
  </page>
  <page>
    <text>2nd blabla blub unique</text>
    <text>2nd blabla blub not unique</text>
    <text>2nd blabla blub again unique</text>
  </page>

【讨论】:

  • Equals 函数正常工作,这不是问题。但我也有类似的,谢谢。
  • @abimelex:那么我对您的问题还有一些不明白的地方。我已经发布了我的完整工作代码以防万一。
  • 哈哈好吧,我想错了方向……程序可以工作,你的代码也可以用这个例子。当我们不只有两个独特的元素时,问题就出现在我的示例中。像4次一样排。这两个代码都没有删除所有重复项......不知道为什么......@xnx 更新了我的问题
  • 啊,是的 - 它不起作用,因为您(我们)在迭代中删除了 text 元素,而不是 page 的子元素。这不起作用,因为删除元素会使迭代过早停止
  • 哦,好吧...我不明白行为原因,但我想出了一个解决方案...我将编辑您的答案,然后在您可以接受的情况下接受它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-21
  • 1970-01-01
  • 1970-01-01
  • 2010-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多