我想区分两个JSON文本文件。不幸的是,它们是以任意顺序构造的,所以当它们在语义上相同时,我会得到差异。我想使用jq(或其他)以任何类型的完整顺序对它们进行排序,以消除仅因元素排序而产生的差异。
- sort-keys解决了问题的一半,但它没有对数组进行排序。
我对jq一无所知,也不知道如何编写一个保存所有数据的jq递归过滤器;任何帮助将不胜感激。
我意识到逐行'差异'输出不一定是比较两个复杂对象的最佳方法,但在这种情况下,我知道这两个文件非常相似(几乎完全相同),并且逐行差异对我来说很好。
Using jq or alternative command line tools to diff JSON files回答了一个非常相似的问题,但没有打印出这些差异。另外,我想保存排序结果,所以我真正想要的只是一个用于对JSON进行排序的过滤程序。
答案 0 :(得分:8)
以下是使用泛型函数 sorted_walk / 1 的解决方案(因为下面的附言中描述的原因而命名)。
normalize.jq:
# Apply f to composite entities recursively using keys[], and to atoms
def sorted_walk(f):
. as $in
| if type == "object" then
reduce keys[] as $key
( {}; . + { ($key): ($in[$key] | sorted_walk(f)) } ) | f
elif type == "array" then map( sorted_walk(f) ) | f
else f
end;
def normalize: sorted_walk(if type == "array" then sort else . end);
normalize
使用bash的例子:
diff <(jq -S -f normalize.jq FILE1) <(jq -S -f normalize.jq FILE2)
POSTSCRIPT:首次发布此回复后修改了walk/1
的内置定义:它现在使用keys_unsorted
而不是keys
。
答案 1 :(得分:5)
我想区分两个JSON文本文件。
将jd
与-set
选项一起使用:
没有输出意味着没有区别。
$ jd -set A.json B.json
差异显示为@ path和+或 - 。
$ jd -set A.json C.json
@ ["People",{}]
+ "Carla"
输出差异也可以用作-p
选项的补丁文件。
$ jd -set -o patch A.json C.json; jd -set -p patch B.json
{"City":"Boston","People":["John","Carla","Bryan"],"State":"MA"}