steamulo / json-diff
PHP 的 JSON 差分/重新排列/补丁/指针库
Requires
- ext-json: *
Requires (Dev)
- phperf/phpunit: 4.8.37
This package is auto-updated.
Last update: 2024-09-07 18:33:24 UTC
README
用于在两个 JSON 文档之间查找无序差异的 PHP 实现。
目的
- 为了简化两个 JSON 文件之间的更改审查,您可以使用标准 diff 工具在重新排列的格式化 JSON 上进行。
- 通过分析从原始 JSON 中删除和更改的内容来检测破坏性更改。
- 保持对象集合的原始顺序(例如,swagger.json 的参数列表)。
- 创建和应用由 IETF 的 RFC 6902 规范的 JSON Patches。
- 创建和应用由 IETF 的 RFC 7386 规范的 JSON Merge Patches。
- 通过 JSON Pointer 获取和修改数据。
- 通过 JSON 值递归替换。
安装
库
git clone https://github.com/swaggest/json-diff.git
Composer
composer require swaggest/json-diff
库使用
JsonDiff
从两个值(original 和 new)创建 JsonDiff 对象。
$r = new JsonDiff(json_decode($originalJson), json_decode($newJson));
在构造过程中,JsonDiff 将递归地构建 rearranged 值,尽可能保持 original 键的顺序。在 original 中缺失的键将按照它们在 new 中的顺序追加到 rearranged 值的末尾。
如果两个值是对象的数组,JsonDiff 将尝试在这些对象中找到一个共同的唯一字段,并将其用作重新排列的标准。您可以通过 JsonDiff::REARRANGE_ARRAYS 选项启用此行为
$r = new JsonDiff( json_decode($originalJson), json_decode($newJson), JsonDiff::REARRANGE_ARRAYS );
可用选项
REARRANGE_ARRAYS
是一个选项,用于启用 数组重新排列 以最小化差异。STOP_ON_DIFF
是一个选项,通过在发现差异时停止比较来提高性能。JSON_URI_FRAGMENT_ID
是一个选项,用于使用 URI 片段标识符表示法(例如:"#/c%25d")。如果未设置,则使用默认的 JSON 字符串表示法(例如:"/c%d")。SKIP_JSON_PATCH
是一个选项,通过不为此 diff 构建 JsonPatch 来提高性能。SKIP_JSON_MERGE_PATCH
是一个选项,通过不为此 diff 构建 JSON Merge Patch 值来提高性能。TOLERATE_ASSOCIATIVE_ARRAYS
是一个选项,允许关联数组模仿 JSON 对象(不推荐)。COLLECT_MODIFIED_DIFF
是一个选项,用于启用 getModifiedDiff。
选项可以组合使用,例如 JsonDiff::REARRANGE_ARRAYS + JsonDiff::STOP_ON_DIFF
。
getDiffCnt
返回差异总数
getPatch
返回差异的 JsonPatch
getMergePatch
返回差异的 JSON Merge Patch 值
getRearranged
返回新值,并按照原始顺序重新排列。
getRemoved
返回作为原始值部分的移除项。
getRemovedPaths
返回从原始值中移除的JSON
路径列表。
getRemovedCnt
返回移除项的数量。
getAdded
返回作为新值部分的添加项。
getAddedPaths
返回添加到新值中的JSON
路径列表。
getAddedCnt
返回添加项的数量。
getModifiedOriginal
返回作为原始值部分的修改项。
getModifiedNew
返回作为新值部分的修改项。
getModifiedDiff
返回包含原始值和新值路径的ModifiedPathDiff
列表。
默认不收集,需要JsonDiff::COLLECT_MODIFIED_DIFF
选项。
getModifiedPaths
返回从原始值到新值中修改的JSON
路径列表。
getModifiedCnt
返回修改项的数量。
JsonPatch
import
从JSON
-解码的数据创建JsonPatch
实例。
export
从JsonPatch
对象创建补丁数据。
op
向JsonPatch
添加操作。
apply
将补丁应用到JSON
-解码的数据上。
setFlags
更改默认行为。
可用标志
JsonPatch::STRICT_MODE
禁止将空数组转换为对象以创建键。JsonPatch::TOLERATE_ASSOCIATIVE_ARRAYS
允许关联数组模仿JSON对象(不推荐)。
JsonPointer
escapeSegment
转义路径段。
splitPath
从JSON Pointer
字符串创建未转义段的数组。
buildPath
从未转义段的数组创建JSON Pointer
字符串。
add
将值添加到由段指定的数据路径。
get
从由段指定的数据路径获取值。
getByPointer
从由JSON Pointer
字符串指定的数据路径获取值。
remove
从由段指定的数据路径移除值。
JsonMergePatch
apply
将补丁应用到JSON
-解码的数据上。
JsonValueReplace
process
递归地用replace
值替换所有等于search
值的节点。
示例
$originalJson = <<<'JSON' { "key1": [4, 1, 2, 3], "key2": 2, "key3": { "sub0": 0, "sub1": "a", "sub2": "b" }, "key4": [ {"a":1, "b":true, "subs": [{"s":1}, {"s":2}, {"s":3}]}, {"a":2, "b":false}, {"a":3} ] } JSON; $newJson = <<<'JSON' { "key5": "wat", "key1": [5, 1, 2, 3], "key4": [ {"c":false, "a":2}, {"a":1, "b":true, "subs": [{"s":3, "add": true}, {"s":2}, {"s":1}]}, {"c":1, "a":3} ], "key3": { "sub3": 0, "sub2": false, "sub1": "c" } } JSON; $patchJson = <<<'JSON' [ {"value":4,"op":"test","path":"/key1/0"}, {"value":5,"op":"replace","path":"/key1/0"}, {"op":"remove","path":"/key2"}, {"op":"remove","path":"/key3/sub0"}, {"value":"a","op":"test","path":"/key3/sub1"}, {"value":"c","op":"replace","path":"/key3/sub1"}, {"value":"b","op":"test","path":"/key3/sub2"}, {"value":false,"op":"replace","path":"/key3/sub2"}, {"value":0,"op":"add","path":"/key3/sub3"}, {"value":true,"op":"add","path":"/key4/0/subs/2/add"}, {"op":"remove","path":"/key4/1/b"}, {"value":false,"op":"add","path":"/key4/1/c"}, {"value":1,"op":"add","path":"/key4/2/c"}, {"value":"wat","op":"add","path":"/key5"} ] JSON; $diff = new JsonDiff(json_decode($originalJson), json_decode($newJson), JsonDiff::REARRANGE_ARRAYS); $this->assertEquals(json_decode($patchJson), $diff->getPatch()->jsonSerialize()); $original = json_decode($originalJson); $patch = JsonPatch::import(json_decode($patchJson)); $patch->apply($original); $this->assertEquals($diff->getRearranged(), $original);
PHP 类作为 JSON 对象
由于魔法方法和其他限制,PHP 类无法可靠地映射到/从 JSON 对象。在 JsonPointer
中支持 PHP 类的对象,但有局限性
null
等于不存在
数组重新排列
当启用 JsonDiff::REARRANGE_ARRAYS
选项时,数组项将按原始数组的顺序排列。
如果数组包含同质对象,并且这些对象具有具有唯一值的公共属性,则数组将按与原始数组中具有相同属性值的项的位置进行排序。
示例:原始
[{"name": "Alex", "height": 180},{"name": "Joe", "height": 179},{"name": "Jane", "height": 165}]
vs 新
[{"name": "Joe", "height": 179},{"name": "Jane", "height": 168},{"name": "Alex", "height": 180}]
将产生一个补丁
[{"value":165,"op":"test","path":"/2/height"},{"value":168,"op":"replace","path":"/2/height"}]
如果没有找到合格索引属性,则根据项目相等性进行重新排列。
示例:原始
{"data": [{"A": 1, "C": [1, 2, 3]}, {"B": 2}]}
vs 新
{"data": [{"B": 2}, {"A": 1, "C": [3, 2, 1]}]}
将产生无差异。
CLI 工具
已移动到 swaggest/json-cli