使用 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)

但我可能走错了路。我怎样才能正确地做到这一点?

您就快完成了,您只需要做几件事就可以使您的代码正常工作:

  1. read ('r') 的方式打开文件并在打开它进行写入之前存储它的内容 ('w+')
  2. 对于 select 有一个 <name> 等于 'DEVICE1'<device>,使用这个 xpath:.//device[name='DEVICE1']
  3. 处理完树后,在根上使用 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'))