如何使用一个循环删除多个 XML 元素?
How to delete multiple XML elements using one loop?
我的文件中有一些 XML 数据。我的代码读取它,我想在稍后在代码中使用数据之前从中删除不需要的元素。我有一个不需要的名称列表,我需要删除特定层次结构位置的所有节点,其属性 name
是不需要的。
我使用循环 for child_element in parent_element:
,在循环内我删除了所有符合条件的子元素:parent_element.remove(child_element)
。问题是,当它删除任何子元素时,它会打乱迭代,跳过对下一个子元素的检查。
为了解决这个问题,我添加了一个丑陋的补丁 - 我 运行 一次又一次地循环删除,直到找不到要删除的内容。
import xml.etree.ElementTree as ET
...
names_to_delete = ['bad1', 'bad2']
tree = ET.parse(...)
parent_element = tree.getroot()[0][0]
try_delete_name = True
while try_delete_name: # try deleting again and again, until nothing to delete
try_delete_name = False
for child_element in parent_element:
assert 'name' in child_element.attrib
if child_element.attrib['name'] in names_to_delete:
parent_element.remove(child_element)
try_delete_name = True
示例XML数据:
<root>
<whatever>
<parent>
<child name="x">
<value>99</value>
</child>
<child name="bad2">
<value>222</value>
</child>
<child name="y">
<value>88</value>
</child>
<child name="bad1">
<value>666</value>
</child>
</parent>
</whatever>
</root>
我怎样才能只使用一次遍历子元素来实现这个?
这应该可以解决问题:
import xml.etree.ElementTree as ET
names_to_delete = ['bad1', 'bad2']
tree = ET.parse("example.xml")
parent_element = tree.getroot()[0][0]
for child in list(parent_element):
if child.attrib["name"] in names_to_delete:
parent_element.remove(child)
list(parent_elment) returns children.
只是添加到@Christian 的回答中,另一个选项是 lxml:
from lxml import etree
unclean = """[your xml]"""
doc = etree.XML(unclean)
targets = doc.xpath('//parent//child')
for target in targets:
if target.xpath('./@name')[0] in names_to_delete:
target.getparent().remove(target)
print(etree.tostring(doc).decode())
输出:
<root>
<whatever>
<parent>
<child name="x">
<value>99</value>
</child>
<child name="y">
<value>88</value>
</child>
</parent>
</whatever>
</root>
我的文件中有一些 XML 数据。我的代码读取它,我想在稍后在代码中使用数据之前从中删除不需要的元素。我有一个不需要的名称列表,我需要删除特定层次结构位置的所有节点,其属性 name
是不需要的。
我使用循环 for child_element in parent_element:
,在循环内我删除了所有符合条件的子元素:parent_element.remove(child_element)
。问题是,当它删除任何子元素时,它会打乱迭代,跳过对下一个子元素的检查。
为了解决这个问题,我添加了一个丑陋的补丁 - 我 运行 一次又一次地循环删除,直到找不到要删除的内容。
import xml.etree.ElementTree as ET
...
names_to_delete = ['bad1', 'bad2']
tree = ET.parse(...)
parent_element = tree.getroot()[0][0]
try_delete_name = True
while try_delete_name: # try deleting again and again, until nothing to delete
try_delete_name = False
for child_element in parent_element:
assert 'name' in child_element.attrib
if child_element.attrib['name'] in names_to_delete:
parent_element.remove(child_element)
try_delete_name = True
示例XML数据:
<root>
<whatever>
<parent>
<child name="x">
<value>99</value>
</child>
<child name="bad2">
<value>222</value>
</child>
<child name="y">
<value>88</value>
</child>
<child name="bad1">
<value>666</value>
</child>
</parent>
</whatever>
</root>
我怎样才能只使用一次遍历子元素来实现这个?
这应该可以解决问题:
import xml.etree.ElementTree as ET
names_to_delete = ['bad1', 'bad2']
tree = ET.parse("example.xml")
parent_element = tree.getroot()[0][0]
for child in list(parent_element):
if child.attrib["name"] in names_to_delete:
parent_element.remove(child)
list(parent_elment) returns children.
只是添加到@Christian 的回答中,另一个选项是 lxml:
from lxml import etree
unclean = """[your xml]"""
doc = etree.XML(unclean)
targets = doc.xpath('//parent//child')
for target in targets:
if target.xpath('./@name')[0] in names_to_delete:
target.getparent().remove(target)
print(etree.tostring(doc).decode())
输出:
<root>
<whatever>
<parent>
<child name="x">
<value>99</value>
</child>
<child name="y">
<value>88</value>
</child>
</parent>
</whatever>
</root>