LoginSignup
1
0

More than 1 year has passed since last update.

JSON/YAMLの構造を保ったまま文字列値を空文字に置換する

Posted at

TL; DR

json
$ cat sample.json | jq '(.. | select(type == "string")) |= ""'
{
  "foo": "",
  "bar": {
    "baz": "",
    "bool": true
  },
  "num": 42,
  "arr": [
    "",
    "",
    {
      "three": ""
    }
  ]
}
yaml
$ cat sample.yaml | yq '(.. | select(tag == ("" | tag))) |= ""'
foo: ""
bar:
  baz: ""
  bool: true
num: 42
arr:
  - ""
  - ""
  - three: ""

やりたいこと

JSONやYAMLで書かれた設定ファイルのバリデーションチェックをテストするとき、「全部の値が空文字になったテストケースがあれば楽なのに」と思ったので作りました。

単純に値を空文字にすると深い階層が読み込めなくなってしまうので、スキーマを保ったまま文字列の値だけを空文字に置換するようにしています。

これを...
{
  "foo": "FOO",
  "bar": {
    "baz": "BAZ"
  }
}
こうしたい
{
  "foo": "",
  "bar": {
    "baz": ""
  }
}
階層が消えるのは困る
{
  "foo": "",
  "bar": ""
}

JSONの空文字化

jq を使ってJSONを処理します。

$ jq --version
jq-1.6

オブジェクト内の文字列値を再帰的に探索し、それらを空文字列に置き換えることで実現しました。

json
$ cat sample.json
{
  "foo": "FOO",
  "bar": {
    "baz": "BAZ",
    "bool": true
  },
  "num": 42,
  "arr": [
    "one",
    "two",
    {"three": "THREE"}
  ]
}

$ cat sample.json | jq '(.. | select(type == "string")) |= ""'
{
  "foo": "",
  "bar": {
    "baz": "",
    "bool": true
  },
  "num": 42,
  "arr": [
    "",
    "",
    {
      "three": ""
    }
  ]
}

コードの意味は以下の通りです。

(
    # オブジェクト内の全値を再帰的に取得 (Recursive Descent)
    ..
    # 文字列型のみ抽出
    | select(type == "string")
)
# 上記で抽出できた各値を "" で上書き (Update-assignment)
|= ""

YAMLの空文字化

こちらでは yq を使用しました。

$ yq --version
yq (https://github.com/mikefarah/yq/) version 4.20.2

書き方はJSONの場合と同じです。ただし、yqには type 関数が無いため、代わりに tag を用いて文字列型の抽出を行っています。

$ cat sample.yaml
foo: FOO
bar:
  baz: BAZ
  bool: true
num: 42
arr:
  - "one"
  - "two"
  - three: "THREE"

$ cat sample.yaml | yq '(.. | select(tag == ("" | tag))) |= ""'
foo: ""
bar:
  baz: ""
  bool: true
num: 42
arr:
  - ""
  - ""
  - three: ""

tag 関数は式のタグを取得する関数で、デフォルトでは型名が取得できます。

$ echo "a: foo" | yq '.a | tag'
!!str

ただし、!!str のリテラルをべた書きすることはできないので、タグは第一級オブジェクトではなさそうです。
仕方がないので、上記のように「 . のタグが "" のタグと等しい」という回りくどい比較を行っています(解決策をご存じの方はコメントいただけるとありがたいです)。

おわりに

jq/yqは本当に何でもできると改めて実感しました。早く極めてシェル芸人になりたい

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0