class JsonCompareUtil:
@classmethod
def compareValues(cls, source, target, *ignores, path='', compare_result = []):
"""
递归对比两个json串的value
:param source: 比较的模板json
:param target: 目标json
:param ignores: 忽略对比的key
:param path: 不用传
:param compare_result: 不用传
:return: 对比结果列表说明,如果全部匹配返回空列表
"""
if not isinstance(source, (list, tuple, dict, set)):
# 比对非list、tuple、dict、set类型的数据
if not source == target:
msg = {
'field': path,
'error_type': '值不相等',
'source': source,
'target': target
}
compare_result.append(msg)
elif isinstance(source, (list, tuple, set)):
#类型是否一致
if type(source) != type(target):
msg = {
'field': path,
'error_type': "类型不一致",
'source': f"类型={type(source)}",
'target': f"类型={type(target)}"
}
compare_result.append(msg)
return
#长度是否一致
if len(source) != len(target):
msg = {
'field': path,
'error_type': "数组长度不一致",
'source': f"数组长度={len(source)}",
'target': f"数组长度={len(target)}"
}
compare_result.append(msg)
return
#值是否一致
for index, value in enumerate(source):
if index < len(target):
cls.compareValues(value, target[index], *ignores, path = f'{path}[{index}]' if path else f'{index}')
else:
cls.compareValues(value, {}, *ignores, path = f'{path}[{index}]' if path else f'{index}')
else:
#比对值为dict类型数据
if not isinstance(target, dict):
msg = {
'field': path,
'error_type': "目标不是dict",
'source': f"源类型={type(source)}",
'target': f"目标类型={type(target)}"
}
compare_result.append(msg)
return
source_keys = source.keys()
target_keys = target.keys()
#求差集
diff_keys = list(source_keys ^ target_keys)
#有key不同
if diff_keys:
for key in diff_keys:
msg = {
'field': f"{path}.{key}" if path else f'{key}',
'error_type': '字段缺失',
'source': f"字段[{key}]缺失",
'target': target.get(key, None)
}
compare_result.append(msg)
#key都相同,递归处理
else:
for key, value in source.items():
if key in ignores:
continue
if key in target.keys():
cls.compareValues(value, target[key], *ignores, path = f"{path}.{key}" if path else f'{key}')
else:
msg = {
'field': f"{path}.{key}" if path else f'{key}',
'error_type': '字段缺失',
'source': value,
'target': f"字段[{key}]缺失"
}
compare_result.append(msg)
return compare_result
@classmethod
def compareKeys(cls, source, target, path='', compare_result = []):
"""
递归对比两个json的结构
:param source: 比较的模板json
:param target: 目标json
:param path: 不用传
:param compare_result: 不用传
:return: 对比结果列表说明,如果全部匹配返回空列表
"""
#数组
if isinstance(source, list) and isinstance(target, list):
#递归处理里面的dict
for a, b in zip(source, target):
cls.compareKeys(a, b, path=path)
if isinstance(source, dict) and isinstance(target, dict):
source_keys = source.keys()
target_keys = target.keys()
#求差集
diff_keys = list(source_keys ^ target_keys)
#有key不同
if diff_keys:
for key in diff_keys:
msg = {
'field': f"{path}.{key}" if path else f'{key}',
'error_type': '字段缺失',
'source': f"字段[{key}]缺失",
'target': target.get(key, '')
}
compare_result.append(msg)
#key都相同,递归处理
else:
for key, value in source.items():
#字典嵌套
if isinstance(value, dict):
cls.compareKeys(value, target.get(key), path=f'{path}.{key}' if path else key)
#列表中包含字典
elif isinstance(value, list):
cls.compareKeys(value, target.get(key), path=f'{key}[*]')
return compare_result