如何在Python中精准实现字典/JSON与XML的双向转换并完整保留结构?
如何在Python中精准实现字典/JSON与XML的双向转换并完整保留结构?
我太懂你这种烦恼了!之前用dicttoxml和xmltodict做双向转换的时候,也踩过这个讨厌的“item嵌套+类型丢失”双坑——好好的结构平白多了一层冗余的item键,连整数都变成了字符串,要是写后处理代码清理吧,又怕误改合法字段,真心闹心。不过别担心,咱们通过调整两个库的参数配置,就能完美解决这些问题,完全不用额外写复杂的后处理!
先给你说核心思路:要从“生成XML”和“解析XML”两个环节同时下手,既要让XML生成时避免无意义的<item>标签,也要让解析时自动还原原始结构和数据类型。
方案一:生成语义化XML(推荐,结构更清晰)
这个方案会把列表元素的标签从默认的<item>改成和父节点对应的单数形式(比如mydicts下面的元素用mydict),生成的XML更易读,解析时也能直接完美还原结构。
import xmltodict import dicttoxml # 自定义函数:把父节点的复数名转成单数(简单实现,复杂场景可以用inflect库优化) def plural_to_singular(parent_key): return parent_key[:-1] if parent_key.endswith('s') else parent_key # 原始JSON/字典 original_json = { "mydicts": [ {"id": 1, "name": "alice"}, {"id": 2, "name": "bob"} ] } # 1. JSON转XML:用自定义标签替换默认的<item> xml_output = dicttoxml.dicttoxml( original_json, root=True, # 保留根节点 item_func=plural_to_singular, # 列表元素用父键的单数标签 attr_type=False # 不生成冗余的type属性(比如type="int") ) print("生成的XML:") print(xml_output.decode('utf-8')) # 2. XML转JSON:强制解析列表并还原类型 parsed_json = xmltodict.parse( xml_output, # 强制把单数标签的节点解析成列表(避免单个元素时变成字典) force_list=[plural_to_singular("mydicts")], attr_prefix='', # 去掉属性前缀,避免不必要的嵌套 cdata_key='' # 不保留CDATA标记 ) # 去掉xmltodict默认的root节点外层 parsed_json = parsed_json['root'] # 额外处理:把XML解析出的字符串类型数字转回数值类型 def convert_types(data): if isinstance(data, dict): for k, v in data.items(): if isinstance(v, str): if v.isdigit(): data[k] = int(v) elif '.' in v and all(part.isdigit() for part in v.split('.')): data[k] = float(v) elif isinstance(v, list): for item in v: convert_types(item) return data parsed_json = convert_types(parsed_json) print("\n解析后的字典:") print(parsed_json) print("\n和原始结构&类型完全一致:", parsed_json == original_json)
方案二:保留默认- 标签,解析时自动清理嵌套
如果你不想修改XML的标签格式,就想用默认的<item>,那可以用xmltodict的postprocessor参数自动去掉item的嵌套,同时还原数据类型:
import xmltodict import dicttoxml original_json = { "mydicts": [ {"id": 1, "name": "alice"}, {"id": 2, "name": "bob"} ] } # 1. JSON转XML:用默认的<item>标签(和你原来的代码逻辑一致) xml_output = dicttoxml.dicttoxml( original_json, root=True, attr_type=False ) print("生成的XML:") print(xml_output.decode('utf-8')) # 自定义后处理函数:去掉item嵌套+还原数据类型 def clean_and_convert(path, key, value): if key == 'item': # 把字符串数字转成数值类型 for k, v in value.items(): if isinstance(v, str): if v.isdigit(): value[k] = int(v) elif '.' in v and all(part.isdigit() for part in v.split('.')): value[k] = float(v) # 返回None+值,相当于移除item键,直接保留内容 return None, value return key, value # 2. XML转JSON:自动清理item嵌套 parsed_json = xmltodict.parse( xml_output, force_list=['mydicts'], # 强制mydicts为列表,避免单个元素时变成字典 postprocessor=clean_and_convert, attr_prefix='', cdata_key='' ) parsed_json = parsed_json['root'] print("\n解析后的字典:") print(parsed_json) print("\n和原始结构&类型完全一致:", parsed_json == original_json)
小提示
- 方案一更推荐,因为生成的XML语义化更强,后续维护起来更方便;
- 关于类型转换:XML本身没有数据类型的概念,所有内容都是文本,所以必须手动处理类型转换,上面的代码已经包含了基础的数字转换逻辑,复杂类型(比如布尔值)可以自己扩展;
- 如果你有单个元素的列表(比如mydicts里只有一个字典),一定要用
force_list强制解析成列表,否则xmltodict会把它转成普通字典,破坏原始结构。
备注:内容来源于stack exchange,提问作者funkmeister
相关产品推荐
相关产品推荐

