JSONの扱い方を解説!PythonやJavaScript・Swiftでの基本的な使用法とは。配列取得や出力方法も紹介
PythonでJSON・辞書型オブジェクト変換
動作確認環境は以下です。
- $ python –version
- Python 3.8.2
JSON・辞書型オブジェクト変換コード
PythonでJSONを扱う場合はWeb APIからの取得・データベースからの取得・ファイルストレージからの読込などが考えられます。
ここではローカルにあるJSONファイルからJSON定義を読み込み、取得した想定でコードを提示しました。
debug関数で型と変数の値を表示できるようにしています。デバッグの際にご利用下さい。
- import json, pprint
- def debug(value):
- print(type(value))
- # print(value)
- pp = pprint.PrettyPrinter(indent=2)
- pp.pprint(value)
- return
- print(‘— JSONファイル読込 —‘)
- readWrapper = open(‘input.json’, ‘r’)
- print(‘— JSONの取得 —‘)
- inputJson = readWrapper.read()
- debug(inputJson)
- print(‘— JSONを辞書型オブジェクトに変換 —‘)
- dictObj = json.loads(inputJson)
- debug(dictObj)
- print(‘— 辞書型オブジェクトをJSONに変換 —‘)
- jsonStr = json.dumps(dictObj)
- debug(jsonStr)
- print(‘— JSONファイル書込 —‘)
- writeWrapper = open(‘output.json’ , ‘w’)
- writeWrapper.write(jsonStr)
- print(‘— JSONファイル整形出力 —‘)
- print(‘python -m json.tool output.json’)
Pythonでテキストファイルを読み込むときは、TextIOWrapperを使用します。第2引数にrを渡せば読み込み用、wを渡せば書込み用です。
「python -m json.tool output.json」を出力したJSONに対して実行すれば、整形された状態で出力することができます。
またpprintはデバッグ時のデータ表示に便利です。もし見辛い場合はコメントアウトされている通常のprintを利用下さい。
json.loadsとjson.dumps
json.loadsはJSONを辞書型オブジェクトに変換するメソッドです。
PythonでJSONを扱うときは辞書型オブジェクトにパースしてから、追加・編集・削除を行うようにします。
パース(parse)とはデータを解析しやすいデータ構造に変換する処理のことです。
json.loadsとjson.loadは別のメソッドなので注意して下さい。
またjson.dumpsは辞書型オブジェクトをJSONに変換するメソッドです。修正後の辞書型オブジェクトを元のJSON形式に戻します。
PythonでJSON由来の辞書型オブジェクト操作
JSONから取得した辞書型オブジェクトの操作方法と出力方法をまとめました。
JSON由来の辞書型オブジェクト操作コード
以下のコードは前項のコードの下に追加していけば動作します。
- print(‘— 辞書型オブジェクトの操作 —‘)
- # 参照
- print(dictObj[‘name’])
- print(dictObj[‘children’])
- # 追加
- dictObj[‘pattern’] = ‘brown tabby’
- print(dictObj[‘pattern’])
- debug(dictObj)
- # 編集
- dictObj[‘pattern’] = ‘calico’
- print(dictObj[‘pattern’])
- debug(dictObj)
- # 削除
- dictObj.pop(‘pattern’)
- debug(dictObj)
Pythonで辞書型の値にアクセスする際は「オブジェクト[キー]」のように記述します。
またpopメソッドの引数にキーを指定すれば、指定したキーの要素を削除することができます。
辞書型オブジェクト
辞書型あるいはディクショナリ(dictionary)型の特徴はkeyとvalueのセットで1つの要素を表すデータ構造です。
辞書型であればJSONのデータ構造を保ったままPythonで取り扱うことができます。
上記以外にも多くのアクセス方法や操作メソッドが提供されているので、リファレンスなどを参照し適切な方法を見つけて下さい。
PythonでJSON由来の配列操作
オブジェクトが入れ子になっているだけで、基本的な操作方法は前項と変わりません。
異なる点といえば配列の要素にアクセスするときにインデックスを指定するくらいでしょう。
- print(‘— 辞書型オブジェクト配列の操作 —‘)
- # 参照
- print(dictObj[‘children’][0][‘name’])
- print(dictObj[‘children’][1][‘name’])
- # 追加
- dictObj[‘children’].append({
- “id”: 4,
- “name”: “nora”,
- “vaccin”: False,
- “detail”: {
- “personality”: “naughty”
- }
- })
- debug(dictObj[‘children’])
- # 編集
- dictObj[‘children’][2][‘name’] = ‘sabi’
- dictObj[‘children’][2][‘vaccin’] = True
- debug(dictObj[‘children’][2])
- # 削除
- newHome = dictObj[‘children’].pop()
- debug(newHome)
- debug(dictObj[‘children’])
JavaScriptでJSON・JavaScriptオブジェクト変換
動作確認環境は以下です。
- https://code.jquery.com/jquery-3.5.0.min.js
- Google Chrome v81.0.4044.113
- <!DOCTYPE html>
- <html lang=”ja”>
- <head>
- <meta charset=”utf-8″ />
- <title>JavaScript JSON</title>
- <script src=”https://code.jquery.com/jquery-3.5.0.min.js”
- integrity=”sha256-xNzN2a4ltkB44Mc/Jz3pT4iU1cmeR0FkXs4pru/JxaQ=”
- crossorigin=”anonymous”></script>
- </head>
- <body>
- <script type=”text/javascript” src=”script.js”></script>
- </body>
- </html>
以降、script.jsのコードを記載します。
JSON・JavaScriptオブジェクト変換コード
クライアント側のブラウザで動作するJavaScriptは、ローカルファイルを読み込むことはできません。
APIやサーバー上のJSONファイルを読み込んで処理を行うのが基本です。
このためサンプルコードは「127.0.0.1:3000」環境でサーバーを起動して動作させるようにしています。
- function debug(value) {
- const copy = JSON.parse(JSON.stringify(value));
- console.log(typeof copy);
- console.log(copy);
- }
- console.log(‘— JSONファイル読込 —‘);
- $.getJSON(‘http://127.0.0.1:3000/input.json’, (inputObj) => {
- console.log(‘— JavaScriptオブジェクトの取得 —‘);
- debug(inputObj);
- console.log(‘— JavaScriptオブジェクトをJSONに変換 —‘);
- let jsonStr = JSON.stringify(inputObj);
- debug(jsonStr);
- console.log(‘— JSONをJavaScriptオブジェクトに変換 —‘);
- let jsObj = JSON.parse(jsonStr);
- debug(jsObj);
- });
JSON.stringifyとJSON.parse
JavaScriptでJSONをパースする際に使用するのが、JSON.parseメソッドです。
このメソッドで文字列のJSONをJavaScriptオブジェクトに変換します。またJSON.stringifyメソッドで元に戻すことが可能です。
JSONとJavaScriptオブジェクトは別物なので、取り扱う際は混同しないようにご注意下さい。
JSON由来のJavaScriptオブジェクト操作
JavaScriptオブジェクトを操作していきましょう。
JavaScriptオブジェクト操作コード
JavaScriptオブジェクトの操作コードは以下の通りです。
- console.log(‘JavaScriptオブジェクトの操作’);
- // 参照
- console.log(jsObj.name);
- console.log(jsObj.children);
- // 追加
- jsObj.pattern = ‘brown tabby’;
- console.log(jsObj.pattern);
- debug(jsObj);
- // 編集
- jsObj.pattern = ‘calico’;
- console.log(jsObj.pattern);
- debug(jsObj);
- // 削除
- delete jsObj.pattern;
- debug(jsObj);
Pythonと異なり「jsObj.pattern」のようにドットをつなげてアクセスします。
他に特筆すべき点はプロパティの削除メソッドdeleteです。
JSONとJavaScriptオブジェクト
JSONはキーをダブルクオーテーションで囲ってありますが、JavaScriptオブジェクトはキーを囲いません。
またJSONでは配列や同レベルのプロパティの末尾にカンマを付けない仕様になっていますが、JavaScriptオブジェクトでは使用可能です。
またJSONそのものに対して「jsObj.pattern」のように値を取得しようとするとundefinedになってしまいます。
JavaScriptでJSON由来の配列操作
JavaScriptもPythonとほぼ似た要領で値を取得・編集・削除することができるでしょう。
- console.log(‘JavaScriptオブジェクト配列の操作’);
- // 参照
- console.log(jsObj.children[0].name);
- console.log(jsObj.children[1].name);
- // 追加
- jsObj.children.push({
- “id”: 4,
- “name”: “nora”,
- “vaccin”: false,
- “detail”: {
- “personality”: “naughty”
- }
- });
- debug(jsObj.children);
- // 編集
- jsObj.children[2].name = ‘sabi’;
- jsObj.children[2].vaccin = true;
- debug(jsObj.children[2]);
- // 削除
- let newHome = jsObj.children.pop();
- debug(newHome);
- debug(jsObj.children);
注意したいのはデバック時のコンソール出力についてです。
debug関数を見ると「JSON.parse(JSON.stringify(value))」していると思います。
これをしないとコンソール出力が全て変更後の値になり、値が変わったのに出力が変わらないという状態になってしまうでしょう。
詳細は「プリミティブ型」「オブジェクト型」「deep copy」などで検索頂ければ記事が出てきます。
SwiftでJSON・データ型オブジェクト変換
動作確認環境は以下です。
- $ swift –version
- Swift version 5.2.2 (swift-5.2.2-RELEASE)
- Target: x86_64-unknown-linux-gnu
JSON・データ型オブジェクト変換コード
Swiftでは非常に厳密な型チェックが行われるため、他の2言語に比べるとかなり異なるコードになってしまっています。
- import Foundation
- protocol StringOrData { }
- extension Data: StringOrData { }
- extension String: StringOrData { }
- extension Dictionary: StringOrData { }
- func debug(value: StringOrData) {
- print(type(of: value))
- debugPrint(value)
- return
- }
- print(“— JSONファイル読込 —“)
- let readHandle = FileHandle(forReadingAtPath: “input.json”)!
- print(“— データ型オブジェクトの取得 —“)
- let inputJson = readHandle.readDataToEndOfFile()
- debug(value: inputJson)
- readHandle.closeFile()
- print(“— データ型オブジェクトをJSONに変換 —“)
- let jsonStr = String(data: inputJson, encoding: .utf8)!
- debug(value: jsonStr)
- print(“— JSONをデータ型オブジェクトに変換 —“)
- let jsonData = jsonStr.data(using: .utf8)!
- debug(value: jsonData)
- print(“— データ型オブジェクトを辞書型に変換 —“)
- var dictObj: Dictionary<String, Any> = [:];
- do {
- dictObj = try JSONSerialization.jsonObject(with: jsonData) as! Dictionary<String, Any>
- debug(value: dictObj)
- } catch {
- print(error)
- }
- print(“— JSONファイル書込 —“)
- let writeHandle = FileHandle(forWritingAtPath: “output.json”)!
- writeHandle.write(jsonData)
- writeHandle.closeFile()
Swiftでファイルからデータを読み込むのに利用するのがFileHandleクラスです。
Swiftではデータ型を更にJSONSerialization.jsonObjectで変換してからデータの修正を行わなければなりません。
クラスを定義してCodableプロトコルを使えば、もう少しスマートになるでしょう。
JSONSerialization.jsonObject
JSONSerialization.jsonObjectはデータ型オブジェクト型を、辞書型・配列型のオブジェクトに変換します。
「import Foundation」を書かないと利用できないため、コードを移植する際はお気をつけ下さい。
SwiftでJSON由来の辞書型オブジェクト操作
Swiftにおける辞書型オブジェクトの操作方法について見ていきましょう。
JSON由来の辞書型オブジェクト操作コード
Swiftでは普通ダブルクオーテーションを使用します。また関数を呼び出すときに「value:」のような指定が必要です。
- print(“— 辞書型オブジェクトの操作 —“)
- // 参照
- print(dictObj[“name”] ?? “”)
- print(dictObj[“children”] ?? “”)
- // 追加
- dictObj[“pattern”] = “brown tabby”
- print(dictObj[“pattern”] ?? “”)
- debug(value: dictObj)
- // 編集
- dictObj[“pattern”] = “calico”
- print(dictObj[“pattern”] ?? “”)
- debug(value: dictObj)
- // 削除
- dictObj[“pattern”] = nil
- debug(value: dictObj)
また要素を削除するためのメソッドはなく、対象のキーに対してnilを代入することで削除されます。
printメソッド使用時の注意点
printメソッドに決まったように書かれている「?? “”」を削除すると、表示されるのが以下のエラーメッセージです。
「warning: expression implicitly coerced from ‘Any?’ to ‘Any’」
printメソッドは引数に非オプショナル型のインスタンスを指定しなければなりません。
しかしdictObj[“pattern”]の中身が必ずしもStringとは限らないため、警告が表示されてしまいます。
今回はサンプルコードのため上記のような対応をしましたが、実際の開発では値のキャストや変換などの処理が必要でしょう。
SwiftでJSON由来の配列操作
最後にSwiftでの配列の扱い方について見ていきましょう。これでコードが出てくるのは最後です。
- print(“— 辞書型オブジェクト配列の操作 —“)
- // 参照
- var children = dictObj[“children”] as! [Dictionary<String, Any>]
- print(children[0][“name”] ?? “”)
- print(children[1][“name”] ?? “”)
- // 追加
- children.append([
- “id”: 4,
- “name”: “nora”,
- “vaccin”: false,
- “detail”: [
- “personality”: “naughty”
- ]
- ])
- dictObj[“children”] = children
- print(dictObj[“children”] ?? “”)
- // 編集
- children[2][“name”] = “sabi”
- children[2][“vaccin”] = true
- debug(value: children[2])
- // 削除
- let newHome = children.removeLast()
- debug(value: newHome)
- dictObj[“children”] = children
- print(dictObj[“children”] ?? “”)
3行目でわざわざキャストをしているのも、型チェックによる警告やエラーが発生するためです。
他の言語ではremoveやpopでしたが、SwiftではremoveLastメソッドに名称が変わっています。
まとめ
最後に、肝心な部分を言語ごとにまとめてみましょう。
PythonのJSON操作
Pythonは辞書型オブジェクトにパースした状態で解析を行う言語でした。
- json.loads(JSONを辞書型オブジェクトに変換)
- json.dumps(辞書型オブジェクトをJSONに変換)
JavaScriptのJSON操作
JavaScriptではJavaScriptオブジェクトに変換したものを操作します。
- JSON.parse(JSONをJavaScriptオブジェクトに変換)
- JSON.stringify(JavaScriptオブジェクトをJSONに変換)
SwiftのJSON操作
Swiftではデータ型として取得したJSONを、更に辞書型にパースすることで操作可能にしていました。
- JSONSerialization.jsonObject(with:) as! Dictionary<String, Any>(データ型オブジェクトを辞書型に変換)