xmltodict.parse()默认单元素不转列表导致json字段类型不一致,需用force_list=['item']强制指定标签始终为列表,注意命名空间需预处理或完整匹配。

xmltodict.parse() 默认不把单元素转成列表,JSON里字段类型不一致
遇到 XML 里某个标签可能只出现一次、也可能出现多次时,xmltodict.parse() 默认会把单个 <item></item> 解析成 dict,多个就变成 list —— 导致下游 JSON 字段类型飘忽,Python 里用 for item in data['items'] 直接报 TypeError: 'dict' object is not iterable。
用 force_list 参数指定哪些标签必须始终是列表
这不是全局开关,而是按需声明:告诉 xmltodict.parse() “只要看到这些标签名,不管里面几个,一律包成 list”。最常用写法是传一个字符串列表:
import xmltodict xml = '<root><item>a</item></root>' data = xmltodict.parse(xml, force_list=['item'])
结果 data['root']['item'] 就是 [{'#text': 'a'}],不是 {'#text': 'a'}。注意:force_list 值是标签名本身,不是 XPath 路径,也不区分大小写(内部用 .lower() 比对)。
- 只写
force_list=['item'],不会影响<user></user>或嵌套的<item></item>子节点(除非也列进去) - 如果想让所有同名标签都强制列表,包括深层嵌套的,就老老实实把名字全列上,比如
['item', 'entry', 'member'] - 空 XML 标签如
<item></item>也会被转成[{}],不是[None]或空字符串
别漏掉命名空间导致 force_list 失效
带命名空间的 XML(比如 <item xmlns:ns="http://example.com"></item>),标签名实际是 {http://example.com}item,而 force_list=['item'] 匹配不上。
立即学习“Python免费学习笔记(深入)”;
- 要么提前用正则或
lxml剥掉命名空间再喂给xmltodict - 要么在
force_list里写完整带命名空间的键,但得先知道 NS URI,且格式要严格匹配(含花括号) - 更稳妥的做法:统一预处理 XML,删掉
xmlns属性和前缀,避免解析时引入额外复杂度
和 xml.etree.ElementTree 对比:轻量需求别硬上 xmltodict
如果只是想确保某几个字段是 list,又不想引入第三方依赖,直接用标准库也能做:
import xml.etree.ElementTree as ET
def get_items(root):
items = root.findall('item')
return [{k: v for k, v in el.items()} | {'#text': el.text.strip() if el.text else ''} for el in items]
xmltodict 的优势在于整棵树一键转 dict,但代价是灵活性低、错误提示弱;一旦 XML 结构稍复杂(比如混合文本+子节点、属性冲突),force_list 就容易漏判或误判。
真正难处理的从来不是“单节点变数组”,而是“同一标签在不同层级语义不同”——这时候硬塞 force_list 反而让数据更难用。










