created: 2023-04-03T09:00:13.846Z

jq で jsonにパースできる文字列はオブジェクトにパースして出力する

たとえば、このように文字列なんだけどjsonとしてパースできるもののこと。

{
  "s": "{\"b\": 1}"
}

"{\"b\": 1}" は JSON としてパースできるので、↓のようにパースした結果を得たい。(ことが多い)

{
  "s": {
    "b": 1
  }
}

実装

こんなjqスクリプトを書けば、JSONオブジェクトにパースできるものはパースしてくれるようになる。

with_entries(
    if (
        (.value | type == "string")
        and (.value | fromjson? | type) == "object"
    )
    then
        .value |= fromjson
    else
        .
    end
)
$ echo '{"s": "{\"b\": 1}"}' | jq --from-file=/tmp/_.jq
{
  "s": {
    "b": 1
  }
}

説明

  1. with_entries()関数は、オブジェクト内の各エントリーに対して関数を適用するもの。このスクリプトでは、各エントリーに対して後述の関数を適用することで、オブジェクト内の値を処理することになる。

  2. if文は、条件分岐を行うためのもの。このスクリプトでは、以下の条件で分岐している。

    • (.value | type == "string"): 値が文字列である場合
    • and (.value | fromjson? | type) == "object": 値をJSONパースした結果がオブジェクトである場合。つまりJSONとしてパース可能である場合
  3. thenブロックは、条件が真である場合に実行される処理

    • .valueをJSONパースした結果を再度.valueに代入している
    • |= は代入を行う二項演算子
  4. elseブロックは、条件が偽である場合に実行される。このスクリプトでは、.valueをそのまま返す。

サイバーセキュリティの教科書
[ad] サイバーセキュリティの教科書
Thomas Kranz, Smoky (単行本(ソフトカバー))