xml.etree.ElementTree.Element.remove 没有删除所有元素
xml.etree.ElementTree.Element.remove not removing all elements
请看下面代码:
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>'
我完全不理解这个。我也没有看到被删除的特定元素的任何模式。
文档仅仅说:
Removes subelement from the element. Unlike the find* methods this
method compares elements based on the instance identity, not on tag
value or contents.
我doing/assuming哪里错了?我在 Kubuntu Trusty 上使用 Python 2.7.5 和 3.4.0 得到的输出基本相同。
谢谢!
是的,获取根标签的所有子标签,并以相反的顺序一一删除
例如
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 />'
用你的代码只删除了一个元素。
例如
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>'
这说明了问题:
>>> 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 />'
这是可行的,因为循环执行时迭代器没有变化。
或者,如果要删除根元素 and 及其所有属性的所有子元素,可以使用 root.clear()
:
>>> root = ET.fromstring('<a href="blah"><b /><c><d /></c></a>')
>>> root.clear()
>>> ET.tostring(root)
b'<a />'
请看下面代码:
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>'
我完全不理解这个。我也没有看到被删除的特定元素的任何模式。
文档仅仅说:
Removes subelement from the element. Unlike the find* methods this method compares elements based on the instance identity, not on tag value or contents.
我doing/assuming哪里错了?我在 Kubuntu Trusty 上使用 Python 2.7.5 和 3.4.0 得到的输出基本相同。
谢谢!
是的,获取根标签的所有子标签,并以相反的顺序一一删除
例如
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 />'
用你的代码只删除了一个元素。 例如
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>'
这说明了问题:
>>> 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 />'
这是可行的,因为循环执行时迭代器没有变化。
或者,如果要删除根元素 and 及其所有属性的所有子元素,可以使用 root.clear()
:
>>> root = ET.fromstring('<a href="blah"><b /><c><d /></c></a>')
>>> root.clear()
>>> ET.tostring(root)
b'<a />'