Python JSON对象转换成自定义词典Python JSON对象转换成自定义词典

54 阅读3分钟

遇到了一个复杂Python JSON对象到自定义词典的转换问题,JSON对象的数据结构复杂,涉及多层嵌套,需要对嵌套的数据进行递归遍历和转换。

解决方案

  1. 数据预处理:
    • 首先使用deepcopy()函数创建JSON数据的副本,防止在转换过程中修改原始数据。
  2. 递归遍历:
    • 接下来,使用自定义函数walk_fun_lim()对JSON数据进行递归遍历。该函数可以递归遍历嵌套的数据结构,并对每个字典元素执行指定的转换操作。
  3. 转换操作:
    • transformers_robots_in_disguise()函数中,对每个字典元素进行转换操作。
      • 提取PerfList元素,并将其转换为自定义格式。
      • 提取Resource元素,并将其转换为自定义格式。
  4. 转换结果:
    • 转换完成后,将得到一个新的字典数据结构,其中包含了转换后的数据。

代码例子

import json
from copy import deepcopy
from pprint import pprint
from StringIO import StringIO

# JSON数据
json_str = \
'''
{
    "Resource": [
        {
            "@name": "Bravo",
            "@signature": "h#Bravo",
            "@type": "ESX_5.x",
            "@typeDisplayName": "ESX Server",
            "PerfList": {
                "@attrId": "cpuUsage",
                "@attrName": "Usage",
                "Data": [
                    {
                        "@data": "26.00",
                        "@end": "01:05:00",
                        "@interval": "60",
                        "@start": "01:04:00"
                    },
                    {
                        "@data": "24.00",
                        "@end": "01:04:00",
                        "@interval": "60",
                        "@start": "01:03:00"
                    },
                    {
                        "@data": "36.00",
                        "@end": "01:03:00",
                        "@interval": "60",
                        "@start": "01:02:00"
                    },
                    {
                        "@data": "38.00",
                        "@end": "01:02:00",
                        "@interval": "60",
                        "@start": "01:01:00"
                    },
                    {
                        "@data": "37.00",
                        "@end": "01:01:00",
                        "@interval": "60",
                        "@start": "01:00:00"
                    }
                ]
            },
            "Resource": [
                {
                    "@name": "Tango",
                    "@signature": "vm#Tango",
                    "@type": "vm",
                    "@typeDisplayName": "Virtual Machine",
                    "PerfList": {
                        "@attrId": "cpuUsage",
                        "@attrName": "Usage",
                        "Data": {
                            "@data": "12.00",
                            "@end": "04:05:00",
                            "@interval": "60",
                            "@start": "04:04:00"
                        }
                    }
                },
                {
                    "@name": "Charlie",
                    "@signature": "vm#Charlie",
                    "@type": "vm",
                    "@typeDisplayName": "Virtual Machine",
                    "PerfList": {
                        "@attrId": "cpuUsage",
                        "@attrName": "Usage",
                        "Data": [
                            {
                                "@data": "12.00",
                                "@end": "04:20:00",
                                "@interval": "60",
                                "@start": "04:19:00"
                            },
                            {
                                "@data": "12.00",
                                "@end": "04:19:00",
                                "@interval": "60",
                                "@start": "04:18:00"
                            }
                        ]
                    }
                }
            ]
        },
        {
            "@name": "Alpha",
            "@signature": "h#Alpha",
            "@type": "ESX_5.x",
            "@typeDisplayName": "ESX Server",
            "PerfList": [
                {
                    "@attrId": "cpuUsage",
                    "@attrName": "Usage",
                    "Data": {
                        "@data": "9",
                        "@end": "06:10:00",
                        "@interval": "60",
                        "@start": "06:09:00"
                    }
                },
                {
                    "@attrId": "cpuUsagemhz",
                    "@attrName": "Usage MHz",
                    "Data": {
                        "@data": "479",
                        "@end": "06:10:00",
                        "@interval": "60",
                        "@start": "06:09:00"
                    }
                }
            ]
        }
    ]
}
'''

# 数据预处理
json_data = json.load(StringIO(json_str))
data_copy = deepcopy(json_data)

# 递归遍历和转换
def walk_fun_lim(ilist, func=None):
    tlist = []
    ttlist = []
    if(isinstance(ilist, list)):
        ttlist = filter(lambda x: x, func(filter(lambda x: isinstance(x, dict), ilist)))
        if(ttlist):
            tlist += ttlist
        for q in ilist:
            ttlist = filter(lambda x: x, walk_fun_lim_helper(q, func, count+1))
            if(ttlist):
                tlist += ttlist
    elif(isinstance(ilist, dict)):
        ttlist = filter(lambda x: x, func([ilist]))
        if(ttlist):
            tlist += ttlist
        for q in ilist:
            ttlist = filter(lambda x: x, walk_fun_lim_helper(ilist[q], func, count+1))
            if(ttlist):
                tlist += ttlist
    return [tlist] if(count != 0) else tlist

def transformers_robots_in_disguise(x):
    for idict in x:
        plist = idict.pop("PerfList", [])
        plist = plist if(isinstance(plist, list)) else [plist]
        for sub_dict in plist:
            sub_name = sub_dict.pop("@attrId")
            dlist = sub_dict.pop("Data", [])
            dlist = dlist if(isinstance(dlist, list)) else [dlist]
            new_dict = {}
            for sub_dict in dlist:
                new_dict["from_%(@start)s_to_%(@end)s" % sub_dict] = sub_dict["@data"]
                new_dict["@interval"] = sub_dict["@interval"]
            idict[sub_name] = new_dict
        rlist = idict.pop("Resource", [])
        rlist = rlist if(isinstance(rlist, list)) else [rlist]
        for sub_dict in rlist:
            sub_type = sub_dict.pop("@type")
            sub_name = sub_dict.pop("@name")
            idict.setdefault(sub_type, {})[sub_name] = sub_dict
    return []

walk_fun_lim(data_copy, transformers_robots_in_disguise)

# 转换结果
pprint(data_copy)

这个解决方案使用walk_fun_lim()函数对JSON数据进行递归遍历,并在遍历过程中执行transformers_robots_in_disguise()函数进行转换操作。最后得到的data_copy就是转换后的结果。