【问题标题】:How to delete multiple XML elements using one loop?如何使用一个循环删除多个 XML 元素?
【发布时间】:2020-06-07 12:17:07
【问题描述】:

我在一个文件中有一些 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>

我怎样才能只使用一次通过子元素来实现这一点?

【问题讨论】:

  • 您的 XML 有问题:child 的结束标签和param 的开始标签在哪里?
  • 使用 XSLT(在 Pythin 的 lxml 模块或外部处理器中可用)您不需要任何循环。
  • @JackFleeting 我发布了我的真实 XML 文件的编辑版本;试图使名称更具表现力,但忘记更改所有名称。

标签: python elementtree


【解决方案1】:

这应该可以解决问题:

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) 返回子元素。

【讨论】:

    【解决方案2】:

    只是添加到@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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      • 2019-08-14
      • 2022-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多