JSON比较工具 - 在线免费比较JSON | JSON差异对比
该工具可在线免费比较两个JSON对象或文件,逐项列出新增、删除和修改的所有数值,并以颜色标注差异类型,同时用类似JSON路径的表达式标明每处差异在数据结构中的具体位置。比较过程完全在浏览器本地进行,无需注册,适合调试API响应、核对配置文件版本以及排查数据同步问题等场景。
JSON 差异工具
文档
JSON 比较工具通常称为 JSON 差异工具,用于比较两个 JSON(JavaScript 对象表示法)值,并报告它们之间发生的变化。它会列出每个新增、删除或修改的属性或数组项,并给出其在数据中的确切位置。本页通过基于实际比较逻辑的示例,说明 whiz.tools 的 JSON 比较工具如何工作。
什么是 JSON 比较?
JSON 比较是指对照检查两个 JSON 文档,以找出差异的过程。JSON 文档是一段由对象(花括号中的键值对)、数组(方括号中的有序列表)和字符串、数字、布尔值、null 等原始值构成的文本。当文档超过几行后,凭肉眼比较会变得缓慢且容易出错,因此比较工具会自动进行匹配并突出显示每项变化。
开发人员使用这种比较来检查 API 响应、跟踪配置文件的变化、验证数据迁移是否丢失信息,以及审查版本控制中 JSON 文件的修改。
工具如何比较两个 JSON 值
工具先使用标准 JSON 解析器解析两个输入,然后逐层同时遍历生成的两个值。每一步按以下顺序提出三个问题:
- 两个值的类型是否不同(例如一个是对象,另一个是数字),或者其中一个是
null而另一个不是?如果是,工具会在该位置记录一次修改,并停止向更深层比较。 - 两个值是否都是原始值(字符串、数字、布尔值或 null)?如果是,工具会直接比较它们。任何差异都算作修改,包括从数字
123变为字符串"123"。 - **两个值是否都是对象或都是数组?**如果是,工具会根据以下规则比较其内容,并递归比较其中嵌套的对象或数组。
每个差异都会记录一个路径,例如 user.address.city 或 tags[1],因此很容易在原始文档中找到。对象成员之间用点号连接,数组项则用方括号中的索引表示。若文档最顶层出现差异,例如数组被对象替换,数据内部没有可用路径,因此会标记为 $。这是 RFC 9535(JSONPath 标准)定义的根标识符,表示整个文档。
比较对象
对于两个 JSON 对象,工具会收集任一对象中出现的所有键。对于每个键:
- 如果该键只存在于第二个对象中,则它是一个新增属性。
- 如果该键只存在于第一个对象中,则它是一个删除属性。
- 如果该键同时存在于两个对象中,工具会递归比较这两个值。
键的顺序不影响结果。JSON 标准没有规定对象成员的顺序,因此 {"a":1,"b":2} 和 {"b":2,"a":1} 会被视为相同。
比较数组
数组按位置而不是按内容进行比较。工具会逐个索引遍历两个数组,比较每个索引处的值,直到较长数组的末尾。如果一个数组较短,较长数组末尾多出的项会被报告为新增或删除。
这意味着工具从不尝试根据数组项的内容进行匹配。它不会发现某个对象从索引 1“移动”到了索引 2;它只会看到每个索引处的值发生了变化。在数组中间删除或插入一项,会使后续每一项都向前或向后移动一个位置,因此通常会显示为多项分别修改,而不是一次明确的新增或删除。
计算示例
示例 1:比较两个对象
第一个 JSON:
1{ "user": { "address": { "city": "New York", "zip": "10001" } } }
2第二个 JSON:
1{ "user": { "address": { "city": "Boston", "zip": "02108" } } }
2结果:
- 已修改
user.address.city:"New York"→"Boston" - 已修改
user.address.zip:"10001"→"02108"
示例 2:数组末尾发生变化
第一个 JSON:
1{ "tags": ["important", "urgent", "review"] }
2第二个 JSON:
1{ "tags": ["important", "critical", "review", "documentation"] }
2索引 0 未改变,索引 1 发生变化,索引 2 未改变,索引 3 仅存在于第二个数组中。结果:
- 已修改
tags[1]:"urgent"→"critical" - 已新增
tags[3]:"documentation"
示例 3:从数组中间删除一项
本示例展示从数组中间删除一项时会发生什么,因为这是一种常见的困惑来源。
第一个 JSON:
1{
2 "products": [
3 { "id": 1, "name": "Laptop", "price": 999.99 },
4 { "id": 2, "name": "Mouse", "price": 24.99 },
5 { "id": 3, "name": "Keyboard", "price": 59.99 }
6 ]
7}
8第二个 JSON,其中删除了“Mouse”项,并在末尾添加了“Monitor”项:
1{
2 "products": [
3 { "id": 1, "name": "Laptop", "price": 899.99 },
4 { "id": 3, "name": "Keyboard", "price": 59.99 },
5 { "id": 4, "name": "Monitor", "price": 349.99 }
6 ]
7}
8看到这些内容时,人们会说“删除了 Mouse,添加了 Monitor”。但由于工具严格按索引比较,它不会这样判断。它会将索引 0 与索引 0、索引 1 与索引 1、索引 2 与索引 2 分别进行比较,因此被删除项之后的每个字段都会与错误的对象对齐。实际结果是七项修改:
- 已修改
products[0].price:999.99→899.99 - 已修改
products[1].id:2→3 - 已修改
products[1].name:"Mouse"→"Keyboard" - 已修改
products[1].price:24.99→59.99 - 已修改
products[2].id:3→4 - 已修改
products[2].name:"Keyboard"→"Monitor" - 已修改
products[2].price:59.99→349.99
要在比较此类列表时获得更清晰的结果,请先以相同方式对两个数组排序或设置键,例如将两个列表按相同顺序排列,或在比较前根据 ID 字段匹配对象。
工具不会执行的操作
- **它不会根据内容匹配数组项。**如上所示,它完全按索引位置比较,因此无法识别某项是移动了而不是发生了变化。
- **它不会检测循环引用。**这在实际使用中并不构成限制:两个输入都来自
JSON.parse,该函数始终构建普通树结构,不可能生成引用自身的值。有效 JSON 文本本身也不可能包含循环引用。 - **它不提供比较前对数组排序的设置。**在粘贴输入前重新排列数组项,是避免上述索引偏移影响的唯一方法。
如何使用工具
- 将第一个 JSON 文档粘贴到左侧文本框,将第二个粘贴到右侧文本框。
- 当两个文本框都包含文本后,工具会自动比较;也可以点击“比较”手动运行。
- 阅读结果列表。每一行都会显示一个路径,例如
user.age,以及它是新增、删除还是修改,并将旧值和新值并排显示。 - 点击“复制”,以纯文本形式复制结果。
如果文本框中的内容不是有效 JSON,工具会在该文本框下方显示错误,而不是进行比较。如果两个文本框中的内容都无效,两个错误会同时出现。
常见问题
两个 JSON 值之间什么算作差异?
如果某个属性或数组项只存在于两个文档中的一个,或者同时存在但值或类型不同,则它们存在差异。将值从数字 5 改为字符串 "5" 算作修改,即使它们看起来可能相似。
项的顺序重要吗? 这取决于容器。JSON 对象没有规定成员顺序,因此两个对象即使键和值的顺序不同,只要内容相同,也会被视为相同。数组是有序的,工具按索引位置比较数组,因此将某项移动到其他位置会被报告为一系列修改,而不是移动。
结果路径 $ 表示什么?
它表示整个文档发生了变化,而不是其中某一部分发生变化。当两个输入在顶层属于不同类型的值时,就会出现这种情况,例如一侧是数组,另一侧是对象,或者两个普通数字 1 和 2。$ 是 RFC 9535(JSONPath 标准)中的根标识符。
我的 JSON 数据会发送到服务器吗? 不会。比较在浏览器中使用 JavaScript 运行,不会上传任何内容。
缩进或压缩等格式会影响结果吗? 不会。两个输入都会先解析为 JSON 值,然后再进行比较,因此空白、缩进和换行都不会产生影响。比较的只有实际数据。
工具能比较带注释或尾随逗号的 JSON 吗? 不能。RFC 8259 定义的标准 JSON 不允许注释或尾随逗号。包含这些内容的输入会被判定为无效并拒绝。
参考文献
- IETF。《JavaScript 对象表示法(JSON)数据交换格式》。RFC 8259,2017 年 十二月。
- IETF。《JavaScript 对象表示法(JSON)补丁》。RFC 6902,2013年4月。
- IETF。《JSONPath:JSON 查询表达式》。RFC 9535,2024 年 二月。(第 2.2 节定义了根标识符
$。) - Mozilla Developer Network。《JSON.parse()》。