雑学

どーも!

たかぽんです!

今回はjson形式の記述をcsv形式に変換して保存をしていこうと思います!

普段は需要無いと思いますが、なんらかのログをjson形式で出していて、それを確認したい...!

という際などは便利そうですね...!

ではみていきます!

jsonからcsv形式に変換する

さて、ではまずどうやってやっていくのか...

今回はターミナルでjqコマンドを使ってやっていきます。

jqコマンド自体はjsonをいい感じに綺麗に表示してくれるだけのコマンドと思われがちですが...

csvへの変換も出来てしまうんですね...!

今回の記事はMac向けではあるんですが、jqコマンドはWindowsでも使用できるようです。(インストール周り少し違うようですが...)

よければjqコマンドのインストール周り調べてみて、お試しください!

(僕も時間があれば試してみようと思います!)

では、早速やっていこうと思います。

brewのインストール

まずはjqコマンドをインストールする必要があります。

そのために必要なbrewコマンドもインストールの必要があるので、そこからやっていきましょう。

brewのインストールは"brew -v"で確認することができます。(場所はどこでも大丈夫です)

(base) Takapon:MyProject taka$ brew -v
Homebrew 2.5.8
Homebrew/homebrew-core (git revision 6e8854; last commit 2020-11-03)
Homebrew/homebrew-cask (git revision f69bb; last commit 2020-11-03)
(base) Takapon:MyProject taka$

バージョン情報ではなく、Command Not Found的な何かが出てきた場合は入っていない可能性が高いので、入れましょう!

以下の記事を参考にインストールしてみてください。

さて、brewを入れた方は今度はbrewを使ってjqコマンドを使えるよう、インストールしていきます。

以下のコマンドを叩くだけです。

brew install jq

一通りババーッとでてきて処理が終わったらjqコマンドが入っているので、確認してみます。

(base) Takapon:study taka$ jq -h
jq - commandline JSON processor [version 1.6]

Usage:	jq [options] <jq filter> [file...]
	jq [options] --args <jq filter> [strings...]
	jq [options] --jsonargs <jq filter> [JSON_TEXTS...]

...
...
...

上記のように"jq -h"でヘルプを確認することができればjqのインストールに成功しているので、準備OKです!

次は変換元のjsonファイルを簡単に用意します。

jsonファイルを用意する

適当なフォルダに以下の形でJsonファイルを作成します。

実際のケースはここがもっと行数の多いログデータ等になると考えてもらって大丈夫です。

名前は適当にBeforeConvertToCSV.jsonとでもつけておきます。

// BeforeConvertToCSV.json
[
  {
    "id": 1,
    "item1": "test_a_1",
    "item2": "test_a_2",
    "item3": "test_a_3",
		"item4": [
			{
				"item4_1":"test_a_4_1",
			  "item4_2":"test_a_4_2"
			}
		]
  },
  {
    "id": 2,
    "item1": "test_b_1",
    "item2": "test_b_2",
    "item3": "test_b_3",
		"item4": [
			{
				"item4_1":"test_b_4_1",
			  "item4_2":"test_b_4_2"
			}
		]
  },
  {
    "id": 3,
    "item1": "test_c_1",
    "item2": "test_c_2",
    "item3": "test_c_3",
		"item4": [
			{
				"item4_1":"test_c_4_1",
			  "item4_2":"test_c_4_2"
			}
		]
  }
]

では、早速上記からcsvを作っていきましょう...!

jqコマンドでcsvを作成する

細かい解説は後回しにして、今回は上記からcsvを作成してみます!

以下のコマンドを叩いてみましょう!

cat BeforeConvertToCSV.json | jq

catでファイルの中身を出し、その中身をjqコマンドに渡しているんですね。

これで、基本的なjqコマンドの出力が見れるはずです。

本来はjsonを整形して表示してくれる物なんですが...

今回はもともと整形した形で表示しているので、さほど意味ないです...

基本的な使い方をみたので、早速、変換してみましょう!

先ほど保存したファイルと同じファイル下で、以下のコマンドを叩きます。

cat BeforeConvertToCSV.json | jq -r '.[] | [.id, .item1, .item2, .item3, .item4[].item4_1, .item4[].item4_2]|@csv' > AfterConvertToCSV.csv

これで、csvに変換したあとの値がBeforeConvertToCSV.csvと言う名前として保存されます。

実際にcatしてみると...?

(base) Takapon:study taka$ cat AfterConvertToCSV.csv
1,"test_a_1","test_a_2","test_a_3","test_a_4_1","test_a_4_2"
2,"test_b_1","test_b_2","test_b_3","test_b_4_1","test_b_4_2"
3,"test_c_1","test_c_2","test_c_3","test_c_4_1","test_c_4_2"
(base) Takapon:study taka$

それっぽいですね...!

試しに完成したものをmacのデフォルトのnumbersで開いてみます。

いい感じですが...

ただ一点、項目名に一番最初の要素のデータが入っていますね...

これどうにかできないか調べたけど、いまいちわからず...

例えばjsonファイルに項目名を追加したファイルを追加する...とか、出来上がったCSVを編集する形での対応は可能です。

// 以下のように項目名を入れたjsonのデータを一番最初の要素として追加する
[
	{
		"id": "ID",
		"item1": "item1",
		"item2": "item2",
		"item3": "item3",
		"item4": [
			{
				"item4_1":"item4-1",
				"item4_2":"item4-2"
			}
		]
	},
  {
    "id": 1,
    ...
    ...

上記をすると...

以下のように一番上に項目名が追加され...

(base) Takapon:study taka$ cat AfterConvertToCSV.csv
"ID","item1","item2","item3","item4-1","item4-2"
1,"test_a_1","test_a_2","test_a_3","test_a_4_1","test_a_4_2"
2,"test_b_1","test_b_2","test_b_3","test_b_4_1","test_b_4_2"
3,"test_c_1","test_c_2","test_c_3","test_c_4_1","test_c_4_2"

csvをnumbersでみた場合もいい感じになっています。

もちろん、csvをに直接カラムを追加して、対応する項目名をつけていただいてもいいかなと。

では、一通り変換はできたので、もう少し細かい解説をしておこうと思います。

json変換時のオプションはどうやって調べる?

さて、先ほどの例だと先ほどのコマンドで行けたんですが、大抵同じ形式のjsonは少ないと思います...

今回はそこを少しでも対応できるよう、どうやって読み解いていけばいいのか、解説していこうと思います。

コマンドのおさらいです。

cat BeforeConvertToCSV.json | jq -r '.[] | [.id, .item1, .item2, .item3, .item4[].item4_1, .item4[].item4_2]|@csv' > AfterConvertToCSV.csv

"cat BeforeConvertToCSV.json"

までは解説も不要かと思いますが、ただ"BeforeConvertToCSV.json"ファイルの中身を出力しているだけです。

そして、パイプ " | "で繋ぎ、jqコマンドの入力としてcatの出力を渡しているんですね。

jqコマンドのオプション -rは、jsonとして出力しないようにしています。

もし"-r"オプションをつけないと、以下のように意図した挙動にならないのでご注意を!

そして、最も大切なのがその次ですね!

以下がその部分です。

'.[] | [.id, .item1, .item2, .item3, .item4[].item4_1, .item4[].item4_2]|@csv'

これは、まず最初にやっているのが、'.[]'によって、外側の配列部分を取り除いています。

わかりやすいように以下に1単位分の先ほどの例を表示しておきます。

// [           '.[]'で取り除く
  {
    "id": 1,
    "item1": "test_a_1",
    "item2": "test_a_2",
    "item3": "test_a_3",
		"item4": [
			{
				"item4_1":"test_a_4_1",
			  "item4_2":"test_a_4_2"
			}
		]
  },
// ]

実際に、以下のコマンドを実行すると配列部分が消えているのがわかるかと思います。

cat BeforeConvertToCSV.json | jq '.[]'

では次に、またまたパイプがあるんですが、これは先ほどとは違い、jqコマンドでの表記のため、役割が違います。

そちらの説明をする前に、以下を実行してみてください。

(base) Takapon:study taka$ cat BeforeConvertToCSV.json | jq '.[].id, .[].item1'
"ID"
1
2
3
"item1"
"test_a_1"
"test_b_1"
"test_c_1"

このようにして、".[]"で不要な部分を取り除いたあと、その下にある値を取得することができます。

上記ではそれぞれのIDとitem1の値を取得しています。

では、さらに以下を実行します。

(base) Takapon:study taka$ cat BeforeConvertToCSV.json | jq '.[] | .id, .item1'
"ID"
"item1"
1
"test_a_1"
2
"test_b_1"
3
"test_c_1"

".[]"で中身を取得するんですが、以降の値取得時に全てに対して共通して.[]を取り除くため、一番最初に".[]"時際して、そのあとに".id"や ".item1"と指定して値を取得しています。

取得の順序は前者だと一つのパラメータをまとめて取得していく形ですが、共通処理をまとめて".[]"の記載が一つの場合はそれぞれ一項目ずつ取得しているのがわかりますね。

そして、CSVでの表示をする場合は上記の表示を行ごとに配列で囲ってあげる必要があります。

そのため、以下のようになります。

(base) Takapon:study taka$ cat BeforeConvertToCSV.json | jq '.[] | [.id, .item1]'
[
  "ID",
  "item1"
]
[
  1,
  "test_a_1"
]
[
  2,
  "test_b_1"
]
[
  3,
  "test_c_1"
]

項目ごとにいい感じに配列で括られていますね!

さて、ここまできたらitem4ももうお分かりの方が多いかと思いますが...

item4のようにさらに配列の中に入っている場合は以下のようにして細かく指定してあげれば大丈夫です。

.item4[].item4_1, .item4[].item4_2

例えば以下のように指定すればそれぞれ細かい値まで取得することができます。

(base) Takapon:study taka$ cat BeforeConvertToCSV.json | jq '.[] | [.item4[].item4_1, .item4[].item4_2]'
[
  "item4-1",
  "item4-2"
]
[
  "test_a_4_1",
  "test_a_4_2"
]
[
  "test_b_4_1",
  "test_b_4_2"
]
[
  "test_c_4_1",
  "test_c_4_2"
]

そして、csv化する場合は最後に " | @csv" をつけることで@csvに対応した形式にして出力することができます。

なので、イメージとしては...

" <全要素に共通して取り除く(or辿っていく)必要がある部分> | [ .要素1, .要素2 , .要素3 , .........] | @csv"

といった感じでしょうか。

そして、最後の以下の箇所は指定したファイル名(AfterConvertToCSV.csv)として書き出すと言うことをやっているだけですね。

 > AfterConvertToCSV.csv

以上が大まかな解説です!

基本的なjsonには対応できるかな...?と思います!

また、一部の値が特定の値の場合のみに上記を取得する...等も設定できるようですので、よければ詳しく調べてみてください!

(そのうち時間があれば試してみようと思います...!)

まとめ

さて、今回はjson形式のデータをcsv形式に変換する方法をみていきました!

jqコマンドの存在は知っていてたんですが、csv変換までできるとは...!

おそらく大抵のことはもうコマンドでなんとかなるんでしょうね...きっと...

こういった便利コマンドは知っているのと知らないのではだいぶん違うと思うので、しっかり蓄えていきたいところですね...!

またなにかしらみつけたら記事にしていこうと思います!

それでわ!

おすすめの記事