如何制作JSON叶子的路径?

时间:2017-10-29 20:28:02

标签: json path jq

假设我们有以下JSON:

[
  {
    "dir-1": [
      "file-1.1",
      "file-1.2"
    ]
  },
  "dir-1",
  {
    "dir-2": [
      "file-2.1"
    ]
  }
]

我们希望获得下一个输出:

  "dir-1/file-1.1"
  "dir-1/file-1.2"
  "dir-1"
  "dir-2/file-2.1"

即。获取所有叶子的路径,使用/连接项目。有没有办法在JQ上做到这一点?

我试过这样的事情:

cat source-file | jq 'path(..) | [ .[] | tostring ] | join("/")'

但它不会产生我需要的东西。

3 个答案:

答案 0 :(得分:3)

您可以通过将路径与其值合并来利用流的工作方式。 Streams只会为叶值发出path, value对。只需忽略编号的索引。

$ jq --stream '
select(length == 2) | [(.[0][] | select(strings)), .[1]] | join("/")
' source-file

返回:

"dir-1/file-1.1"
"dir-1/file-1.2"
"dir-1"
"dir-2/file-2.1"

答案 1 :(得分:0)

此解决方案类似于Jeff Mercado使用tostreamflatten

的解决方案
tostream | select(length==2) | .[0] |= map(strings) | flatten | join("/")

Try it online at jqplay.org

另一种方法是使用递归函数来遍历输入,例如

def slashpaths($p):
  def concat($p;$k): if $p=="" then $k else "\($p)/\($k)" end;
  if   type=="array"  then .[] | slashpaths($p)
  elif type=="object" then
       keys_unsorted[] as $k
     | .[$k] | slashpaths(concat($p;$k))
  else concat($p;.) end;
slashpaths("")

Try it online at tio.run!

答案 2 :(得分:0)

使用--stream很好,但以下内容可能不那么深奥:

paths(scalars) as $p
| getpath($p) as $v
| ($p | map(strings) + [$v])
| join("/")

(如果使用jq 1.4或更早版本,并且如果任何叶子可能是数字或布尔值或null,则上面的[$v]应替换为[$v|tostring]。)

结果是否应被视为"离开的路径"是另一回事......