xml.etree.elementtree是读取xml最轻量够用的选择,需注意bom编码、命名空间声明、避免低效遍历、text为空检查、sql注入防护、类型转换、缺失字段处理、批量插入优化及特殊字符清洗。

用 xml.etree.ElementTree 读取 XML 是最轻量且够用的选择
Python 标准库的 xml.etree.ElementTree(常简写为 ET)对结构清晰、无命名空间或简单命名空间的 XML 文件足够可靠。它不依赖外部包,内存占用低,解析速度也够日常使用。别一上来就选 lxml——除非你明确需要 XPath 2.0、XSLT 或处理畸形 HTML 混合内容。
常见错误是直接用 ET.parse() 打开含 BOM 的 UTF-8 XML 文件却没设 encoding,导致 ParseError: not well-formed (invalid token)。解决办法是先用 open() 以 encoding='utf-8-sig' 打开再传给 ET.parse():
with open('data.xml', encoding='utf-8-sig') as f:
tree = ET.parse(f)
root = tree.getroot()
- 如果 XML 有命名空间(如
{http://example.com/ns}item),必须在查找时显式声明前缀,例如root.findall('.//ns:item', namespaces={'ns': 'http://example.com/ns'}) - 避免用
.iter()遍历全树做条件过滤——性能差;优先用.findall()加 XPath 表达式定位目标节点 -
text属性可能为None,访问前务必检查,否则抛AttributeError
把 XML 节点映射成 SQLite 的 INSERT 语句要防 SQL 注入
千万别拼接字符串构造 SQL:f"INSERT INTO books VALUES ('{title}')" 是高危操作。SQLite 的 sqlite3 模块原生支持参数化查询,所有用户数据都必须走 ? 占位符。
典型流程是:遍历每个 XML 元素 → 提取字段值(注意空值/类型转换)→ 构造元组 → 用 cursor.execute("INSERT ...", row_tuple) 批量插入。
容易忽略的点:
- XML 中数字字段(如
<price>29.99</price>)默认是字符串,需显式转float或int,否则存进 SQLite 会变成 TEXT 类型 - 日期字段(如
<pub_date>2023-05-12</pub_date>)建议转成 ISO 格式字符串存入 TEXT 字段,或用datetime.date.fromisoformat()转对象后存为 INTEGER(Julian Day) - 字段缺失时(比如某条记录没
<isbn></isbn>),不能传None给非 NULL 列;要么数据库建表时设isbn TEXT DEFAULT NULL,要么代码中补空字符串或默认值
批量插入用 executemany() 而不是循环调 execute()
插入上千条记录时,逐条 execute() 会触发上千次磁盘 I/O,慢得明显。改用 executemany() + list of tuples,配合 connection.execute("PRAGMA synchronous = OFF") 和事务包裹,速度能提升 10 倍以上。
实操要点:
- 先
conn.execute("BEGIN TRANSACTION"),再executemany(),最后conn.commit();不手动 BEGIN 时,SQLite 默认每条语句自动提交,失去批量优势 -
executemany()的第二个参数必须是可迭代对象,每个元素是长度与 SQL 中?数量一致的序列;别传字典(要用executemany(..., list_of_dicts)配:key占位符) - 单次
executemany()数据量别超 5000 行——太大可能触发 SQLite 的SQLITE_MAX_VARIABLE_NUMBER限制(默认 999)
遇到特殊字符、换行或 CDATA 内容要小心编码和空白处理
XML 中的 、、(零宽空格)等,会被 ElementTree 自动解码但可能残留多余空白。直接存入 SQLite 后,SELECT 出来的内容可能和原始 XML 不一致。
建议统一做清洗:
- 对
elem.text和elem.tail,用str.strip()去首尾空白,再用re.sub(r'\s+', ' ', ...)合并中间多个空白为单空格 - CDATA 内容无需额外处理——
ElementTree已将其当作普通文本读出 - 若 XML 含 HTML 实体(如
©),ElementTree不会自动转义;需要时可用html.unescape()处理,但注意只对 text/tail 调用,别对整个 XML 字符串乱用
最麻烦的是混合内容(mixed content):一个元素里既有文本又有子元素。这时 elem.text 只包含第一个子元素前的文本,其余得靠遍历 elem 的 itertext() 并手动拼接——这种结构最好在 XML 设计阶段就规避。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











