You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 15:48:11