You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python ElementTree往返转换(from/tostring)丢失命名空间问题

为什么XML解析后序列化丢失了未使用的命名空间?

这是因为Python标准库的xml.etree.ElementTree在序列化XML时,只会保留DOM树中实际被元素或属性引用的命名空间。你的基础XML里虽然声明了d和m命名空间,但没有任何元素或属性使用它们,所以tostring()方法会自动丢弃这些“冗余”的命名空间声明。

解决办法

方法一:用标准库手动保留命名空间

如果你必须使用标准库,可以通过注册命名空间前缀,并临时添加一个引用该命名空间的属性/元素,让序列化工具认为这个命名空间是被使用的:

import xml.etree.ElementTree as ET

BASE = """<?xml version="1.0" encoding="utf-8" ?>
<feed xml:base="https://www.nuget.org/api/v2/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" >
</feed>
"""

# 先注册对应的命名空间前缀,避免被自动改成ns0/ns1这类默认前缀
ET.register_namespace('', 'http://www.w3.org/2005/Atom')
ET.register_namespace('d', 'http://schemas.microsoft.com/ado/2007/08/dataservices')
ET.register_namespace('m', 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata')

root = ET.fromstring(BASE)

# 添加临时属性来引用d和m命名空间,确保序列化时保留声明
root.set('{http://schemas.microsoft.com/ado/2007/08/dataservices}temp', '')
root.set('{http://schemas.microsoft.com/ado/2007/08/dataservices/metadata}temp', '')

# 序列化XML
xml_str = ET.tostring(root, encoding='utf-8', xml_declaration=True).decode('utf-8')

# 如果不需要临时属性,可以手动移除(或者后续添加真实元素后再序列化)
xml_str = xml_str.replace(' d:temp=""', '').replace(' m:temp=""', '')
print(xml_str)

方法二:使用lxml库(更省心)

lxml库的XML序列化行为更贴近原始XML,会保留所有声明过的命名空间,哪怕暂时没被使用。如果你可以引入第三方库,这是更简单的方案:

from lxml import etree

BASE = """<?xml version="1.0" encoding="utf-8" ?>
<feed xml:base="https://www.nuget.org/api/v2/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" >
</feed>
"""

root = etree.fromstring(BASE)
# pretty_print=True可以让输出更美观,和原始格式接近
xml_str = etree.tostring(root, encoding='utf-8', xml_declaration=True, pretty_print=True).decode('utf-8')
print(xml_str)

补充说明

如果你的后续开发中会添加使用d或m命名空间的元素/属性,那其实不需要额外处理——当你把这些元素添加到DOM树后,再次调用tostring()时,对应的命名空间声明会自动被包含进去,因为此时它们不再是“冗余”的了。

内容的提问来源于stack exchange,提问作者dthor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:30:56