はじめに
以前の投稿で、IBM i 上でDBのデータをCSVに書き出す方法を書きました。
最近では、JSON形式でのデータを求められる事も増えてきており、CSVから変換しているという話も聞いています。
そこで、今回はCSVをJSONに変換する方法を紹介していきます。
CSVへの出力方法はこちらで書いています。
https://qiita.com/tom_m_m/items/660cb6ce0bafaeac832f
本記事は、IBM i 7.5 環境を元に記載しております。
JSONへの変換方法
CSVファイルをJSONに変換する方法はいくつか考えられますが、Pythonで変換するのが簡単かと思います。
IBM iでもPASE環境であれば、Pythonも実行できるので全てIBM i上で完結してJSONファイルの書き出しまで行うことができます。
PASE環境へのアクセスは、以下になります。
- ACSからSSH端末を開く
- コマンドラインでsshアクセスする
- VSCodeなどを使ってアクセスする
どの方法でも大丈夫ですので、好きな方法で良いです。
Pythonは、yumでインストール可能ですので、インストールが必要です。
変換スクリプト
CSVファイルをJSONファイルに変換するだけであれば、とても簡単なスクリプトで実行できます。
以下がサンプルです。
入力CSVファイル
と出力JSONファイル
は、スクリプト実行時に指定できるようにしています。
Pythonで操作するので、IFS上に入力ファイルをおいてください。
出力ファイルもIFS上にかきだされます。
ファイルは、IFS上のパスで指定します。
/home/user1/inputfile.csv
のような形式です。
import csv
import json
import sys
input_file = sys.argv[1]
output_file = sys.argv[2]
print('入力CSVファイル: ', input_file)
print('出力JSONファイル: ', output_file)
# open CSV
with open(input_file, 'r', encoding='utf-8') as f:
d_reader = csv.DictReader(f)
d_list = [row for row in d_reader]
# export JSON
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(d_list, f, ensure_ascii=False)
前回の記事で書き出したCSVファイルを使って動作を確認してみます。
書き出し済みのファイルはこちらです。
demo # cat cpytoimpf_output.csv
"8010302","センシャブラシ","洗車ブラシ","洗車ブラシ","2","1","1","バラ","ボール","ケース",260,189.00,238.00
"8010303","ツヤダシラバー","つや出しラバー","つや出しラバー","2","1","1","バラ","ボール","ケース",550,398.00,495.00
"8010304","テンネンハチミツワックス","天然蜂蜜ワックス","天然蜂蜜ワックス","2","1","1","バラ","ボール","ケース",900,765.00,880.00
"8010305","ワックススプレータイプ","ワックススプレー","ワックススプレータイプ","2","1","1","バラ","ボール","ケース",400,288.00,360.00
"8020101","ヘルメット フル","ヘルメット フル","ヘルメット フル","2","2","1","バラ","ボール","ケース",6200,3840.00,4800.00
"8020102","ヘルメット","ヘルメット","ヘルメット","2","2","1","バラ","ボール","ケース",6000,3560.00,4450.00
"8020103","グローブ","グローブ","グローブ","2","2","1","バラ","ボール","ケース",4800,3040.00,3800.00
"13010101","フードオオブクロ","フード 大袋","フード 大袋","1","4","3","バラ","ボール","ケース",700,585.00,630.00
使用するファイルを以下のようになっており、スクリプトexport_json.py
を使ってCSVファイルcpytoimpf_output.csv
をJSONファイルpython_export_output.json
に変換します。
demo
|-- cpytoimpf_output.csv
|-- export_json.py
では、実行してみます。
demo # python export_json.py ./cpytoimpf_output.csv ./python_export_output.json
入力CSVファイル: ./cpytoimpf_output.csv
出力JSONファイル: ./python_export_output.json
出力が長いので途中までにしますが、書き出したファイルはこちらになります。
ちゃんとJSON形式になっていますね。
DBのカラム名がキーになっており、valueにデータが入っています。
demo # cat python_export_output.json
[{"CSHSHCD": "8010302", "CSHSHNK": "センシャブラシ", "CSHSHNR": "洗車ブラシ", "CSHSHNM": "洗車ブラシ", "CSHHB1C": "2", "CSHHB2C": "1", "CSHHB3C": "1", "CSHTMN1": "バラ", "CSHTMN2": "ボール", "CSHTMN3": "ケース", "CSHKUGP": "260", "CSHSPG1": "189.00", "CSHHPG1": "238.00"}, {"CSHSHCD": "8010303", "CSHSHNK": "ツヤダシラバー", "CSHSHNR": "つや出しラバー", "CSHSHNM": "つや出しラバー", "CSHHB1C": "2", "CSHHB2C": "1", "CSHHB3C": "1", "CSHTMN1": "バラ", "CSHTMN2": "ボール", "CSHTMN3": "ケース", "CSHKUGP": "550", "CSHSPG1": "398.00", "CSHHPG1": "495.00"}, {"CSHSHCD": "8010304", "CSHSHNK": "テンネンハチミツワックス", "CSHSHNR": "天然蜂蜜ワックス", "CSHSHNM": "天然蜂蜜ワックス", "CSHHB1C": "2", "CSHHB2C": "1", "CSHHB3C": "1", "CSHTMN1": "バラ", "CSHTMN2": "ボール", "CSHTMN3": "ケース", "CSHKUGP": "900", "CSHSPG1": "765.00", "CSHHPG1": "880.00"}, {"CSHSHCD": "8010305", "CSHSHNK": "ワックススプレータイプ", "CSHSHNR": "ワ
JSONへの書き出しができているのはわかりますが、見づらいです。
そこで、jq
というコマンドが便利です。
jq
もyumでインストールできますので、使ってみてください。
単純に中身を表示するだけであれば、このように使うと良いです。
demo # cat python_export_output.json | jq .
[
{
"CSHSHCD": "8010302",
"CSHSHNK": "センシャブラシ",
"CSHSHNR": "洗車ブラシ",
"CSHSHNM": "洗車ブラシ",
"CSHHB1C": "2",
"CSHHB2C": "1",
"CSHHB3C": "1",
"CSHTMN1": "バラ",
"CSHTMN2": "ボール",
"CSHTMN3": "ケース",
"CSHKUGP": "260",
"CSHSPG1": "189.00",
"CSHHPG1": "238.00"
},
{
"CSHSHCD": "8010303",
"CSHSHNK": "ツヤダシラバー",
"CSHSHNR": "つや出しラバー",
"CSHSHNM": "つや出しラバー",
"CSHHB1C": "2",
"CSHHB2C": "1",
"CSHHB3C": "1",
"CSHTMN1": "バラ",
"CSHTMN2": "ボール",
"CSHTMN3": "ケース",
"CSHKUGP": "550",
"CSHSPG1": "398.00",
"CSHHPG1": "495.00"
使い方の一部ですが、フィルタリングなどもできます。
demo # cat python_export_output.json | jq '.[] | select(.CSHSHCD == "8010303")'
{
"CSHSHCD": "8010303",
"CSHSHNK": "ツヤダシラバー",
"CSHSHNR": "つや出しラバー",
"CSHSHNM": "つや出しラバー",
"CSHHB1C": "2",
"CSHHB2C": "1",
"CSHHB3C": "1",
"CSHTMN1": "バラ",
"CSHTMN2": "ボール",
"CSHTMN3": "ケース",
"CSHKUGP": "550",
"CSHSPG1": "398.00",
"CSHHPG1": "495.00"
}
Pythonで加工もできる
先程は、単純にすべてのデータをJSONに変換しました。
ただ、一部のデータだけ書き出したいという要望もあるでしょう。
Python内で、CSVのデータを配列に格納しているので加工もできますし、取り出すデータを指定することも可能です。
例えば、スクリプトを以下のように変更してみます。
import csv
import json
import sys
input_file = sys.argv[1]
output_file = sys.argv[2]
print('入力CSVファイル: ', input_file)
print('出力JSONファイル: ', output_file)
# open CSV
with open(input_file, 'r', encoding='utf-8') as f:
d_reader = csv.DictReader(f)
rows = list(d_reader)
for i in range(len(rows)):
rows[i] = {'CSHSHNM':rows[i]['CSHSHNM'], 'CSHTMN1':rows[i]['CSHTMN1'], 'CSHHPG1':rows[i]['CSHHPG1']}
## export JSON
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(rows, f, ensure_ascii=False)
こうすると、以下の部分で特定のカラムのみ取り出して書き出すことができます。
for i in range(len(rows)):
rows[i] = {'CSHSHNM':rows[i]['CSHSHNM'], 'CSHTMN1':rows[i]['CSHTMN1'], 'CSHHPG1':rows[i]['CSHHPG1']}
このスクリプトで出力したファイルは、このように特定のカラム情報のみを含んだものになります。
demo # cat ext_out.json | jq .
[
{
"CSHSHNM": "洗車ブラシ",
"CSHTMN1": "バラ",
"CSHHPG1": "238.00"
},
{
"CSHSHNM": "つや出しラバー",
"CSHTMN1": "バラ",
"CSHHPG1": "495.00"
},
{
CLプログラムからも呼び出し可能
CLプログラムから、PASEのコマンドを実行できることをご存知でしょうか?
これができるので、CPYTOIMPFからPythonでのJSONファイルへの変換までCLプログラムで一気に実行できちゃいます。
CLプログラムからは、こちらのコマンドでPythonを実行できます。
Pythonの実行バイナリは、絶対パスで指定する必要があるので注意です。
CALL QP2SHELL PARAM('/QOpenSys/pkgs/bin/python' 'Pythonプログラム')
CPYTOIMPFと一緒にCLプログラムとして書くと、このようになります。
PGM
CPYTOIMPF FROMFILE(DEMO/DEMOTABLE) TOSTMF('/home/demouser/demo/cl_cpytoimpf.csv') MBROPT(*REPLACE) STMFCCSID(01208) RCDDLM(*LF) STRDLM(*DBLQUOTE) RMVBLANK(*BOTH) ADDCOLNAM(*SQL)
SBMJOB CMD(CALL PGM(QP2SHELL) +
PARM('/QOpenSys/pkgs/bin/python' +
'/home/demouser/demo/json_ext_out.py ' +
'/home/demouser/demo/cl_cpytoimpf.csv' +
'/home/demouser/demo/cl_json_out.json'))
ENDPGM
コンパイルして、実行するとCSVの書き出しからJSONへの変換まで一括して行われます。