【问题标题】:How to remove a specific tag that could be empty in an xml file如何删除 xml 文件中可能为空的特定标签
【发布时间】:2019-06-03 12:14:36
【问题描述】:

我正在尝试从 xml 文件中删除特定标签,但前提是它为空。

文件:

<?xml version="1.0" encoding="utf-8"?>
<parent>
  <child>
    <value1>Foo<value1/>
    <value2>Bar<value2/>
    <value3>Hello World<value3/>
    <value3/>
    <value3/>
    <value3/>
  <child/>
<parent/>

预期输出:

<?xml version="1.0" encoding="utf-8"?>
<parent>
  <child>
    <value1>Foo<value1/>
    <value2>Bar<value2/>
    <value3>Hello World<value3/>
  <child/>
<parent/>

我在读取文件和使用 lxml 解析它时遇到问题,因此我对任何其他 python3 方法/模块持开放态度。 理想情况下希望代码执行以下操作:

def remove_empty_tag(tag=tagname, file=data):
   ...

data = open("file.xml").read()
new_xml = remove_empty_tag(tag="value3", data)
print(new_xml)

但愿意寻求任何帮助,甚至是方向。

【问题讨论】:

标签: xml python-3.x tags lxml is-empty


【解决方案1】:

您不需要open() 来读取或写入文件;使用lxml的parse()解析文件,使用write()写新的。

您还应该能够使用 self:: xpath 轴而不是 python if 来检查标签名称。

示例...

XML 输入 (old.xml)

<parent>
  <child>
    <value1>Foo</value1>
    <value2>Bar</value2>
    <value3>Hello World</value3>
    <value3/>
    <value3/>
    <value3/>
  </child>
</parent>

Python

from lxml import etree


def remove_empty_tag(tag, original_file, new_file):
    root = etree.parse(original_file)
    for element in root.xpath(f".//*[self::{tag} and not(node())]"):
        element.getparent().remove(element)

    # Serialize "root" and create a new tree using an XMLParser to clean up
    # formatting caused by removing elements.
    parser = etree.XMLParser(remove_blank_text=True)
    tree = etree.fromstring(etree.tostring(root), parser=parser)
    # Write to new file.
    etree.ElementTree(tree).write(new_file, pretty_print=True, xml_declaration=True, encoding="utf-8")


remove_empty_tag("value3", "old.xml", "new.xml")

XML 输出 (new.xml)

<?xml version='1.0' encoding='UTF-8'?>
<parent>
  <child>
    <value1>Foo</value1>
    <value2>Bar</value2>
    <value3>Hello World</value3>
  </child>
</parent>

注意:序列化和创建新树并不是绝对必要的。你可以这样做:

root.write(new_file, pretty_print=True, xml_declaration=True, encoding="utf-8")

但输出的格式会略有不同(注意child结束标记的额外缩进:

<?xml version='1.0' encoding='UTF-8'?>
<parent>
  <child>
    <value1>Foo</value1>
    <value2>Bar</value2>
    <value3>Hello World</value3>
    </child>
</parent>

【讨论】:

  • 谢谢。与我自己的答案相比,这是一种更清洁的做事方式。两者都取得了相同的结果。
【解决方案2】:
from lxml import etree


def remove_empty_tag(tag, original_file, new_file):
    file = open(original_file, 'r', encoding='utf8').read()
    root = etree.fromstring(file)
    for element in root.xpath(".//*[not(node())]"):
        if element.tag == tag:
            element.getparent().remove(element)
    with open(new_file, 'wb') as f:
        f.write(etree.tostring(root, pretty_print=True))


remove_empty_tag("value3", "old.xml", "new.xml")

这就是我想要实现的目标,由于某种原因,如果文件/数据中有&lt;?xml version="1.0" encoding="utf-8"?&gt;,它会抱怨文件/数据。所以只需将其删除即可修复。不是真正的重复,因为来自另一个线程的答案没有指定如何只删除特定的空标签,也没有说明它实际上在做什么,或者如何将它写入一个没有随机'\ n'的新文件......

【讨论】:

  • “抱怨”是什么意思?您收到的实际错误/警告消息是什么?您不必删除 XML 声明即可使其正常工作。 (不过,您的示例 XML 格式不正确,因为您的结束标签都错了;需要先修复这些。)
  • 我给出的例子是不正确的,是的,因为我试图用一个快速的虚拟数据来展示我想要实现的目标。在询问这个平台的问题时,我不想使用私人数据。我在 xml 的第一行中不断收到的消息是 ValueError: Unicode strings with encoding declaration are not supported.,我只是在处理它之前将其删除并将其放回(不是手动,而是通过一些字符串操作)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-28
  • 1970-01-01
  • 2020-09-02
相关资源
最近更新 更多