XMLGenerator写中文需显式指定UTF-8编码,startElementNS参数顺序为(name, qname, attrs),其中name是(uri, localname)元组;attributes必须用AttributesImpl实例,不自动转义字符实体。

XMLGenerator 写入中文内容时直接报错
默认用 XMLGenerator 写中文,大概率触发 UnicodeEncodeError: 'ascii' codec can't encode characters。它底层用的是 sys.stdout 或传入的文件对象的编码,而 Python 2/3 默认行为不一致,但多数环境没显式指定 encoding 就会崩。
- 必须在初始化时传入带编码声明的
io.TextIOWrapper(Python 3)或手动 wrap 的codecs.StreamWriter(Python 2),不能直接传open('out.xml', 'w') - 推荐统一用
open('out.xml', 'w', encoding='utf-8')(Python 3.7+),再传给XMLGenerator;老版本得用codecs.open('out.xml', 'w', encoding='utf-8') - 别依赖
sys.stdout——它编码不可控,尤其 Windows 控制台默认是 cp936
startElementNS 和 startElement 参数顺序容易搞反
XMLGenerator 提供两套元素开始方法:startElement(无命名空间)和 startElementNS(带命名空间)。后者参数顺序反直觉:不是 (uri, localname, qname, attrs),而是 (name, qname, attrs),其中 name 是 (uri, localname) 元组。
-
startElementNS(('http://example.com/ns', 'item'), 'ex:item', {})才对;写成startElementNS('http://example.com/ns', 'item', ...)会抛TypeError -
qname是可选的,但如果传了,必须和name[1](即 localname)一致,否则生成的前缀可能错乱 - 没命名空间就老实用
startElement,混用容易漏掉xmlns声明或重复声明
attributes 参数必须是 SAX Attributes 对象,不能直接传 dict
调用 startElement 或 startElementNS 时,第三个参数是 attrs,类型必须是 sax.saxutils.XMLGenerator._attrs 实例或兼容的 sax.xmlreader.AttributesImpl,传普通 dict 会静默失败或报 AttributeError。
- 正确做法:
from xml.sax.saxutils import XMLGenerator+from xml.sax.xmlreader import AttributesImpl,然后attrs = AttributesImpl({'class': 'active', 'id': 'main'}) - 别手写
{'class': 'active'}.items()去凑——XMLGenerator内部靠attrs.getLength()和attrs.getNameByIndex(i)遍历,普通 dict 没这些方法 - 如果只是简单场景,用
xml.etree.ElementTree更省心;XMLGenerator适合流式、内存敏感、边生成边写入的场合
不自动处理字符实体,& " 必须自己转义
XMLGenerator.characters() 不做任何转义,传入 "A & B 会直接写进 XML,导致解析失败。它只负责按结构拼标签,内容安全完全甩给调用方。
立即学习“Python免费学习笔记(深入)”;
- 必须手动过一遍
xml.sax.saxutils.escape(),例如:gen.characters(escape('A & B -
escape()默认转义&、、<code>>;加quotechars='"'可额外转双引号(单引号默认不转) - 别用
html.escape()替代——它会把这类 HTML 实体也转,XML 不认
真正麻烦的是混合场景:既要写原始 CDATA,又要插转义文本,还得控制换行缩进——XMLGenerator 本身不提供这些,全得自己在 write() 前预处理。流式生成看着轻量,实际工程里很容易变成状态管理黑洞。








