jqの出力深度を制限します。

jqの出力深度を制限します。

を使用して任意の文書を閲覧したいjq。これを行うには、jq文書の深さを制限し、最初のn(たとえば3)レベルのみを表示したいと思います。

次のJSONドキュメントがあるとします。

{
    "a": {
        "b": {
            "c": {
                "d": {
                    "e": "foo"
                }
            }
        }
    },
    "f": {
        "g": {
            "h": {
                "i": {
                    "j": "bar"
                }
            }
        }
    },
    "k": {
        "l": {
            "m": {
                "n": {
                    "o": "baz"
                }
            }
        }
    }
}

結果を期待しています

{
    "a": {
        "b": {
            "c": {}
        }
    },
    "f": {
        "g": {
            "h": {}
        }
    },
    "k": {
        "l": {
            "m": {}
        }
    }
}

文書の構造をあらかじめ知っていれば、かなり簡単な作業ですが、そうでない場合が多いです。これがjq、ドキュメント構造の最初のnレベルのみを表示できるようにしたい理由です。これは、辞書と配列を任意に入れ子にすることができます。

より複雑な例は次のとおりです。

[
    { "a": { "b": { "c": { "d": { "e": "foo"}}}}},
    { "f": [ { "g": "foo"}]},
    [ "h", "i", "j" ]
]

私が結果を期待しているところ

[
    { "a": { "b": {}},
    { "f": [{}]},
    [ "h", "i", "j" ]
]

私はjqこれを行うことができますか?

答え1

del関数を配列/オブジェクト値イテレータと組み合わせて.[]?4番目のネストレベルからキー/値を削除すると、目的の結果が得られるようです。

$ jq 'del(.[]?[]?[]?[]?)' <<'EOT'
[
    { "a": { "b": { "c": { "d": { "e": "foo"}}}}},
    { "f": [ { "g": "foo"}]},
    [ "h", "i", "j" ]
]
EOT
[
  {
    "a": {
      "b": {}
    }
  },
  {
    "f": [
      {}
    ]
  },
  [
    "h",
    "i",
    "j"
  ]
]

.[]?配列やオブジェクト以外の項目を繰り返すときの苦情を防ぐには、イテレータフィルタのバージョンが必要です。.[]jq

正直なところ、.[][]ドキュメントのどこにも上記の形式(デフォルトでは:)の配列/オブジェクトイテレータフィルタへの直接的な言及はありません。あまり簡潔ではありませんが、明確に文書化されたバージョンは次のとおりです。

$ jq 'del(.[]? | .[]? | .[]? | .[]?)' ...

答え2

を使用すると、特定のpath(..)文書に対して可能なすべてのパス式を生成できます。その後、たとえば、select(length > 3)長すぎるものを選択できます。で削除できますdelpaths()

jqこれは単一の整数(withとして渡すことができます--argjson)で簡単にパラメータ化できますが、path(..)同時に不必要に「重い」(結果を生み出す)簡潔に見える式を書くことができるという利点があります。すべて文書のパス)。

$ jq 'delpaths([path(..) | select(length > 3)])' file
{
  "a": {
    "b": {
      "c": {}
    }
  },
  "f": {
    "g": {
      "h": {}
    }
  },
  "k": {
    "l": {
      "m": {}
    }
  }
}

質問の最後にあるサンプル文書を使用してテストしてください。

$ jq . file
[
  {
    "a": {
      "b": {
        "c": {
          "d": {
            "e": "foo"
          }
        }
      }
    }
  },
  {
    "f": [
      {
        "g": "foo"
      }
    ]
  },
  [
    "h",
    "i",
    "j"
  ]
]
$ jq --argjson d 1 'delpaths([path(..) | select(length > $d)])' file
[
  {},
  {},
  []
]
$ jq --argjson d 2 'delpaths([path(..) | select(length > $d)])' file
[
  {
    "a": {}
  },
  {
    "f": []
  },
  [
    "h",
    "i",
    "j"
  ]
]
$ jq --argjson d 3 'delpaths([path(..) | select(length > $d)])' file
[
  {
    "a": {
      "b": {}
    }
  },
  {
    "f": [
      {}
    ]
  },
  [
    "h",
    "i",
    "j"
  ]
]

答え3

これはjqバージョンごとに変更される可能性があるスペースに依存しているため理想的ではないかもしれませんが、他のツールを使用して同様の状況に適用できるという点では強力な方法です。

jqはきれいな印刷が完了した後、jsonツリーの下の要素の前にスペースを追加します。したがって、特定の数の先行スペースがある行で逆方向grepを実行すると、特定の深さを超えるすべての要素を削除できます。以下の例では、あなたの例と同様に、深さが4以上の要素を削除しました。

grifball@grifball-Computer:~$ cat limit-output.json
{"a":{"b":{"c":{"d":{"e":"foo"}}}},"f":{"g":{"h":{"i":{"j":"bar"}}}},"k":{"l":{"m":{"n":{"o":"baz"}}}}}
grifball@grifball-Computer:~$ cat limit-output.json | jq
{
  "a": {
    "b": {
      "c": {
        "d": {
          "e": "foo"
        }
      }
    }
  },
  "f": {
    "g": {
      "h": {
        "i": {
          "j": "bar"
        }
      }
    }
  },
  "k": {
    "l": {
      "m": {
        "n": {
          "o": "baz"
        }
      }
    }
  }
}
grifball@grifball-Computer:~$ cat limit-output.json | jq | grep -v '^\s\{8\}'
{
  "a": {
    "b": {
      "c": {
      }
    }
  },
  "f": {
    "g": {
      "h": {
      }
    }
  },
  "k": {
    "l": {
      "m": {
      }
    }
  }
}

関連情報