xml.etree.ElementTree是Python标准库中最轻量且够用的XML解析方案,无需外部依赖,适合中等规模、无复杂命名空间和深度嵌套的XML文件。

用 Python 的 xml.etree.ElementTree 解析 XML 最稳
XML 结构千差万别,但只要不是带命名空间嵌套过深、不混文本节点,xml.etree.ElementTree 是标准库中最轻量又够用的选择。它不依赖外部包,解析速度对中等规模文件(
常见错误现象:ParseError: not well-formed (invalid token) —— 多半是编码不对或含 BOM 头;AttributeError: 'NoneType' object has no attribute 'text' —— 路径写错或某条记录缺字段。
- 先用
open(file, encoding='utf-8-sig')读取,自动跳过 UTF-8 BOM - 用
root.findall('.//record')这类相对路径,比硬写root[0][1][2]更健壮 - 字段提取统一用
elem.find('field_name')?.text or '',避免 None 报错(Python 3.8+ 可用海象运算符,否则加 if 判断)
CSV 写入时字段顺序和空值处理不能靠默认
XML 中每个 的子元素顺序可能不一致,直接按首次出现的字段定 CSV header,后续记录字段缺失就会错位。CSV 模块本身不校验列对齐,错位后 Excel 打开全是偏移数据。
使用场景:多来源 XML 合并、历史数据迁移、API 返回结构松散的 XML。
- 先遍历一遍所有
record,收集全部可能出现的字段名,用set()去重,再转为固定顺序的list - 写入每行时,严格按该 list 顺序取值:
[elem.find(f).text.strip() if elem.find(f) is not None else '' for f in field_order] - 避免用
csv.writer.writerow(dict.values())—— dict 无序,Python 3.6+ 虽保持插入序,但逻辑上不可靠
遇到带命名空间的 XML 别硬怼标签名
像 这种,直接写 root.find('product') 一定返回 None。ElementTree 默认不识别前缀,必须显式传入命名空间字典。
性能影响:命名空间解析本身开销极小,但写错会导致整个解析逻辑失效,调试成本远高于加一行配置。
- 提取命名空间:
namespaces = {'ns': 'http://example.com'}(URI 必须完全一致) - 查找时带上:
root.find('ns:product', namespaces)或root.findall('.//ns:record', namespaces) - 如果 XML 有多个 namespace 前缀,但 URI 相同,可以只映射一个前缀,比如
{'x': 'http://same.uri'},然后统一用x:tag
大文件别一次性 load 到内存
超过 50MB 的 XML,用 ET.parse() 容易触发 MemoryError。ElementTree 提供 iterparse() 流式解析,边读边写 CSV,内存占用基本恒定。
容易踩的坑:忘记调用 elem.clear(),导致已处理节点仍驻留内存;或在循环中反复调用 findall() 导致重复遍历。
- 用
for event, elem in ET.iterparse(file, events=('start', 'end')): - 在
event == 'end'且elem.tag == 'record'时提取数据,立刻写入 CSV 行,然后调用elem.clear() - 外层保留一个
root = None,首次start事件时赋值,用于后续elem.getparent()(如需父级上下文)










