如何使用 jq 获取找到的值的索引路径?

How to get the index path of found values using jq?

假设我有一个 JSON 这样的:

{
  "json": [
    "a", 
    [
      "b", 
      "c", 
      [
        "d", 
        "foo", 
        1
      ], 
      [
        [
          42, 
          "foo"
        ]
      ]
    ]
  ]
}

我想要一个包含 foo:

jq 索引路径数组
[
    ".json[1][2][1]",
    ".json[1][3][0][1]"
]

我可以使用 jq 实现吗?如何实现? 我尝试 recurse | .foo 先获取匹配项,但收到错误消息:Cannot index array with string "foo".

首先,我不确定获取jq程序数组的目的是什么。虽然存在这样做的方法,但很少有必要; jq 不提供任何类型的 eval 命令。

jq有路径的概念,是一个字符串和数字组成的数组,表示一个元素在JSON中的位置;这相当于您预期输出中的字符串。例如,".json[1][2][1]" 将表示为 ["json", 1, 2, 1]。标准库包含几个使用此概念操作的函数,例如 getpathsetpathpathsleaf_paths.

因此,我们可以获得给定 JSON 中的所有叶路径并遍历它们,select 那些它们在输入 JSON 中的值为 "foo" 的路径,并从中生成一个数组:

jq '[paths as $path | select(getpath($path) == "foo") | $path]'

这将 return,对于您给定的输入,以下输出:

[
  ["json", 1, 2, 1],
  ["json", 1, 3, 0, 1]
]

现在,虽然这不是必需的,而且很可能表明您正在以错误的方式解决您所面临的任何问题,但可以将这些数组转换为您寻求的 jq 路径字符串通过以下脚本转换每个路径:

".\(map("[\(tojson)]") | join(""))"

完整的脚本因此是:

jq '[paths as $path | select(getpath($path) == "foo") | $path | ".\(map("[\(tojson)]") | join(""))"]'

其输出为:

[
  ".[\"json\"][1][2][1]",
  ".[\"json\"][1][3][0][1]"
]

可以进一步调整 Santiago 的优秀程序以生成请求格式的输出:

def jqpath:
  def t: test("^[A-Za-z_][A-Za-z0-9_]*$");
  reduce .[] as $x
    ("";
     if ($x|type) == "string"
     then . + ($x | if t then ".\(.)" else  ".[" + tojson + "]" end)
     else . + "[\($x)]"
     end);

[paths as $path | select( getpath($path) == "foo" ) | $path | jqpath]


jq -f wrangle.jq input.json

[
  ".json[1][2][1]",
  ".json[1][3][0][1]"
]