Python Python3 解析复杂结构的 json

xiakexing · December 10, 2018 · Last by xiakexing replied at December 13, 2018 · 3035 hits
#!/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:通过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 😀

再见理想 回复

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

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

这么多层 if 和 for 嵌套……

arrow 回复

已经用了递归了。。。

Jerry li 回复

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

xiakexing 回复
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]}}

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

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
keke 回复

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

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up