需求:
有两个json文件。两个都是复杂嵌套格式。需要比对A.json里是否包含b.json。
例如A.json是
{
"role": "admin",
"routes": [
"/Home",
"/DeviceManagement",
"/UserManagement"
]
}
B.json是
{
"role": "admin",
"routes": [
"/Home",
"/TemplateManagement",
"/DataDictionary",
"/ClassifyAndSubEntry",
"/ProjectManagement",
"/DeviceManagement",
"/UserManagement"
]
}
要检查B文件是否包含A文件。这个json文件还好嵌套不多,当多个dict和list魂用,即[]和{}太多时,则会出现很难比对的问题。我考虑使用jsonpath来解决这个问题
代码实现
1.把json文件变成一个新的dict[jsonpath,value] ,例如’infos/0/item’: ‘direction’ 表示jsonpath为”infos.0.item”对应的值是direction。具体的可以打印一下JsonPathValue这个类的final_dict就能明白了
# filename : test1.py
# description :
#
# created by zhenwei.li at 2019/5/27 10:59
import json
class JsonPathValue(object):
def __init__(self, datadict):
self.stack = []
self.final_dict = {}
self.do_walk(datadict)
def get_dict(self):
return self.final_dict
def do_walk(self, datadict):
if isinstance(datadict, dict):
for key, value in datadict.items():
self.stack.append(key)
# print("/".join(self.stack))
if isinstance(value, dict) and len(value.keys()) == 0:
self.final_dict["/".join(self.stack)] = "EMPTY_DICT"
if isinstance(value, list) and len(value) == 0:
self.final_dict["/".join(self.stack)] = 'EMPTY_LIST'
if isinstance(value, dict):
self.do_walk(value)
if isinstance(value, list):
self.do_walk(value)
else:
self.final_dict["/".join(self.stack)] = value
self.stack.pop()
if isinstance(datadict, list):
n = 0
for key in datadict:
self.stack.append(str(n))
n = n + 1
if isinstance(key, dict):
self.do_walk(key)
if isinstance(key, list):
self.do_walk(key)
if isinstance(key, str):
self.final_dict["/".join(self.stack)] = key
self.stack.pop()
def json_contain(checkpoint, actual, assert_flag):
"""
检查实际结果(json)中是否包含检查点(json)。两个必须是同种格式,比如同时是{}或者[]
:param checkpoint: 检查点(期望结果)
:param actual: 实际结果
:param assert_flag: 是否启用assert检查
:return: 匹配成功或失败
"""
result = False
if isinstance(checkpoint, list):
'''如果期望的检查点是list[]格式,使用此方法检查'''
find_count = 0
check_lenth = len(checkpoint)
for item in checkpoint:
checkpoint_dict = JsonPathValue(item).get_dict()
if isinstance(actual, list):
find_flag = False
for actual_item in actual:
actual_dict = JsonPathValue(actual_item).get_dict()
find_flag = list_contain(checkpoint_dict, actual_dict, False)
if find_flag:
find_count += 1
break
print(find_flag)
else:
assert False, "返回的实际结果格式不正确"
if assert_flag:
assert find_flag, "期望结果中的\n%s\n匹配失败,实际结果是:\n%s" % (item, actual)
if find_count == check_lenth:
result = True
elif isinstance(checkpoint, dict):
'''
如果期望的检查点是dict{}格式
'''
checkpoint_dict = JsonPathValue(checkpoint).get_dict()
actual_dict = JsonPathValue(actual).get_dict()
if list_contain(checkpoint_dict, actual_dict, True):
result = True
return result
def list_contain(checkpoint_dict, actual_dict, assert_flag):
"""
检查实际结果(list)中是否包含期望结果(list)
:param checkpoint_dict: 实际结果
:param actual_dict: 期望结果
:param assert_flag: 是否启用assert检查
"""
result = set(checkpoint_dict.items()).issubset(set(actual_dict.items()))
if assert_flag is True:
different = set(checkpoint_dict.items()) - (set(actual_dict.items()))
assert result, \
"期望结果中的%s匹配失败,实际结果是:\n%s" % (different, actual_dict)
return result
json_data = open('A.json', 'rb').read()
json_dict = json.loads(json_data)
json_data2 = open('B.json', 'rb').read()
json_dict2 = json.loads(json_data2)
res1 = json_contain(json_dict, json_dict2, True)
print(res1)