Python實現json串比對並輸出差異結果


主要是利用遞歸,逐層級、逐次、逐字段比較;可以用於冪等類接口的返回體校驗。

class JsonCompare:
	def __init__(self, second_data, first_data, debug_model=False):
		"""
		用於兩個json串比對,輸出兩串json字段差異

		:param second_data: 用於比對的新json
		:param first_data: 基准json
		:param debug_model: 為True時將在控制台輸出比對結果,默認不開啟
		"""

		self.compare_result = []  # 存放字段差異
		self.compare_error = []  # 存放字段比對異常
		self.compare(second_data, first_data)

		if debug_model:
			for i in self.compare_result:
				print(i)
			for i in self.compare_error:
				print(i)

	def compare(self, second_data, first_data, path=''):
		try:
			if not isinstance(second_data, (list, tuple, dict)):
				# 比對非list\tuple\dict類型的數據
				if not second_data == first_data:
					msg = {
						'field': path,
						'error_type': 'field value diff',
						'secondResp': second_data,
						'firstResp': first_data
					}
					self.compare_result.append(msg)

			elif isinstance(second_data, (list, tuple)):
				# 如果新數據是list/tuple,則判斷老數據是否類型一致;不一致則追加到compare_error
				if type(second_data) != type(first_data):
					msg = {
						'field': path,
						'error_type': "field type diff",
						'secondResp': f"type is {type(second_data)}",
						'firstResp': f"type is {type(first_data)}"
					}
					self.compare_result.append(msg)
					return
				if len(second_data) != len(first_data):
					msg = {
						'field': path,
						'error_type': "field indexLength diff",
						'secondResp': f"Length of list is {len(second_data)}",
						'firstResp': f"Length of list is {len(first_data)}"
					}
					self.compare_result.append(msg)
				for index, value in enumerate(second_data):
					try:
						if index < len(first_data):
							self.compare(
								value, first_data[index], f'{path}:{index}')
						else:
							self.compare(value, {}, f'{path}:{index}')
					except Exception as e:
						self.compare_error.append(
							f'Unknown error: {e.args}')
			else:
				# 比對值為dict類型數據
				if not isinstance(first_data, dict):
					msg = {
						'field': path,
						'error_type': "field type diff",
						'secondResp': f"type is {type(second_data)}",
						'firstResp': f"type is {type(first_data)}"
					}
					self.compare_result.append(msg)
					return
				new_keys = set(second_data.keys())
				old_keys = set(first_data.keys())
				diff_keys = old_keys - new_keys  # 用於檢查老數據存在某個key,但新數據不存在。
				for key, value in second_data.items():
					try:
						if key in first_data.keys():
							self.compare(
								value, first_data[key], f"{path}:{key}")
						else:
							msg = {
								'field': f"{path}:{key}",
								'error_type': 'field missing',
								'secondResp': value,
								'firstResp': f"Field of '{key}' is not exists"
							}
							self.compare_result.append(msg)
					except Exception as e:
						self.compare_error.append(
							f'Unknown error:{e.args}')
				if diff_keys:
					for key in diff_keys:
						msg = {
							'field': f"{path}:{key}",
							'error_type': 'field missing',
							'secondResp': f"Field of '{key}' is not exists",
							'firstResp': first_data[key]
						}
						self.compare_result.append(msg)

		except Exception as e:
			self.compare_error.append(
				f'Unknown error:{e.args}')

使用方法:

_old_data = {
		"key1": "value1",
		"key2": "value2",
		"key3": [1],
		"object": {
			"object_key1": "object_value2",
			"object_key2": {
				"sub_key": "object_key2_sub_value"
			},
			"object_key3": [
				{"list_sub_key1": "xx"},
				{"list_sub_key2": "xx"}
			]

		},
		"x": 1.2
	}
_new_data = {
	"key1": "value1",
	"key2": "value2",
	"key3": (1,),
	"object": {
		"object_key1": "object_value1",
		"object_key2": {
			"sub_key": "object_key2_sub_value",
			"sub_key2": {"xx": 1}
		},
		"object_key3": [
			{"list_sub_key1": "xx"},
			{"list_sub_key2": []}
		]

	},
	"x": 1.2
}

print("方式一:")
JsonCompare(_new_data, _old_data, debug_model=True)
print("方式二:")
json_compare = JsonCompare(_new_data, _old_data)
print(json_compare.compare_result)
print(json_compare.compare_error)
=======================================================================
方式一:
{'field': ':key3', 'error_type': 'field type diff', 'secondResp': "type is <class 'tuple'>", 'firstResp': "type is <class 'list'>"}
{'field': ':object:object_key1', 'error_type': 'field value diff', 'secondResp': 'object_value1', 'firstResp': 'object_value2'}
{'field': ':object:object_key2:sub_key2', 'error_type': 'field missing', 'secondResp': {'xx': 1}, 'firstResp': "Field of 'sub_key2' is not exists"}
{'field': ':object:object_key3:1:list_sub_key2', 'error_type': 'field type diff', 'secondResp': "type is <class 'list'>", 'firstResp': "type is <class 'str'>"}
方式二:
[{'field': ':key3', 'error_type': 'field type diff', 'secondResp': "type is <class 'tuple'>", 'firstResp': "type is <class 'list'>"}, {'field': ':object:object_key1', 'error_type': 'field value diff', 'secondResp': 'object_value1', 'firstResp': 'object_value2'}, {'field': ':object:object_key2:sub_key2', 'error_type': 'field missing', 'secondResp': {'xx': 1}, 'firstResp': "Field of 'sub_key2' is not exists"}, {'field': ':object:object_key3:1:list_sub_key2', 'error_type': 'field type diff', 'secondResp': "type is <class 'list'>", 'firstResp': "type is <class 'str'>"}]
[]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM