Python Python3 解析复杂结构的 json

匿名 · 2018年12月10日 · 3077 次阅读
#!/usr/bing/env python
# -*- coding: utf-8 -*-
# @author: xiaoxiao
# @date  : 2018/12/7

dt = {}

def analysis_json_to_dict(json):
    # 如果传入的json是list
    if isinstance(json, list):
        # 遍历list的每个元素
        for i, val in enumerate(json):
            # 如果list的元素是一个字典
            if isinstance(val, dict):
                analysis_json_to_dict(val)
            # 否则,如果不是字典,则构建字典,其中value为''
            else:
                val_list = '{"' + str(val) + '":' + '""}'
                dt.update(eval(val_list))
    # 如果传入的json是一个dict
    elif isinstance(json, dict):
        # print("dict:" + str(json))
        # 遍历dict的每组元素
        for dict_key in json:
            dict_value = json[dict_key]
            # 如果dict_value是一个list
            if isinstance(dict_value, list):
                dt[dict_key] = {}
                # 遍历list,可能还有多组dict和其它结构,形如:[{"id" : 1,"name" : "Number1","age" : 11},{"id" : 2,"name" : "Number2","age" : 22},"student"],list里面有两组dict和一个元素student
                for i, val in enumerate(dict_value):
                    # 如果val是一个dict
                    if isinstance(val, dict):
                        # 遍历val(dict结构)
                        for val_k, val_value in val.items():
                            # 如果当前val_key已经存在于dt的key里面,则追加到这个key对应的value里面
                            if val_k in dt[dict_key].keys():
                                # 如果dt[dict_key][val_k]只有一个值,非list结构,则构造一个list,以保存多个值
                                if not isinstance(dt[dict_key][val_k], list):
                                    # 如果dt[dict_key][val_k]这个值是一个字符串
                                    if type(dt[dict_key][val_k]) is str:
                                        temp_str = str(dt[dict_key][val_k])
                                        dt[dict_key][val_k] = temp_str.strip(',').split(',')
                                    # 如果是int型,则先转成str,然后转换成list保存str,最后转换成list中保存int的值
                                    elif type(dt[dict_key][val_k]) is int:
                                        temp_str = str(dt[dict_key][val_k])
                                        dt[dict_key][val_k] = temp_str.strip(',').split(',')
                                        dt[dict_key][val_k] = [int(i) for i in dt[dict_key][val_k]]
                                    # 如果是float型,则先转成str,然后转换成list保存str,最后转换成list中保存float的值
                                    elif type(dt[dict_key][val_k]) is float:
                                        temp_str = str(dt[dict_key][val_k])
                                        dt[dict_key][val_k] = temp_str.strip(',').split(',')
                                        dt[dict_key][val_k] = [float(i) for i in dt[dict_key][val_k]]
                                    # 如果是bool型,则先转成str,然后转换成list保存str,最后转换成list中保存bool的值
                                    elif type(dt[dict_key][val_k]) is bool:
                                        temp_str = str(dt[dict_key][val_k])
                                        dt[dict_key][val_k] = temp_str.strip(',').split(',')
                                        dt[dict_key][val_k] = [bool(i) for i in dt[dict_key][val_k]]
                                    dt[dict_key][val_k].append(val_value)
                                # 否则,如果dt[val_k]已经是一个list,则直接追加到后面
                                else:
                                    dt[dict_key][val_k].append(val_value)
                            # 否则,如果当前val_key未存在于dt的key里面,则直接添加
                            else:
                                dt[dict_key][val_k] = val_value
                    # 否则,val不是dict,直接构造成dict形式,加入到dt中保存,如:"student":""
                    else:
                        val_list = '{"' + str(val) + '":' + '""}'
                        dt[dict_key].update(eval(val_list))
            # 否则,如果dict_value不是一个list
            else:
                # 如果当前key已经存在于dt里面,则追加到这个key对应的value里面
                if dict_key in dt.keys():
                    # 如果dt保存的value还不是list,则需要构造一个list
                    if not isinstance(dt[dict_key], list):
                        # 如果dt[dict_key][val_k]这个值是一个字符串
                        if isinstance(dt[dict_key], str):
                            temp_str = str(dt[dict_key])
                            dt[dict_key] = temp_str.strip(',').split(',')
                        # 否则,如果是int型或Boolean类型
                        else:
                            temp_str = str(dt[dict_key])
                            dt[dict_key] = temp_str.strip(',').split(',')
                            dt[dict_key] = [int(i) for i in dt[dict_key]]
                        dt[dict_key].append(dict_value)
                    # 否则,如果dt保存的值已经是list,直接追加
                    else:
                        dt[dict_key].append(dict_value)
                # 如果当前key未存在于dt里面,则直接增加key-value
                else:
                    dt[dict_key] = dict_value
    return dt

# 场景一:没有头的json数组
d1 = [{"id" : 1,"name" : "Number1","age" : 11},{"id" : 2,"name" : "Number2","age" : 22},{"id" : "3","name" : "Number3","age" : 33}]
json_to_dict1 = analysis_json_to_dict(d1)
print("场景一结果:" + str(json_to_dict1))
dt.clear()  # dt是全局,这里需要dict清除dt,让dt={}
print('-----------------------------------------------------------')


# 场景二:有头的json数组
d2 = {"persons" :[{"id" : 1,"name" : "Number1","age" : 11},{"id" : "2","name" : "Number2","age" : 22},{"id" : 3,"name" : "Number3","age" : 33}]}
json_to_dict2 = analysis_json_to_dict(d2)
print("场景二结果:" + str(json_to_dict2))
dt.clear()  # dt是全局,这里需要dict清除dt,让dt={}
print('-----------------------------------------------------------')

# # 场景三:json数组外含有其它json字符串
d3 = {"code" : 200, "persons" :[{"id" : 1,"name" : "Number1","age" : 11},{"id" : True,"name" : "Number2","age" : 22},{"id" : 3,"name" : "Number3","age" : 33}]}
json_to_dict3 = analysis_json_to_dict(d3)
print("场景三结果:" + str(json_to_dict3))
dt.clear()  # dt是全局,这里需要dict清除dt,让dt={}

运行结果:

场景一结果{'id': [1, 2, '3'], 'name': ['Number1', 'Number2', 'Number3'], 'age': [11, 22, 33]}
-----------------------------------------------------------
场景二结果{'persons': {'id': [1, '2', 3], 'name': ['Number1', 'Number2', 'Number3'], 'age': [11, 22, 33]}}
-----------------------------------------------------------
场景三结果{'code': 200, 'persons': {'id': [1, True, 3], 'name': ['Number1', 'Number2', 'Number3'], 'age': [11, 22, 33]}}
共收到 12 条回复 时间 点赞
匿名 #1 · 2018年12月10日

踩坑 1:通过 isinstance(dt[dict_key][val_k], int) 来判断 dt[dict_key][val_k] 是不是 int 型时,测试发现 bool 值的 True 和 False 也返回了 True。后来才得知 isinstance 无法区分 int 和 bool 类型,因此改成内建函数 type(dt[dict_key][val_k]) is int 来判别。

如果是 java,可以参考一下 zson:https://github.com/zhangfei19841004/zson 😀

匿名 #3 · 2018年12月11日
再见理想 回复

感觉 Java 处理复杂 json 天生劣势😂

能不能用递归啊,这种代码很难看。。

这么多层 if 和 for 嵌套……

匿名 #6 · 2018年12月11日
arrow 回复

已经用了递归了。。。

匿名 #7 · 2018年12月11日
Jerry li 回复

因为要处理的情况特别多。。。

d1 = [{"id" : 1,"name" : "Number1","age" : 11},{"id" : 2,"name" : "Number2","age" : 22},{"id" : "3","name" : "Number3","age" : 33}]
d2 = {"persons" :[{"id" : 1,"name" : "Number1","age" : 11},{"id" : "2","name" : "Number2","age" : 22},{"id" : 3,"name" : "Number3","age" : 33}]}
d3 = {"code" : 200, "persons" :[{"id" : 1,"name" : "Number1","age" : 11},{"id" : True,"name" : "Number2","age" : 22},{"id" : 3,"name" : "Number3","age" : 33}]}


## 获取  json 数组或json 对象的 key 列表
def get_json_keys(json_str,json_keys = []):
    if isinstance(json_str,list):
        for json_obj in json_str:
            for key in json_obj.keys():
                if key not in json_keys:
                    json_keys.append(key)
    elif isinstance(json_str,dict):
        for key in json_str.keys():
                if key not in json_keys:
                    json_keys.append(key)
    return json_keys


## 将json 数组中相同的 key - value值进行合并
def get_key_values(json_str,json_keys):
    target_json = {}
    for key in json_keys:
        key_values = []
        for json_obj in json_str:
            if isinstance(json_obj,dict):
                key_values.append(json_obj[key])
        target_json[key] = key_values
    return target_json

## 主方法
def analyse_json(json_str):
    target_json = {}
    json_keys = []
    if isinstance(json_str,list):
        json_keys = get_json_keys(json_str,json_keys)
        target_json = get_key_values(json_str,json_keys)
    elif isinstance(json_str,dict):
        json_keys = get_json_keys(json_str,json_keys)
        for key in json_keys:
            if not isinstance(json_str[key],list) and not  isinstance(json_str[key],dict):
                target_json[key] = json_str[key]
            else:
                target_json[key] = analyse_json(json_str[key])
    return target_json


print(analyse_json(d1))
print(analyse_json(d2))
print(analyse_json(d3))


输出:

{'id': [1, 2, '3'], 'name': ['Number1', 'Number2', 'Number3'], 'age': [11, 22, 33]}
{'persons': {'id': [1, '2', 3], 'name': ['Number1', 'Number2', 'Number3'], 'age': [11, 22, 33]}}
{'code': 200, 'persons': {'id': [1, True, 3], 'name': ['Number1', 'Number2', 'Number3'], 'age': [11, 22, 33]}}

按这样拆分会不会好一点?

匿名 #9 · 2018年12月11日
Jerry li 回复

😅 溜,学习了,点个赞~😘

实操不如用 jsonpath,或者转成字串用正则划算...

def get_json_keys(json_str,json_keys = []):这个默认参数用列表的,没仔细看,可能是特意为之

尝试写了个函数,好像也能满足上面提到的场景。。。

def analysis_json(json):
    if isinstance(json, list) and isinstance(json[0], dict):
        return analysis_json({x: list(map(lambda k: k[x], json)) for x in json[0]})
    elif isinstance(json, dict):
        return {x: analysis_json(json[x]) for x in json}
    else:
        return json
匿名 #12 · 2018年12月13日
a2021 回复

厉害啊大佬,真是万能的列表推导公式😂 我也得学习下~😃

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册