LoginSignup
3
6

More than 1 year has passed since last update.

ワンライナーでのJSON, YAMLの整形や変換とその相違

Last updated at Posted at 2018-11-09

注意: Ruby V3.1では非互換

YAMLにアンカー、エイリアスがあるとエラーとなります。
その場合、YAML.loadであればYAML.unsafe_loadに置き換えてください。


コマンドラインから Ruby | Python | jq を用いた JSON <-> YAML の変換、および JSON, YAML, XML の整形の例 を示す。

環境

$ ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin15]

$ python --version
Python 3.8.2

$ jq --version
jq-1.6

MAC OS 10.13.6 に Chef Development Kit Version: 3.3.23 を導入し echo 'eval "$(chef shell-init bash)"' >> ~/.bash_profile としている環境

jqとその前提であるyqの導入方法例

環境 Fedora 32 (Workstation Edition)

$ sudo yum install jq
...
$ pip3 install --user yq
...

#JSON -> YAML の変換

Ruby による JSON -> YAML の変換

  • ruby -r json -r yaml -e "puts YAML.dump_stream(JSON.parse(STDIN.read))"
$ echo '{ "foo": { "bar":0, "baz":1 }, "qux": { "quux":2, "corge":3 } }' | \
ruby -r json -r yaml -e "puts YAML.dump_stream(JSON.parse(STDIN.read))"
---
foo:
  bar: 0
  baz: 1
qux:
  quux: 2
  corge: 3

Python による JSON -> YAML の変換

  • python -c "import yaml; import json; import sys; print(yaml.dump(json.load(sys.stdin)))"
$ echo '{ "foo": { "bar":0, "baz":1 }, "qux": { "quux":2, "corge":3 } }' | python -c "import yaml; import json; import sys; print(yaml.dump(json.load(sys.stdin)))"
foo:
  bar: 0
  baz: 1
qux:
  corge: 3
  quux: 2

Python 3.8.2では問題なかったのですが、Python 3.6.2ではimport yamlが以下のエラーで失敗。
ModuleNotFoundError: No module named 'yaml'

PyYAMLモジュールが必要なのかもしれません。
https://pcl.solima.net/pyblog/archives/567
https://qiita.com/sot528/items/dc401a2d9676f9cda01f

yq -y . による JSON -> YAML の変換

$ echo '{ "foo": { "bar":0, "baz":1 }, "qux": { "quux":2, "corge":3 } }' | yq -y . 
foo:
  bar: 0
  baz: 1
qux:
  quux: 2
  corge: 3

YAML -> JSON の変換

Ruby による YAML -> JSON の変換

  • ruby -r json -r yaml -e "puts JSON.pretty_generate(YAML.load(STDIN.read))"

$ echo "
---
foo:
  bar: 0
  baz: 1
qux:
  quux: 2
  corge: 3
" | ruby -r json -r yaml -e "puts JSON.pretty_generate(YAML.load(STDIN.read))"
{
  "foo": {
    "bar": 0,
    "baz": 1
  },
  "qux": {
    "quux": 2,
    "corge": 3
  }
}

Python による YAML -> JSON の変換

  • python -c "import yaml; import json; import sys; print(json.dumps(yaml.load(sys.stdin, Loader=yaml.FullLoader), indent=2))"
$ echo "
---
foo:
  bar: 0
  baz: 1
qux:
  quux: 2
  corge: 3
" | python -c "import yaml; import json; import sys; print(json.dumps(yaml.load(sys.stdin, Loader=yaml.FullLoader), indent=2))"
{
  "foo": {
    "bar": 0,
    "baz": 1
  },
  "qux": {
    "quux": 2,
    "corge": 3
  }
}

上と同様にPythonのレベルによってはPyYAMLが必要となる可能性がある。

yq . による YAML -> JSON の変換

echo "
---
foo:
  bar: 0
  baz: 1
qux:
  quux: 2
  corge: 3
"  | yq .
{
  "foo": {
    "bar": 0,
    "baz": 1
  },
  "qux": {
    "quux": 2,
    "corge": 3
  }
}

#JSONの整形

Ruby による JSON の整形

  • ruby -r json -e "puts JSON.pretty_generate(JSON.parse(STDIN.read))"
$ echo '{ "foo": { "bar":0, "baz":1 }, "qux": { "quux":2, "corge":3 } }' | \
ruby -r json -e "puts JSON.pretty_generate(JSON.parse(STDIN.read))"
{
  "foo": {
    "bar": 0,
    "baz": 1
  },
  "qux": {
    "quux": 2,
    "corge": 3
  }
}

当初JSON.loadを使用していたが、{ "json_class": "Chef::Role" } にて失敗することがあった為、JSON.perseに置き換え

Python による JSON の整形

  • python -c "import json; import sys; print(json.dumps(json.load(sys.stdin), indent=2))"
$ echo '{ "foo": { "bar":0, "baz":1 }, "qux": { "quux":2, "corge":3 } }' | \
python -c "import json; import sys; print(json.dumps(json.load(sys.stdin), indent=2))"
{
  "foo": {
    "bar": 0,
    "baz": 1
  },
  "qux": {
    "quux": 2,
    "corge": 3
  }
}

yq . による JSON の整形

$ echo '{ "foo": { "bar":0, "baz":1 }, "qux": { "quux":2, "corge":3 } }' | yq .
{
  "foo": {
    "bar": 0,
    "baz": 1
  },
  "qux": {
    "quux": 2,
    "corge": 3
  }
}

#YAMLの整形

Ruby による YAML の整形

  • ruby -r yaml -e "puts YAML.dump_stream(YAML.load(STDIN.read))"
$ echo "
---
foo:
     bar:     0
     baz: 1
qux:
  quux: 2
  corge: 3
" | ruby -r yaml -e "puts YAML.dump_stream(YAML.load(STDIN.read))"
---
foo:
  bar: 0
  baz: 1
qux:
  quux: 2
  corge: 3

Python による YAML の整形

  • python -c "import yaml; import sys; print(yaml.dump(yaml.load(sys.stdin, Loader=yaml.FullLoader)))"
$ echo "
---
foo:
     bar:     0
     baz: 1
qux:
  quux: 2
  corge: 3
" | python -c "import yaml; import sys; print(yaml.dump(yaml.load(sys.stdin, Loader=yaml.FullLoader)))"
foo:
  bar: 0
  baz: 1
qux:
  corge: 3
  quux: 2

上と同様にPythonのレベルによってはPyYAMLが必要となる可能性がある。

yq -y . による YAML の整形

$ echo "
---
foo:
     bar:     0
     baz: 1
qux:
  quux: 2
  corge: 3
" | yq -y . 
foo:
  bar: 0
  baz: 1
qux:
  quux: 2
  corge: 3

YAML整形の相違

yq -y . ruby python
directoryにおける順序 保たれる 保たれる  保たれない
&id001, *id001などによる参照 展開される &1などに変更 &id001などに変更
インデント あける傾向 つめる傾向 つめる傾向
YAMLフロースタイル ブロックスタイルに展開 ブロックスタイルに展開 ブロックスタイルに展開
コメント 削除 削除 削除
>によるヒアドキュメント 行をまとめる 行をまとめる 行をまとめる
縦線によるヒアドキュメント 先頭行は縦棒を除いてつめ、全体を'で囲いその内部で改行を保つ 書式は保たれる 先頭行は縦棒を除いてつめ、全体を'で囲いその内部で改行を保つ
文字列のvalueにおける前後の'や" 削除 削除 削除
>によるvalueである文字列の内容が'文字で開始される場合 文字列全体を'で囲い、内部の'は''(シングルクォート2つ)に置き換え 文字列全体を"(ダブルクォート)で囲い、内部の'はそのまま 文字列全体を'で囲い、内部の'は''(シングルクォート2つ)に置き換え
>によるvalueである文字列の内容が"文字で開始される場合 文字列全体を'で囲い、内部の"はそのまま 文字列全体を"(ダブルクォート)で囲い、内部の"は"とエスケープ 文字列全体を'で囲い、内部の"はそのまま

インデントはオプションにより制御できるかもしれない
コメントを自動的に残すのは困難か。

#XMLの整形

  • ruby -r nokogiri -e "puts Nokogiri::XML(STDIN.read, &:noblanks).to_xml"
$ echo '<?xml version="1.1" encoding="UTF-8"?>  <foo>    <bar>val</bar>  </foo>' | \
ruby -r nokogiri -e "puts Nokogiri::XML(STDIN.read, &:noblanks).to_xml"
<?xml version="1.1" encoding="UTF-8"?>
<foo>
  <bar>val</bar>
</foo>

#参考
YAML <-> JSON 変換 (Rubyで実装)
[Python] [Tips] ワンライナー(?)でyaml->json
JSONの整形をvim(jq)だけで手軽に済ませてみる

3
6
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
3
6