必须显式指定encoding="utf-8"并设置xml_declaration=true,否则xml文件无编码声明,windows记事本等工具误判为gbk导致中文显示为问号或方块。

写入XML时中文变成问号或方块,根本原因是编码没指定
Python 3 默认用 UTF-8,但 xml.etree.ElementTree 的 write() 方法默认不写 BOM、也不显式声明编码,如果用记事本等工具打开,容易误判为 ANSI(如 GBK),导致中文显示为乱码。这不是解析失败,是「保存格式」和「查看方式」错配。
- 必须显式传入
encoding="utf-8"参数给write() - 必须在 XML 声明中体现编码,即开头要有
<?xml version="1.0" encoding="utf-8"?> - 如果用
open()手动写入,文件句柄也得用encoding="utf-8",否则write()写进去的仍是字节流乱码
tree.write() 必须带 encoding 和 xml_declaration=True
write() 不加参数时默认用 ASCII 编码写入,中文直接报错或静默丢弃。即使你用 UTF-8 打开文件,没声明 encoding 就等于没告诉 XML 解析器“这串字节该按 UTF-8 解”,外部工具(比如浏览器、IE、旧版记事本)会瞎猜。
- 正确调用:
tree.write("out.xml", encoding="utf-8", xml_declaration=True) - 漏掉
xml_declaration=True→ 没有<?xml ...?>行,部分工具无法识别编码 - 只写
encoding="utf-8"但不写xml_declaration=True→ 文件内容是 UTF-8 字节,但没声明,等于“穿了衣服不挂牌” - Windows 记事本尤其依赖这一行才能正确加载 UTF-8 中文
用 open() + write() 时,文件打开模式不能用 "w" 简单替代
有人想绕过 write(),改用 open("x.xml", "w").write(tree.tostring(...).decode()),这非常危险:一旦节点含特殊字符(如 &、),<code>tostring() 返回的是已转义的字节,直接 decode 再 write 容易二次转义或解码失败。
- 不要手动 decode / encode
tostring()结果 —— 它返回bytes,应直接用二进制模式写入 - 安全写法:
with open("out.xml", "wb") as f: f.write(etree.tostring(tree, encoding="utf-8", xml_declaration=True)) - 注意:这里
encoding="utf-8"是给tostring()用的,不是给open()的;open()必须是"wb",否则文本模式会尝试按系统默认编码再编码一次
ElementTree 对中文属性值和文本内容本身无限制,乱码只出在 IO 环节
很多人以为 Element.text = "你好" 会出问题,其实不会。ElementTree 内部全用 Unicode 字符串,中文赋值完全正常。所有乱码都发生在「从内存写到磁盘」这一步,和解析、构建、查找完全无关。
立即学习“Python免费学习笔记(深入)”;
- 确认乱码是否真存在:用
cat out.xml(Linux/macOS)或type out.xml(Windows PowerShell)看原始字节,比记事本更可信 - 如果终端能正常显示中文,但记事本打不开 → 几乎肯定是缺
xml_declaration=True - 如果连
cat都显示 或空格 → 写入时用了错误的 encoding(比如写成了gbk)或 open 模式错了









