jq: рекурсивно объединяет объекты и объединяет массивы - PullRequest
0 голосов
/ 07 декабря 2018

У меня есть два файла json, orig.json и patch.json, которые имеют похожие форматы.

orig.json:

{
        "a": {
                "a1": "original a1",
                "a2": "original a2",
                "list": ["baz", "bar"]
        },
        "b": "original value B"
}

patch.json:

{
    "a": {
            "a1": "patch a1",
            "list": ["foo"]
    },
    "c": "original c"
}

В настоящее время я использую jq для их рекурсивного объединения.Однако поведение jq по умолчанию для списков - просто переназначение.Пример вывода из jq с использованием $ jq -s '.[0] * .[1]' orig.json patch.json:

{
  "a": {
    "a1": "patch a1",
    "a2": "original a2",
    "list": [
      "foo"
    ]
  },
  "b": "original value B",
  "c": "original c"
}

Обратите внимание, что a.list теперь равно patch.json's a.list.Я хочу, чтобы новый a.list был списком orig.json и списками patch.json.Другими словами, я хочу, чтобы a.list равнялся ["baz", "bar", "foo"].

Есть ли способ, которым я могу легко сделать это с помощью jq, возможно, переопределив стратегию слияния по умолчанию для массивов?

Ответы [ 2 ]

0 голосов
/ 07 декабря 2018

Вот обобщенная функция, которая рекурсивно комбинирует две составные сущности JSON путем объединения массивов в одной и той же позиции:

# Recursively meld a and b,
# concatenating arrays and
# favoring b when there is a conflict 
def meld(a; b):
  if (a|type) == "object" and (b|type) == "object"
  then reduce ([a,b]|add|keys_unsorted[]) as $k ({}; 
    .[$k] = meld( a[$k]; b[$k]) )
  elif (a|type) == "array" and (b|type) == "array"
  then a+b
  elif b == null then a
  else b
  end;

Вывод meld ($ orig; $ patch)

С $для orig задано содержимое файла orig.json, а для $ patch - содержимое файла patch.json:

{
  "a": {
    "a1": "patch a1",
    "a2": "original a2",
    "list": [
      "baz",
      "bar",
      "foo"
    ]
  },
  "b": "original value B",
  "c": "original c"
}
0 голосов
/ 07 декабря 2018

Вызов:

jq -f patch.jq --argfile patch patch.json  orig.json

, где patch.jq содержит:

(.a.list + $patch.a.list) as $a
| . + $patch
| .a.list = $a

производит:

{
  "a": {
    "a1": "patch a1",
    "list": [
      "baz",
      "bar",
      "foo"
    ]
  },
  "b": "original value B",
  "c": "original c"
}
...