JSON 格式化 / 压缩 / 校验JSON 转义 / 去转义JSON 对比JSON 键排序JSON 转字符串 / 字符串转 JSONJSON 转 XMLXML 转 JSONJSON 数组转 CSVCSV 转 JSON 数组JSON 与 YAML 互转JSON 生成代码定义查询参数与 JSON 互转Cookie 与 JSON 互转JSON 与 Properties 互转
—
JSON 对比
比较两段 JSON,列出新增、删除与修改的键路径
JSON 对比:为什么文本 diff 看 JSON 会满屏噪声
文本 diff 与结构化 diff 的差别
把两个 JSON 用文本 diff 工具比较,会出现两类问题:
- 格式差异被当成内容差异。A 是缩进 2 空格、B 是压缩成一行,文本 diff 会认为整段都变了。实际上数据完全一致。
- 键顺序差异被当成内容差异。JSON 对象是无序的(规范明确如此),
{"a":1,"b":2}与{"b":2,"a":1}语义相同,但文本 diff 会标出两处删除两处新增。
结构化 diff 的做法是先解析成对象再比较:忽略空白与键顺序,只在真实的路径上报告差异。输出的形式是"哪个路径、从什么变成了什么",这比行号定位有用得多——尤其在深度嵌套的配置或接口响应里,行号几乎不提供信息。
四个必须明确的判定规则
比较 JSON 时,有几个地方"看起来一样"和"确实相同"不是一回事,工具必须选定规则并说明:
| 情况 | 是否算差异 | 说明 |
|---|---|---|
1 vs 1.0 | 通常不算 | 数值相等;但字符串形式不同 |
1(数字)vs "1"(字符串) | 算 | 类型不同,JSON 里它们是两种值 |
键不存在 vs 值为 null | 算 | "没有这个字段"和"字段是空"语义不同,接口里尤其如此 |
true vs "true" | 算 | 布尔与字符串,不能混用 |
第三行是最常见的争议点。在 JSON Merge Patch(RFC 7396)这类规范里,null 被用来表示"删除该键",正是因为这两个状态必须区分开。
数组比较的特殊困难
对象有键可以对齐,数组没有。所以"[1,2,3] 变成 [3,2,1]"这件事有两种解释:
- 元素被重新排序——如果数组本身是有序集合(比如按时间排的用户列表),这是重排。
- 三个元素各自被替换——如果把数组当无序集合看,那全部内容没变。
工具无法知道你的意图,所以必须选一种算法。常见做法是基于最长公共子序列(LCS),它能识别出"某几个元素保留、某几个被插入或删除",对中间插入新元素的情况表现最好——而这恰恰是实际开发中最常见的变更(往列表里加一项)。纯按下标逐位比较的实现在插入场景下会把后面所有元素都标成"变了",噪声极大。
还有一层:如果数组元素是对象,且有你已知的唯一键(比如 id),按 id 对齐比按位置对齐准确得多。这只是通用的结构算法做不到的,需要针对数据结构定制。
它做不到的事
- 不理解语义重命名。把
userName改名成username,工具只能报"删除了一个键、新增了一个键",它不知道这是一次改名。 - 不校验结构合法性。两边都是合法 JSON 才比得下去;结构不符合你的接口约定不会被发现,这需要 JSON Schema。
- 大文件性能。结构化 diff 的复杂度在嵌套深、数组大时会明显上升。几 MB 的 JSON 建议先用 jq 之类的工具裁剪到关心的子树再比。
实用工作流
- 先确认两边都是合法 JSON(本工具会在解析失败时直接报错,而不是给出错误的对比结果)。
- 看差异的路径,而不是位置。路径能直接告诉你"是配置里的某一项变了"。
- 数组出现大量差异时,先考虑是不是元素顺序变了,或者是不是该按唯一键对齐。
- 如果结果是给 diff 评审用的,先用键排序工具把两边都排序再比,可以消掉键顺序带来的噪声。
常见问题
数组顺序变了怎么算?
按相同下标逐项比较。如果元素只是位置移动,对应下标的旧值和新值不同,会被标记为"修改"。
对比会忽略字段顺序吗?
会。对象的键顺序不同但内容相同,视为无差异;只有值的增删改才会被列出。