Как получить поддерево json, содержащее известный объект - PullRequest
0 голосов
/ 02 апреля 2020

Я хочу извлечь поддерево, содержащее сфокусированное окно, из i3-msg -t get_tree с помощью jq. Я знаю, что сфокусированное окно может быть найдено с помощью

i3-msg -t get_tree | jq ".. | (.nodes? // empty)[] | select(.focused == true)"

Простой пример будет:

{
  "node": [
    {
      "node": {
        "foo": "bar"
      }
    },
    {
      "node": {
        "foo": "foo"
      }
    }
  ]
}

И вывод должен при поиске node При обращении к .foo == "bar" должно получиться

{
  "node": [
    {
      "node": {
        "foo": "bar"
      }
    }
  ]
}

Но я не могу найти подходящий метод для извлечения поддерева, охватывающего root, в этот узел.

Ответы [ 2 ]

1 голос
/ 09 апреля 2020

В исходном вопросе есть два отдельных подвопроса, один из которых связан с использованием .. без ссылки на опубликованный образец JSON, а другой основан на заданном c типе ввода JSON. В этом ответе используется стратегия, основанная на использовании paths в соответствии с:

reduce pv as [$p,$v] (null; setpath($p; $v))

Это может или не может обрабатывать массивы по желанию, частично в зависимости от того, что требуется. Если значения null в массивах вообще не нужны, то целесообразно добавить вызов к walk/1 следующим образом:

walk(if type == "array" then map(select(. != null)) else . end)

В качестве альтернативы, если значения null присутствуют в оригинале должны быть сохранены, может использоваться стратегия, описанная в Приложении ниже.

(1) Проблема, характеризующаяся использованием ..

def pv:
 paths as $p
 | getpath($p)
 | . as $v
 | (.nodes? // empty)[] | select(.focused == true)
 | [$p,$v];

reduce pv as [$p,$v] (null; setpath($p; $v))

Как упоминалось выше, для Устраните все нули во всех массивах, вы можете добавить вызов walk/1. В противном случае, если значения null вставлены в массивы с помощью setpath для сохранения аспектов исходной структуры, см. Приложение ниже.

(2) Для образца JSON, достаточно следующих значений:

def pv:
 paths as $p
 | getpath($p)
 | . as $v
 | (.node? // empty) | select(.foo == "bar")
 | [$p,$v];

reduce pv as [$p,$v] (null; setpath($p; $v))

Для данного образца это дает:

{"node":[{"node":{"foo":"bar"}}]}

Для аналогичных входных данных, если нужно исключить значения null из массивов, просто нажмите на позвоните на walk/1, как и раньше; см. также Приложение ниже.

Приложение

Если значения null, которые могут быть вставлены в массивы с помощью setpath для сохранения исходной структуры, не нужны, простейшие можно изменить null значения в исходном JSON на какое-либо отличительное значение (например, ": null:"), выполнить выборку, обрезать значения null и затем преобразовать отличительное значение обратно в null.

Пример

Например, рассмотрим этот вариант примера foo / bar:

{
  "node": [
    {
      "node": {
        "foo": "foo0"
      }
    },
    {
      "node": {
        "foo": "bar",
        "trouble": [
          null,
          1,
          null
        ]
      }
    },
    {
      "node": {
        "foo": "foo1"
      }
    },
    {
      "node": {
        "foo": "bar",
        "trouble": [
          1,
          2,
          3
        ]
      }
    }
  ],
  "nodes": [
    {
      "node": {
        "foo": "foo0"
      }
    },
    {
      "node": {
        "foo": "bar",
        "trouble": [
          null,
          1,
          null
        ]
      }
    }
  ]
}

Используя ": null:" в качестве отличительного значения, следующий вариант может использоваться «основная» программа, ранее показанная для этого случая:

walk(if type == "array" then map(if . == null then ":null:" else . end) else . end)
| reduce pv as [$p,$v] (null; setpath($p; $v))
| walk(if type == "array"
       then map(select(. != null) | if . == ":null:" then null else . end)
       else . end)
0 голосов
/ 07 апреля 2020
.node |= map(select(.node.foo == "bar"))

Эта концепция называется Обновление назначения

...