需求:
有两个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)