如何在Python中转换xmltodict生成的JSON适配前端XML解析器
实现思路与方案
针对xmltodict解析后的数据结构转换需求,这里提供几个实用的实现思路:
1. 递归遍历重组字典
这是最直接的方案,利用递归处理任意深度的嵌套结构,逐个节点整理属性和文本:
- 遍历字典的每个键值对,将所有
@开头的属性键收集到单独的@对象中(去掉键名的@前缀) - 将
#text字段重命名为# - 遇到嵌套的字典或列表时,递归调用转换函数继续处理
代码示例:
import xmltodict def transform_xml_structure(data): # 处理列表类型 if isinstance(data, list): return [transform_xml_structure(item) for item in data] # 处理字典类型 elif isinstance(data, dict): transformed = {} attrs = {} text_content = None for key, value in data.items(): if key.startswith('@'): # 收集属性,去掉@前缀 attrs[key[1:]] = value elif key == '#text': # 保存文本内容 text_content = value else: # 递归处理子节点 transformed[key] = transform_xml_structure(value) # 添加属性对象(如果有属性) if attrs: transformed['@'] = attrs # 添加文本字段(如果有文本) if text_content is not None: transformed['#'] = text_content return transformed # 基本类型直接返回 else: return data # 测试用例 xml_sample = '''<book id="123" category="tech"> <title lang="en">Python Programming</title> <author>John Doe</author> </book>''' parsed_data = xmltodict.parse(xml_sample) result = transform_xml_structure(parsed_data) print(result)
2. 迭代式遍历(避免递归深度问题)
如果XML结构异常深层(比如嵌套数百层),递归可能触发RecursionError,此时可以用栈/队列实现迭代式遍历:
- 用栈保存待处理的节点、父节点及父节点中的键
- 逐个弹出栈中节点,处理属性和文本后,将子节点压入栈继续处理
- 全程不使用递归,避免深度限制
代码示例:
def transform_iterative(data): # 栈元素:(当前处理数据, 父节点, 在父节点中的键/索引) stack = [(data, None, None)] while stack: current, parent, key = stack.pop() if isinstance(current, list): transformed_list = [] # 倒序压栈,保证处理顺序正确 for item in reversed(current): stack.append((item, transformed_list, -1)) # 更新父节点 if parent is not None: if key == -1: parent.append(transformed_list) else: parent[key] = transformed_list elif isinstance(current, dict): transformed = {} attrs = {} text_content = None child_nodes = [] for k, v in current.items(): if k.startswith('@'): attrs[k[1:]] = v elif k == '#text': text_content = v else: child_nodes.append((k, v)) if attrs: transformed['@'] = attrs if text_content is not None: transformed['#'] = text_content # 倒序压入子节点,保证处理顺序 for k, v in reversed(child_nodes): stack.append((v, transformed, k)) # 更新父节点 if parent is not None: if key == -1: parent.append(transformed) else: parent[key] = transformed else: # 基本类型直接赋值给父节点 if parent is not None: if key == -1: parent.append(current) else: parent[key] = current return data
3. 自定义JSON编码器
如果最终需要直接序列化为JSON字符串,可以自定义JSONEncoder,在序列化过程中完成结构转换:
- 重写编码器的
encode方法,在内部完成结构转换逻辑 - 无需单独保存转换后的字典,直接输出符合要求的JSON
代码示例:
import json class XMLTargetEncoder(json.JSONEncoder): def encode(self, obj): def transform(node): if isinstance(node, list): return [transform(item) for item in node] elif isinstance(node, dict): res = {} attrs = {} text = None for k, v in node.items(): if k.startswith('@'): attrs[k[1:]] = v elif k == '#text': text = v else: res[k] = transform(v) if attrs: res['@'] = attrs if text is not None: res['#'] = text return res else: return node return super().encode(transform(obj)) # 使用示例 parsed_data = xmltodict.parse(xml_sample) json_output = json.dumps(parsed_data, cls=XMLTargetEncoder, indent=2) print(json_output)
内容的提问来源于stack exchange,提问作者Sean Mullarkey
相关产品推荐
相关产品推荐

