需求:
有兩個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)