使用 Python 3 基于列表删除 LXML 元素树
LXML element tree removal based on list using Python 3
使用 LXML,我希望打开一个现有的 XML 文件,根据设备列表的匹配删除一些 <device>
元素树并保存编辑后的内容XML 相同文件名下。
这是现有的XML内容:
<testsetup>
<devices>
<device>
<name>DEVICE1</name>
<id>SomeID</id>
<keyitem>
<file1>/some/file/path</file1>
<file2>/some/file/path</file2>
</keyitem>
</device>
<device>
<name>DEVICE2</name>
<id>SomeID</id>
<keyitem>
<file1>/some/file/path</file1>
<file2>/some/file/path</file2>
</keyitem>
</device>
<device>
<name>DEVICE3</name>
<id>SomeID</id>
<keyitem>
<file1>/some/file/path</file1>
<file2>/some/file/path</file2>
</keyitem>
</device>
<device>
<name>DEVICE4</name>
<id>SomeID</id>
<keyitem>
<file1>/some/file/path</file1>
<file2>/some/file/path</file2>
</keyitem>
</device>
</devices>
</testsetup>
我有一个需要删除的设备列表:
remove_items = ['DEVICE1', 'DEVICE3']
我希望在输出文件中打印出以下内容:
<testsetup>
<devices>
<device>
<name>DEVICE2</name>
<id>SomeID</id>
<keyitem>
<file1>/some/file/path</file1>
<file2>/some/file/path</file2>
</keyitem>
</device>
<device>
<name>DEVICE4</name>
<id>SomeID</id>
<keyitem>
<file1>/some/file/path</file1>
<file2>/some/file/path</file2>
</keyitem>
</device>
</devices>
</testsetup>
下面是我糊涂的尝试:
import lxml.etree as et
remove_items = ['DEVICE1', 'DEVICE3']
with open('somefile.xml', 'w+', newline='') as out_file:
root = et.parse(out_file)
for dev in remove_items:
for elem in root.xpath(".//device/@name='"+dev+"'"):
elem.getparent().remove(elem)
但我可能走错了路。我怎样才能正确地做到这一点?
您就快完成了,您只需要做几件事就可以使您的代码正常工作:
- 以
read
('r'
) 的方式打开文件并在打开它进行写入之前存储它的内容 ('w+'
)
- 对于 select 有一个
<name>
等于 'DEVICE1'
的 <device>
,使用这个 xpath:.//device[name='DEVICE1']
- 处理完树后,在根上使用
lxml.etree.tostring
获取与树等效的 XML 字符串。
这是应用上述修改后的有效解决方案:
from lxml.etree import parse, tostring
remove_items = ['DEVICE1', 'DEVICE3']
file_name = 'somefile.xml'
with open(file_name, 'r') as in_file:
root = parse(in_file)
for dev in remove_items:
for elem in root.xpath(".//device[name='" + dev + "']"):
elem.getparent().remove(elem)
with open(file_name, 'w+') as out_file:
out_file.write(tostring(root).decode())
解决方案是:
import lxml.etree as et
remove_items = ['DEVICE1', 'DEVICE3']
with open('test1.xml', 'r') as reader, open('test2.xml', 'w') as writer:
tree = et.parse(reader)
devices = tree.getroot().find('devices')
for element in devices.iter('device'):
if element.findtext('name') in remove_items:
print(element.findtext('name'))
devices.remove(element)
writer.write(et.tostring(devices, pretty_print = True).decode('utf-8'))
使用 LXML,我希望打开一个现有的 XML 文件,根据设备列表的匹配删除一些 <device>
元素树并保存编辑后的内容XML 相同文件名下。
这是现有的XML内容:
<testsetup>
<devices>
<device>
<name>DEVICE1</name>
<id>SomeID</id>
<keyitem>
<file1>/some/file/path</file1>
<file2>/some/file/path</file2>
</keyitem>
</device>
<device>
<name>DEVICE2</name>
<id>SomeID</id>
<keyitem>
<file1>/some/file/path</file1>
<file2>/some/file/path</file2>
</keyitem>
</device>
<device>
<name>DEVICE3</name>
<id>SomeID</id>
<keyitem>
<file1>/some/file/path</file1>
<file2>/some/file/path</file2>
</keyitem>
</device>
<device>
<name>DEVICE4</name>
<id>SomeID</id>
<keyitem>
<file1>/some/file/path</file1>
<file2>/some/file/path</file2>
</keyitem>
</device>
</devices>
</testsetup>
我有一个需要删除的设备列表:
remove_items = ['DEVICE1', 'DEVICE3']
我希望在输出文件中打印出以下内容:
<testsetup>
<devices>
<device>
<name>DEVICE2</name>
<id>SomeID</id>
<keyitem>
<file1>/some/file/path</file1>
<file2>/some/file/path</file2>
</keyitem>
</device>
<device>
<name>DEVICE4</name>
<id>SomeID</id>
<keyitem>
<file1>/some/file/path</file1>
<file2>/some/file/path</file2>
</keyitem>
</device>
</devices>
</testsetup>
下面是我糊涂的尝试:
import lxml.etree as et
remove_items = ['DEVICE1', 'DEVICE3']
with open('somefile.xml', 'w+', newline='') as out_file:
root = et.parse(out_file)
for dev in remove_items:
for elem in root.xpath(".//device/@name='"+dev+"'"):
elem.getparent().remove(elem)
但我可能走错了路。我怎样才能正确地做到这一点?
您就快完成了,您只需要做几件事就可以使您的代码正常工作:
- 以
read
('r'
) 的方式打开文件并在打开它进行写入之前存储它的内容 ('w+'
) - 对于 select 有一个
<name>
等于'DEVICE1'
的<device>
,使用这个 xpath:.//device[name='DEVICE1']
- 处理完树后,在根上使用
lxml.etree.tostring
获取与树等效的 XML 字符串。
这是应用上述修改后的有效解决方案:
from lxml.etree import parse, tostring
remove_items = ['DEVICE1', 'DEVICE3']
file_name = 'somefile.xml'
with open(file_name, 'r') as in_file:
root = parse(in_file)
for dev in remove_items:
for elem in root.xpath(".//device[name='" + dev + "']"):
elem.getparent().remove(elem)
with open(file_name, 'w+') as out_file:
out_file.write(tostring(root).decode())
解决方案是:
import lxml.etree as et
remove_items = ['DEVICE1', 'DEVICE3']
with open('test1.xml', 'r') as reader, open('test2.xml', 'w') as writer:
tree = et.parse(reader)
devices = tree.getroot().find('devices')
for element in devices.iter('device'):
if element.findtext('name') in remove_items:
print(element.findtext('name'))
devices.remove(element)
writer.write(et.tostring(devices, pretty_print = True).decode('utf-8'))