xml.etree.ElementTree.Element.remove不删除所有元素

时间:2015-06-16 06:01:11

标签: python xml elementtree

请参阅以下代码:

import xml.etree.ElementTree as ET
for x in ("<a><b /><c><d /></c></a>", "<a><q /><b /><c><d /></c></a>", "<a><m /><q /><b /><c><d /></c></a>"):
    root = ET.fromstring(x)
    for e in root: root.remove(e)
    print(ET.tostring(root))

我希望它能在所有实例中输出<a></a>,但它会给出:

b'<a><c><d /></c></a>'
b'<a><b /></a>'
b'<a><q /><c><d /></c></a>'

我完全不喜欢这个。我没有看到任何被移除的特定元素的模式。

文档只是说:

  

从元素中删除子元素。与find *方法不同   method比较基于实例标识的元素,而不是标记   价值或内容。

我在做什么/假设错了?我在Kubuntu Trusty上使用Python 2.7.5和3.4.0获得了基本相同的输出。

谢谢!

2 个答案:

答案 0 :(得分:3)

这表明了问题:

>>> root = ET.fromstring("<a><b /><c><d /></c></a>")
>>> for e in root:
...     print(e)
... 
<Element 'b' at 0x7f76c6d6cd18>
<Element 'c' at 0x7f76c6d6cd68>
>>> for e in root:
...     print(e)
...     root.remove(e)
...
<Element 'b' at 0x7f76c6d6cd18>

因此,修改正在迭代的对象会影响迭代。这并不完全出乎意料,如果在迭代时更改列表,它也是一样的:

>>> l = [1, 2, 3, 4]
>>> for i in l:
...     l.remove(i)
>>> print l
[2, 4]

作为一种解决方法,您可以重复删除第一个子元素,如下所示:

import xml.etree.ElementTree as ET
for x in ("<a><b /><c><d /></c></a>", "<a><q /><b /><c><d /></c></a>", "<a><m /><q /><b /><c><d /></c></a>"):
    root = ET.fromstring(x)
    for i in range(len(root)):
        root.remove(root[0])
    ET.tostring(root)

输出

b'<a />'
b'<a />'
b'<a />'

这是有效的,因为迭代器在执行循环时不会改变。  或者,如果要删除根元素 的所有子元素的所有属性,可以使用root.clear()

>>> root = ET.fromstring('<a href="blah"><b /><c><d /></c></a>')
>>> root.clear()
>>> ET.tostring(root)
b'<a />'

答案 1 :(得分:1)

是的,获取root标签的所有子项并按相反的顺序逐个删除

E.g。

In [1]: import xml.etree.ElementTree as ET 
In [2]: content = "<a><b /><c><d /></c></a>"
In [15]: root = ET.fromstring(content)
In [16]: for e in root.getchildren()[::-1]:
   ....:     print e
   ....:     root.remove(e)
   ....:     
<Element 'c' at 0xb60890ac>
<Element 'b' at 0xb608908c>

In [17]: ET.tostring(root)
Out[17]: '<a />'

使用您的代码只删除一个元素。 E.g。

In [21]: root = ET.fromstring(content)
In [22]: for e in root:
   ....:     print "Element:", e
   ....:     root.remove(e)
   ....:     
Element: <Element 'b' at 0xb608936c>

In [23]: ET.tostring(root)
Out[23]: '<a><c><d /></c></a>'

没有反向

In [45]: root = ET.fromstring(content)

In [46]: for e in root.getchildren():
   ....:     print "Elenment:", e
   ....:     root.remove(e)
   ....:     
Elenment: <Element 'b' at 0xb6219dcc>

In [47]: ET.tostring(root)
Out[47]: '<a>asas<c><d /></c></a>'