如何在Groovy/JavaScript中对比JSON并输出原格式差异
问题:JSON对比需保留原层级结构并标记变更节点
需要对比两个JSON对象,输出与输入JSON格式完全一致的差异结果。例如仅修改L2_Entity_Nm字段值时,期望输出保留原JSON的层级结构,并在发生变更的节点上添加"operation": "UPDATED"字段。但当前参考代码运行后返回的是Difference对象列表格式,不符合预期,需调整代码实现目标。
解决方案:递归遍历对比,构建层级化差异结果
核心思路是递归遍历两个JSON的每一层节点,逐层对比值并保留原结构,仅在变更节点添加标记:
- 遇到对象类型节点:递归对比其子节点,仅保留存在变更的子结构;
- 遇到数组类型节点:按索引逐一对比元素(复杂场景可根据唯一标识匹配);
- 节点值发生变更:在该节点下添加
"operation": "UPDATED"字段; - 无变更的节点不纳入最终结果。
代码实现(Python)
def compare_json(old_json, new_json): diff = {} # 处理新增、更新的节点 for key in new_json: old_val = old_json.get(key) new_val = new_json[key] if old_val is None: # 新增节点,标记为ADDED(可按需调整) diff[key] = {**(new_val if isinstance(new_val, dict) else {"value": new_val}), "operation": "ADDED"} elif isinstance(old_val, dict) and isinstance(new_val, dict): # 递归对比子对象 sub_diff = compare_json(old_val, new_val) if sub_diff: diff[key] = sub_diff elif isinstance(old_val, list) and isinstance(new_val, list): # 数组对比:按索引逐一检查 arr_diff = [] max_len = max(len(old_val), len(new_val)) for i in range(max_len): old_item = old_val[i] if i < len(old_val) else None new_item = new_val[i] if i < len(new_val) else None if old_item is None: arr_diff.append({**(new_item if isinstance(new_item, dict) else {"value": new_item}), "operation": "ADDED"}) elif new_item is None: arr_diff.append({**(old_item if isinstance(old_item, dict) else {"value": old_item}), "operation": "REMOVED"}) elif isinstance(old_item, dict) and isinstance(new_item, dict): item_diff = compare_json(old_item, new_item) if item_diff: arr_diff.append(item_diff) elif old_item != new_item: arr_diff.append({"value": new_item, "operation": "UPDATED"}) if arr_diff: diff[key] = arr_diff elif old_val != new_val: # 值变更,添加UPDATED标记 diff[key] = {"value": new_val, "operation": "UPDATED"} # 处理被删除的节点 for key in old_json: if key not in new_json: diff[key] = {**(old_json[key] if isinstance(old_json[key], dict) else {"value": old_json[key]}), "operation": "REMOVED"} return diff
测试示例
输入旧JSON:
{ "L1_Entity": { "L1_Entity_Nm": "总部", "L2_Entity": { "L2_Entity_Nm": "技术部", "Staff_Count": 50 } } }
输入新JSON:
{ "L1_Entity": { "L1_Entity_Nm": "总部", "L2_Entity": { "L2_Entity_Nm": "研发部", "Staff_Count": 50 } } }
输出结果:
{ "L1_Entity": { "L2_Entity": { "L2_Entity_Nm": { "value": "研发部", "operation": "UPDATED" } } } }
可调整点
- 如果希望将变更值与
operation放在同一层级(而非嵌套value),可修改基本类型值的处理逻辑(注意字符串、数字等基本类型无法直接添加键,需转为字典结构); - 数组对比若需根据对象唯一标识(如
id)匹配而非索引,可修改数组遍历逻辑,先通过唯一键关联新旧元素再对比; - 可按需扩展
operation类型,比如ADDED、REMOVED来覆盖更多场景; - 对于null、日期等特殊类型,需额外添加判断逻辑确保对比准确。
内容的提问来源于stack exchange,提问作者user22174139
相关产品推荐
相关产品推荐

