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],因此很容易在原始文档中找到。
比较对象
对于两个 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 对象的成员没有规定的顺序,因此键和值相同但顺序不同的两个对象被视为相同。
数组元素的顺序重要吗? 重要。数组按索引位置进行比较,因此把某个元素移到数组中的另一个位置,会被视为一系列修改,而不是移动。
我的 JSON 数据会发送到服务器吗? 不会发送。比较在浏览器中使用 JavaScript 运行,不会上传任何内容。
缩进或压缩等格式会影响结果吗? 不会影响。两个输入都会先解析为 JSON 值,然后再进行比较,因此空白、缩进和换行都不会产生影响。比较的只有实际数据。
这个工具能比较带注释或尾随逗号的 JSON 吗? 不能比较。RFC 8259 定义的标准 JSON 没有注释语法,而且数组和对象不能有尾随逗号。浏览器的 JSON 解析器会把这样的输入判定为无效。
参考文献
- 互联网工程任务组。RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format。RFC 8259 — 对象是无序的名称/值对集合,数组是有序序列,语法只允许在词元之间出现空白字符。
- Mozilla 开发者网络。JSON.parse()。JSON.parse() 参考 — 无效的 JSON 会抛出 SyntaxError,数组和对象不能有尾随逗号。