Как я могу полностью отсортировать произвольный JSON с помощью jq?

Я хочу различать два текстовых файла JSON. К сожалению, они построены в произвольном порядке, поэтому я получаю различия, когда они семантически идентичны. Я хотел бы использовать jq (или что-то еще) для сортировки их в любом полном порядке, чтобы устранить различия только из-за упорядочения элементов.

--sort-keys решает половину проблемы, но не сортирует массивы.

Я довольно незнаком с jq и не знаю, как написать рекурсивный фильтр jq, который сохраняет все данные; любая помощь будьте благодарны.

Я понимаю, что линейный вывод "diff" не обязательно является лучшим способом сравнения двух сложных объектов, но в этом случае я знаю, что два файла очень похожи (почти идентичны), и линейные различия хороши для моих целей.

использование jq или альтернативных инструментов командной строки для различения файлов json отвечает на очень похожий вопрос, но не печатает различия. Кроме того, я хочу сохранить отсортированные результаты, поэтому я действительно хочу программа фильтрации для сортировки JSON.

2 ответов


вот решение, использующее общую функцию 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.


Я хочу различать два текстовых файла JSON.

использовать jd С :

отсутствие выхода означает отсутствие разницы.

$ jd -set A.json B.json

различия отображаются в виде @ path и + или -.

$ jd -set A.json C.json

@ ["People",{}]
+ "Carla"

дифференциалы выход может быть использован как файлы патч с .

$ 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