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

# 注意: 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 としている環境
- [Install ChefDK](https://docs.chef.io/install_dk.html)
- [Configuring ChefDK: configure-ruby-environment](https://docs.chef.io/chefdk_setup.html#configure-ruby-environment)

# 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で実装)](https://qiita.com/lnznt/items/d4798cb42d463cf1acf1)
[[Python] [Tips] ワンライナー(?)でyaml->json](https://qiita.com/some-nyan/items/598df4af947cf0ce01f7)
[JSONの整形をvim(jq)だけで手軽に済ませてみる](https://dev.classmethod.jp/articles/json-formatting-with-jq/)