1. はじめに
jsonのobject
やarray
等の入れ子の任意データに一回でアクセスしたい要件があったため、キーでアクセス可能なマップ(Dict)に変換する処理を作成しました。
(仕様):必要に応じて変更してください。
- 入れ子はキーの階層構造で示す。
- 階層の区切りは
/
とする。 -
array
の要素数はCOUNT
で示す。
2. ソースコード
# -*- coding: utf-8 -*-
import json
import datetime
# ★ポイント1
SEPARATOR = '/'
COUNT = 'COUNT'
# ★ポイント2
def convert_flat_map(keyStr, target, map):
# ★ポイント3
if isinstance(target, dict):
for k in target.keys():
convert_flat_map(keyStr + SEPARATOR + k, target[k], map)
# ★ポイント4
elif isinstance(target, list):
map[keyStr + SEPARATOR + COUNT] = str(len(target))
for i in range(len(target)):
one = target[i]
convert_flat_map(keyStr + SEPARATOR + str(i), one, map)
# ★ポイント5
# 参考(デバッグ)として分岐を分けているだけ。
# 全て map[keyStr] = target で構わない。
elif isinstance(target, int):
map[keyStr] = target
elif isinstance(target, float):
map[keyStr] = target
elif isinstance(target, datetime.date):
map[keyStr] = target
elif isinstance(target, unicode):
map[keyStr] = target
elif isinstance(target, str):
map[keyStr] = target
elif isinstance(target, bool):
map[keyStr] = target
elif target is None:
map[keyStr] = target
else:
print('<other>' + str(target))
# test case 1 : http://json-schema.org/example/address.json
def test01():
# ★ポイント6
f = open('address.json', 'r')
jsonData = json.load(f)
map = {}
convert_flat_map('', jsonData, map)
for k in sorted(map.keys()):
print(k + ' = ' + str(map[k]))
# test case 2 : http://json-schema.org/example/calendar.json
def test02():
f2 = open('calendar.json', 'r')
jsonData2 = json.load(f2)
map2 = {}
convert_flat_map('', jsonData2, map2)
sorted(map2)
for k in sorted(map2.keys()):
print(k + ' = ' + map2[k])
if __name__=='__main__':
# test
test01()
print("------------------------------")
test02()
★ポイント1
入れ子の区切り文字とarray
の要素数を示す文字列を定義します。各自の要件に応じて変更してください。
★ポイント2
今回のポイントです。入れ子やarray
はその内部をさらに取り出すため、再帰処理で呼び出せるように関数を定義しました。
- 第1引数 : マップ(Dict)のキーとなる文字列
- 第2引数 : 解析対象のjsonデータ(Dict)
- 第3引数 : 結果を格納するマップ(Dict)
★ポイント3
jsonデータのobject
はpythonではDict
になるので、格納されている要素に対してconvert_flat_map()
関数を再帰的に呼び出します。
★ポイント4
jsonデータのarray
はpythonではlist
になるので、格納されている要素に対してconvert_flat_map()
関数を再帰的に呼び出します。
また、list
の場合は★ポイント1で定義した文字列で要素数も結果のマップ(Dict)に格納します。
★ポイント5
jsonデータでobject
とarray
以外は入れ子の終端となるので、結果のマップ(Dict)に格納します。
jsonのデータについては https://www.json.org/json-ja.html を参照ください。
(注意)
jsonのデータ型で条件分岐を分けていますがデバッグのためです。必要に応じて★ポイント5の条件分岐は纏めてください。
★ポイント6
動作確認用の処理です。呼び出す際はconvert_flat_map()
の第1引数に空文字を指定します。
なお、ここで第1引数に文字列を指定した場合、キーのプレフィックスとして付与されます。
3. 動作確認
{
"$schema": "http://json-schema.org/draft-06/schema#",
"description": "An Address following the convention of http://microformats.org/wiki/hcard",
"type": "object",
"properties": {
"post-office-box": { "type": "string" },
"extended-address": { "type": "string" },
"street-address": { "type": "string" },
"locality":{ "type": "string" },
"region": { "type": "string" },
"postal-code": { "type": "string" },
"country-name": { "type": "string"}
},
"required": ["locality", "region", "country-name"],
"dependencies": {
"post-office-box": ["street-address"],
"extended-address": ["street-address"]
}
}
/$schema = http://json-schema.org/draft-06/schema#
/dependencies/extended-address/0 = street-address
/dependencies/extended-address/COUNT = 1
/dependencies/post-office-box/0 = street-address
/dependencies/post-office-box/COUNT = 1
/description = An Address following the convention of http://microformats.org/wiki/hcard
/properties/country-name/type = string
/properties/extended-address/type = string
/properties/locality/type = string
/properties/post-office-box/type = string
/properties/postal-code/type = string
/properties/region/type = string
/properties/street-address/type = string
/required/0 = locality
/required/1 = region
/required/2 = country-name
/required/COUNT = 3
/type = object
{
"$schema": "http://json-schema.org/draft-06/schema#",
"description": "A representation of an event",
"type": "object",
"required": [ "dtstart", "summary" ],
"properties": {
"dtstart": {
"format": "date-time",
"type": "string",
"description": "Event starting time"
},
"dtend": {
"format": "date-time",
"type": "string",
"description": "Event ending time"
},
"summary": { "type": "string" },
"location": { "type": "string" },
"url": { "type": "string", "format": "uri" },
"duration": {
"format": "time",
"type": "string",
"description": "Event duration"
},
"rdate": {
"format": "date-time",
"type": "string",
"description": "Recurrence date"
},
"rrule": {
"type": "string",
"description": "Recurrence rule"
},
"category": { "type": "string" },
"description": { "type": "string" },
"geo": { "$ref": "http://json-schema.org/geo" }
}
}
/$schema = http://json-schema.org/draft-06/schema#
/description = A representation of an event
/properties/category/type = string
/properties/description/type = string
/properties/dtend/description = Event ending time
/properties/dtend/format = date-time
/properties/dtend/type = string
/properties/dtstart/description = Event starting time
/properties/dtstart/format = date-time
/properties/dtstart/type = string
/properties/duration/description = Event duration
/properties/duration/format = time
/properties/duration/type = string
/properties/geo/$ref = http://json-schema.org/geo
/properties/location/type = string
/properties/rdate/description = Recurrence date
/properties/rdate/format = date-time
/properties/rdate/type = string
/properties/rrule/description = Recurrence rule
/properties/rrule/type = string
/properties/summary/type = string
/properties/url/format = uri
/properties/url/type = string
/required/0 = dtstart
/required/1 = summary
/required/COUNT = 2
/type = object
4. さいごに
今回はjsonをフラットマップ(Dict)に変換する処理について説明しました。この処理が必要かどうかは要件によって異なりますが、1つのキーを利用して1回で任意のデータにアクセスできるのは個人的には便利かと思います。