跳至内容

JSON比较工具 - 在线免费比较JSON | JSON差异对比

该工具可在线免费比较两个JSON对象或文件,逐项列出新增、删除和修改的所有数值,并以颜色标注差异类型,同时用类似JSON路径的表达式标明每处差异在数据结构中的具体位置。比较过程完全在浏览器本地进行,无需注册,适合调试API响应、核对配置文件版本以及排查数据同步问题等场景。

JSON 差异工具

加载计算器...
📚

文档

JSON 比较工具通常称为 JSON 差异工具,用于比较两个 JSON(JavaScript 对象表示法)值,并报告它们之间发生的变化。它会列出每个新增、删除或修改的属性或数组项,并给出其在数据中的确切位置。本页通过基于实际比较逻辑的示例,说明 whiz.tools 的 JSON 比较工具如何工作。

什么是 JSON 比较?

JSON 比较是指对照检查两个 JSON 文档,以找出差异的过程。JSON 文档是一段由对象(花括号中的键值对)、数组(方括号中的有序列表)和字符串、数字、布尔值、null 等原始值构成的文本。当文档超过几行后,凭肉眼比较会变得缓慢且容易出错,因此比较工具会自动进行匹配并突出显示每项变化。

开发人员使用这种比较来检查 API 响应、跟踪配置文件的变化、验证数据迁移是否丢失信息,以及审查版本控制中 JSON 文件的修改。

工具如何比较两个 JSON 值

工具先使用标准 JSON 解析器解析两个输入,然后逐层同时遍历生成的两个值。每一步按以下顺序提出三个问题:

  1. 两个值的类型是否不同(例如一个是对象,另一个是数字),或者其中一个是 null 而另一个不是?如果是,工具会在该位置记录一次修改,并停止向更深层比较。
  2. 两个值是否都是原始值(字符串、数字、布尔值或 null)?如果是,工具会直接比较它们。任何差异都算作修改,包括从数字 123 变为字符串 "123"。
  3. **两个值是否都是对象或都是数组?**如果是,工具会根据以下规则比较其内容,并递归比较其中嵌套的对象或数组。

每处差异都会记录一个路径,例如 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 文本本身也不可能包含循环引用。
  • **它不提供比较前对数组排序的设置。**在粘贴输入前重新排列数组项,是避免上述索引偏移影响的唯一方法。

如何使用工具

  1. 将第一个 JSON 文档粘贴到左侧文本框,将第二个粘贴到右侧文本框。
  2. 当两个文本框都包含文本后,工具会自动比较;也可以点击“比较”手动运行。
  3. 阅读结果列表。每一行都会显示一个路径,例如 user.age,以及它是新增、删除还是修改,并将旧值和新值并排显示。
  4. 点击“复制”,以纯文本形式复制结果。

如果任一输入框中的文本不是有效的 JSON,工具会对该输入框显示错误,而不是给出比较结果。

常见问题

两个 JSON 值之间什么算作差异? 如果某个属性或数组项只存在于两个文档中的一个,或者同时存在但值或类型不同,则它们存在差异。将值从数字 5 改为字符串 "5" 算作修改,即使它们看起来可能相似。

对象属性的顺序重要吗? 不重要。JSON 对象的成员没有规定的顺序,因此键和值相同但顺序不同的两个对象被视为相同。

数组元素的顺序重要吗? 重要。数组按索引位置进行比较,因此把某个元素移到数组中的另一个位置,会被视为一系列修改,而不是移动。

我的 JSON 数据会发送到服务器吗? 不会发送。比较在浏览器中使用 JavaScript 运行,不会上传任何内容。

缩进或压缩等格式会影响结果吗? 不会影响。两个输入都会先解析为 JSON 值,然后再进行比较,因此空白、缩进和换行都不会产生影响。比较的只有实际数据。

这个工具能比较带注释或尾随逗号的 JSON 吗? 不能比较。RFC 8259 定义的标准 JSON 没有注释语法,而且数组和对象不能有尾随逗号。浏览器的 JSON 解析器会把这样的输入判定为无效。

参考文献

  1. 互联网工程任务组。RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format。RFC 8259 — 对象是无序的名称/值对集合,数组是有序序列,语法只允许在词元之间出现空白字符。
  2. Mozilla 开发者网络。JSON.parse()。JSON.parse() 参考 — 无效的 JSON 会抛出 SyntaxError,数组和对象不能有尾随逗号。