jqコマンドでJSON形式をkey-value形式に変換

# 目的
JSON形式によって階層化されたテキストデータ構造をkey-value形式で表す。
\# 個人的にJSON形式のデータを1ラインごとに見てみたいなと思って...
以下、入力になるJSON形式のデータと期待する出力結果。

```json:入力データ（JSON）
{
  "links": {
    "self": "http://localhost:35357/v3/projects",
    "previous": null,
    "next": null
  },
  "projects": [
    {
      "is_domain": false,
      "description": "Bootstrap project for initializing the cloud.",
      "links": {
        "self": "http://localhost:35357/v3/projects/27e8446cfa4240ae98fc70797a16739c"
      },
      "enabled": true,
      "id": "27e8446cfa4240ae98fc70797a16739c",
      "parent_id": "default",
      "domain_id": "default",
      "name": "admin"
    },
    {
      "is_domain": false,
      "description": "Service Project",
      "links": {
        "self": "http://localhost:35357/v3/projects/9e1eb34a5d4e45ee9ba95421d6f94548"
      },
      "enabled": true,
      "id": "9e1eb34a5d4e45ee9ba95421d6f94548",
      "parent_id": "default",
      "domain_id": "default",
      "name": "service"
    }
  ]
}
```

```text:出力結果
links.self=http://localhost:35357/v3/projects
projects.0.description=Bootstrap project for initializing the cloud.
projects.0.links.self=http://localhost:35357/v3/projects/27e8446cfa4240ae98fc70797a16739c
projects.0.enabled=true
projects.0.id=27e8446cfa4240ae98fc70797a16739c
projects.0.parent_id=default
projects.0.domain_id=default
projects.0.name=admin
projects.1.description=Service Project
projects.1.links.self=http://localhost:35357/v3/projects/9e1eb34a5d4e45ee9ba95421d6f94548
projects.1.enabled=true
projects.1.id=9e1eb34a5d4e45ee9ba95421d6f94548
projects.1.parent_id=default
projects.1.domain_id=default
projects.1.name=service
```

# 実行環境
LinuxディストリビューションのCentOS7環境下にて検証する。
`$ cat /etc/centos-release`
`CentOS Linux release 7.5.1804 (Core)`

また、jqコマンドのバージョンは下記のとおり。
`$ jq --version`
`jq-1.5`

入力データとなるjson形式のファイルを`test.json`とする。
\# 内容は前述したものと同様

```json:test.json
{
  "links": {
    "self": "http://localhost:35357/v3/projects",
    "previous": null,
    "next": null
  },
  "projects": [
    {
      "is_domain": false,
      "description": "Bootstrap project for initializing the cloud.",
      "links": {
        "self": "http://localhost:35357/v3/projects/27e8446cfa4240ae98fc70797a16739c"
      },
      "enabled": true,
      "id": "27e8446cfa4240ae98fc70797a16739c",
      "parent_id": "default",
      "domain_id": "default",
      "name": "admin"
    },
    {
      "is_domain": false,
      "description": "Service Project",
      "links": {
        "self": "http://localhost:35357/v3/projects/9e1eb34a5d4e45ee9ba95421d6f94548"
      },
      "enabled": true,
      "id": "9e1eb34a5d4e45ee9ba95421d6f94548",
      "parent_id": "default",
      "domain_id": "default",
      "name": "service"
    }
  ]
}
```

# key-value形式に変換（コマンド実行）
jqコマンドのマニュアルに記載してあるが、pathsとgetpath組み込み関数を使用することで実現可能。
\# leaf_pathsは廃止予定らしいので使用していません
詳細はオフィシャルのマニュアルページやオンラインマニュアルをご参照ください。

```shell:コマンド例１
$ cat test.json | jq -r 'paths(scalars)|@csv'
"links","self"
"projects",0,"description"
"projects",0,"links","self"
"projects",0,"enabled"
"projects",0,"id"
"projects",0,"parent_id"
"projects",0,"domain_id"
"projects",0,"name"
"projects",1,"description"
"projects",1,"links","self"
"projects",1,"enabled"
"projects",1,"id"
"projects",1,"parent_id"
"projects",1,"domain_id"
"projects",1,"name"
```

```shell:コマンド例２
$ cat test.json | jq -r 'getpath(paths(scalars))'
http://localhost:35357/v3/projects
Bootstrap project for initializing the cloud.
http://localhost:35357/v3/projects/27e8446cfa4240ae98fc70797a16739c
true
27e8446cfa4240ae98fc70797a16739c
default
default
admin
Service Project
http://localhost:35357/v3/projects/9e1eb34a5d4e45ee9ba95421d6f94548
true
9e1eb34a5d4e45ee9ba95421d6f94548
default
default
service
```

上記のコマンド結果では、keyとvalueが一致しているかわからないので、同時に処理されるように工夫する。

```shell:コマンド例３
$ cat test.json | jq -r 'paths(scalars) as $path | ($path | @csv | tostring) + "=" + (getpath($path) | tostring)'
"links","self"=http://localhost:35357/v3/projects
"projects",0,"description"=Bootstrap project for initializing the cloud.
"projects",0,"links","self"=http://localhost:35357/v3/projects/27e8446cfa4240ae98fc70797a16739c
"projects",0,"enabled"=true
"projects",0,"id"=27e8446cfa4240ae98fc70797a16739c
"projects",0,"parent_id"=default
"projects",0,"domain_id"=default
"projects",0,"name"=admin
"projects",1,"description"=Service Project
"projects",1,"links","self"=http://localhost:35357/v3/projects/9e1eb34a5d4e45ee9ba95421d6f94548
"projects",1,"enabled"=true
"projects",1,"id"=9e1eb34a5d4e45ee9ba95421d6f94548
"projects",1,"parent_id"=default
"projects",1,"domain_id"=default
"projects",1,"name"=service
```

ポイントは "パスを変数に格納", "文字列に変換", "文字列の結合" をすること。
階層の連結を表す記号（上記の場合カンマ","）を変更したり、ダブルクォートを除去したい場合は、次のコマンドを実行する。

```shell:コマンド例４
$ cat test.json | jq -r 'paths(scalars) as $path | ($path | @csv | tostring | gsub(
","; ".") | gsub("\""; "")) + "=" + (getpath($path) | tostring)'
links.self=http://localhost:35357/v3/projects
projects.0.description=Bootstrap project for initializing the cloud.
projects.0.links.self=http://localhost:35357/v3/projects/27e8446cfa4240ae98fc70797a16739c
projects.0.enabled=true
projects.0.id=27e8446cfa4240ae98fc70797a16739c
projects.0.parent_id=default
projects.0.domain_id=default
projects.0.name=admin
projects.1.description=Service Project
projects.1.links.self=http://localhost:35357/v3/projects/9e1eb34a5d4e45ee9ba95421d6f94548
projects.1.enabled=true
projects.1.id=9e1eb34a5d4e45ee9ba95421d6f94548
projects.1.parent_id=default
projects.1.domain_id=default
projects.1.name=service
```

階層の連結記号を外部変数から参照したいなら`--arg`オプションをつければ実現可能。

```shell:コマンド例５
$ cat test.json | jq -r --arg conn "-->" 'paths(scalars) as $path | ($path | @csv | tostring | gsub(
","; $conn) | gsub("\""; "")) + "=" + (getpath($path) | tostring)'
projects-->0-->description=Bootstrap project for initializing the cloud.
projects-->0-->links-->self=http://localhost:35357/v3/projects/27e8446cfa4240ae98fc70797a16739c
projects-->0-->enabled=true
projects-->0-->id=27e8446cfa4240ae98fc70797a16739c
projects-->0-->parent_id=default
projects-->0-->domain_id=default
projects-->0-->name=admin
projects-->1-->description=Service Project
projects-->1-->links-->self=http://localhost:35357/v3/projects/9e1eb34a5d4e45ee9ba95421d6f94548
projects-->1-->enabled=true
projects-->1-->id=9e1eb34a5d4e45ee9ba95421d6f94548
projects-->1-->parent_id=default
projects-->1-->domain_id=default
projects-->1-->name=service
```

# おわりに
うまいことkey-value形式に変換できているように見えるが、valueがnullになっているパスは表示されていません。
null値も表示させたいけど今のところわからないので、表示のさせ方がわかったら追記しときます。