xmltodict.unparse()默认生成紧凑xml,需加pretty=true、indent和newl参数实现格式化;中文乱码多因编码未指定或输入含bytes;非法字符需手动清洗,敏感字符自动转义但cdata需特殊处理。

xmltodict.unparse() 默认不格式化,缩进和换行得手动加
xmltodict.unparse() 生成的是紧凑 XML 字符串,没有换行、没有缩进。如果你直接打印或保存,会得到一行超长内容,人眼根本没法读——这不是 bug,是设计如此,它只负责“转回 XML”,不负责“好看”。
要让它输出可读的格式,必须传 pretty=True 参数,而且得搭配 indent 和 newl 才能控制具体样式:
-
pretty=True是开关,不加它,后面两个参数无效 -
indent=" "指定缩进字符(推荐两个空格,别用\t,不同环境渲染不一致) -
newl="\n"指定换行符(Windows 下若写入文件,有时需用"\r\n",但绝大多数情况"\n"更安全)
中文字符乱码?检查输入 dict 的字符串编码和输出目标
xmltodict.unparse() 返回的是 str(Python 3),不是 bytes。如果你看到中文变成 有效 或直接报错 UnicodeEncodeError,大概率是后续写入文件时没指定编码,或者原始 dict 里混入了字节串。
常见错误现象:TypeError: expected string or bytes-like object —— 往往因为某个值是 bytes 而不是 str;UnicodeEncodeError: 'ascii' codec can't encode character —— 多出现在 Python 2 遗留代码或 sys.stdout 编码异常时。
立即学习“Python免费学习笔记(深入)”;
- 确保输入 dict 中所有字符串字段都是
str类型,不是bytes - 写入文件时显式指定
encoding="utf-8":with open("out.xml", "w", encoding="utf-8") as f: f.write(xml_str) - 避免在 dict 值中直接塞
json.dumps()结果而不设ensure_ascii=False,否则中文变 Unicode 转义
嵌套过深或含特殊字符时,unparse() 可能静默失败
xmltodict.unparse() 对非法 XML 名称(如 key 以数字开头、含空格或冒号)、控制字符(如 \x00)、未闭合 CDATA 等不校验,直接拼进去,导致生成的 XML 无法被标准解析器读取。
典型使用场景:把 API 返回的 JSON(可能含用户输入字段)转成 XML 发给老系统——这时 key 名不可控,值里可能有 、<code>&、" 等。
- key 名建议先清洗:
re.sub(r"[^a-zA-Z0-9_\-]", "_", key),并确保不以数字开头 - 值中的敏感字符不用手动转义——
xmltodict内部用了xml.sax.saxutils.escape(),会自动处理、<code>>、&,但不会处理双引号(除非在属性值中) - 如果值里必须保留
,得自己构造字符串并设cdata_key参数,否则会被当成普通文本转义
性能差?别在循环里反复调用 unparse()
对小数据(xmltodict.unparse(),会明显拖慢吞吐。它内部做了递归遍历 + 字符串拼接,没做缓存或复用。
更严重的是,pretty=True 模式下还会多一层树遍历计算缩进层级,开销比紧凑模式高 2–3 倍。
- 批量处理时,先用
pretty=False生成原始 XML,再用xml.dom.minidom.parseString(...).toprettyxml()统一美化(注意:minidom 会在文本节点间插入多余换行) - 若需极致性能,且结构固定,直接用
string.Template或 f-string 拼接,绕过xmltodict - 别忘了:XML 解析/生成从来不是 Python 的强项,真要高频 XML 处理,Cython 绑定的
lxml是更稳的选择
真正容易被忽略的是:很多人以为 pretty=True 只影响可读性,其实它改变了输出字符串的结构(换行符、空白字符位置),这会影响 XML 签名、哈希比对、甚至某些严格校验的接收方。上线前务必用真实数据跑一遍 end-to-end 验证。










