Python:xml ElementTree(或lxml)中的命名空间

10 投票
2 回答
31317 浏览
提问于 2025-04-16 11:09

我想要读取一个旧的xml文件,对它进行处理然后保存。

这是我的代码:

from xml.etree import cElementTree as ET
NS = "{http://www.somedomain.com/XI/Traffic/10}"

def fix_xml(filename):
    f = ET.parse(filename)
    root = f.getroot()
    eventlist = root.findall("%(ns)Event" % {'ns':NS })
    xpath = "%(ns)sEventDetail/%(ns)sEventDescription" % {'ns':NS }
    for event in eventlist:
        desc = event.find(xpath)
        desc.text = desc.text.upper() # do some editting to the text.

    ET.ElementTree(root, nsmap=NS).write("out.xml", encoding="utf-8")


shorten_xml("test.xml")

我加载的文件内容是:

xmlns="http://www.somedomain.com/XI/Traffic/10"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.somedomain.com/XI/Traffic/10 10.xds"

在根标签下。

我遇到了以下与命名空间有关的问题:

  • 如你所见,每次调用标签时,我都需要在前面加上命名空间才能获取子标签。
  • 生成的xml文件开头没有 <?xml version="1.0" encoding="utf-8"?>
  • 输出的标签像 <ns0:eventDescription>,而我希望输出的是原始的 <eventDescription>,也就是开头没有命名空间。

这些问题该怎么解决呢?

2 个回答

1

为了回答你的问题,我来逐条解释:

  • 你不能忽视命名空间。在使用 .findall() 的路径语法中是这样,使用“真实”的 xpath(lxml 支持的)也是一样:在那种情况下,你仍然需要使用一个前缀,并且还需要提供前缀和 URI 的映射关系。

  • 在调用 .write() 时,记得使用 xml_declaration=Trueencoding='utf-8'(在 lxml 中可用,但在标准库的 xml.etree 中从 Python 2.7 开始才有这个功能)。

  • 我相信 lxml 会按照你想要的方式工作。

10

你可以看看这个关于命名空间的lxml教程,还有这篇关于ElementTree中命名空间的文章

问题1:就像大家一样,忍耐一下吧。与其用 "%(ns)Event" % {'ns':NS },不如试试 NS+"Event"

问题2:默认情况下,只有在需要的时候才会写XML声明。如果你想强制写入(只有在lxml中),可以在你的 write() 调用中加上 xml_declaration=True

问题3:nsmap 参数似乎是lxml特有的。根据我的理解,它需要一个映射,而不是一个字符串。你可以试试 nsmap={None: NS}。effbot的文章中有一部分讲了这个问题的解决方法。

撰写回答