xml.etree.ElementTree足以处理绝大多数轻量级XML映射任务,内置稳定、内存占用低、支持解析、修改与写回;复杂场景(如命名空间、大文件、XSLT)推荐lxml。

用 Python 的 xml.etree.ElementTree 处理常见 XML 映射
绝大多数轻量级 XML 映射任务,不需要引入 XSLT 或专用框架,xml.etree.ElementTree 就够用——它内置、稳定、内存占用低,且支持直接修改节点后写回。
典型场景:把 映射为 Python 字典 {'name': 'Alice', 'age': '30'},或反向生成 XML。
- 用
ET.fromstring()解析字符串,或ET.parse()读取文件 - 用
.find()/.findall()定位节点,避免硬写索引(如root[0].text)——XPath 表达式更健壮 - 注意
.text可能为None,需显式判断;空标签或含换行时,.text.strip()更安全 - 写回时用
tree.write(path, encoding='utf-8', xml_declaration=True),漏掉xml_declaration=True会导致无声明
import xml.etree.ElementTree as ETdef xml_to_dict(element): result = {} for child in element: result[child.tag] = child.text.strip() if child.text else "" return result
tree = ET.parse("input.xml") root = tree.getroot() data = xml_to_dict(root) print(data) # {'name': 'Alice', 'age': '30'}
当字段嵌套或重复出现时,别硬编码层级
遇到 这类结构,用循环 + 列表推导比逐个取 root[0][0] 更可靠。
.findall('item') 返回所有匹配子元素列表,配合 .find('sku').text 可避免 AttributeError ——但得先确认 sku 存在,否则加 or "" 或用 find() 后判空。
- 嵌套映射建议封装成函数,比如
parse_item(elem)单独处理每个 - 不要用
root.iter('sku')全局遍历,除非你明确需要跨层级聚合——它会打乱父子关系 - 如果 XML 有命名空间(如
xmlns="http://example.com/ns"),必须在查找时传入命名空间字典,否则.find('item')返回None
用 lxml 替代 ElementTree 处理复杂规则或大文件
当遇到 XSLT 转换、DTD 验证、CSS 选择器语法、或解析上百 MB 的 XML 时,lxml 是实际选择——它兼容 ElementTree API,但性能更高、功能更全。
安装:pip install lxml;导入后几乎可无缝替换:from lxml import etree,然后把 ET 换成 etree。
-
etree.XMLParser(recover=True)可容忍部分格式错误(如未闭合标签),ElementTree会直接抛ParseError - 支持 CSS 选择器:
root.cssselect('item > sku'),比 XPath 更直观 - 用
etree.XSLT(xsl_tree)执行 XSLT 映射,适合字段重命名、结构重组等强规则场景 - 注意:lxml 默认不校验 DTD,启用需显式设
load_dtd=True和resolve_entities=False防 XXE
自动化调度时,XML 文件路径和编码最容易出错
脚本跑在本地没问题,一上服务器就报 UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff,大概率是源文件用了 gbk 或 latin-1 编码。
- 别依赖系统默认编码,始终显式指定:
open(path, encoding='utf-8', errors='replace') - 用
chardet.detect()自动探测编码(小文件适用),但别在循环里反复调用——开销大 - 路径拼接用
os.path.join()或pathlib.Path(),避免 Windows 下"data\input.xml"在 Linux 报错 - 定时任务(如 cron)中,工作目录不一定是脚本所在目录,
__file__获取绝对路径再拼接更稳:Path(__file__).parent / "data" / "input.xml"
XML 映射真正的复杂点不在语法,而在边界:编码混杂、命名空间隐含、空值表示方式不一( vs vs 缺失字段)、以及上游数据随时变更。自动化脚本上线前,务必用真实脏数据跑几轮,而不是只测 clean case。










