【问题标题】:How can I completely sort arbitrary JSON using jq?如何使用 jq 对任意 JSON 进行完全排序?
【发布时间】:2016-11-10 11:53:25
【问题描述】:

我想区分两个 JSON 文本文件。不幸的是,它们是按任意顺序构建的,所以当它们在语义上相同时我会得到差异。我想使用 jq (或其他)以任何类型的完整顺序对它们进行排序,以消除仅由于元素排序引起的差异。

--sort-keys 解决了一半的问题,但它不能对数组进行排序。

我对jq一无所知,不知道如何编写一个保留所有数据的jq递归过滤器;任何帮助将不胜感激。

我意识到逐行“差异”输出不一定是比较两个复杂对象的最佳方法,但在这种情况下,我知道这两个文件非常相似(几乎相同)并且逐行差异对我来说很好。

Using jq or alternative command line tools to diff JSON files 回答了一个非常相似的问题,但不打印差异。另外,我想保存排序后的结果,所以我真正想要的只是一个对 JSON 进行排序的过滤程序。

【问题讨论】:

标签: json sorting jq


【解决方案1】:

这是一个使用通用函数 sorted_walk/1 的解决方案(之所以如此命名,原因在下面的后记中描述)。

标准化.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

【讨论】:

  • 正是我需要的,谢谢!我看到您在相关帖子中发布了此解决方案的变体,但此处更简单的示例回答了许多问题。
【解决方案2】:

我想比较两个 JSON 文本文件。

jd-set 选项一起使用:

没有输出意味着没有区别。

$ jd -set A.json B.json

差异显示为@路径和+或-。

$ 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"}

https://github.com/josephburnett/jd#command-line-usage

【讨论】:

  • 喜欢学习让我的生活更轻松的新工具。感谢您使用“new to me”jd 分享答案 :)
【解决方案3】:

我很惊讶这不是一个更受欢迎的问题/答案。我还没有看到任何其他 json 深度排序解决方案。也许每个人都喜欢一遍又一遍地解决同一个问题。

这是@peak's excellent solution above 的包装器,它将它包装到一个shell 脚本中,该脚本在管道中或与文件args 一起工作。

#!/usr/bin/env bash

# json normalizer function
# Recursively sort an entire json file, keys and arrays
# jq  --sort-keys is top level only
# Alphabetize a json file's dict's such that they are always in the same order
# Makes json diff'able and should be run on any json data that's in source control to prevent excessive diffs from dict reordering.

[ "${DEBUG}" ] && set -x
TMP_FILE="$(mktemp)"
trap 'rm -f -- "${TMP_FILE}"' EXIT

cat > "${TMP_FILE}" <<-EOT
# 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
EOT

# Don't pollute stdout with debug output
[ "${DEBUG}" ] && cat $TMP_FILE > /dev/stderr

if [ "$1" ] ; then
    jq -S -f ${TMP_FILE}  $1
else
    jq -S -f ${TMP_FILE} < /dev/stdin
fi

【讨论】:

    猜你喜欢
    • 2021-07-26
    • 2017-08-29
    • 2018-10-11
    • 1970-01-01
    • 2020-03-06
    • 2021-04-29
    • 2019-07-07
    • 1970-01-01
    • 2021-11-20
    相关资源
    最近更新 更多