下記の記事と似た主旨のオレオレメモです。
JSONファイルのdiffって有名ライブラリなどでは少しリッチすぎるかなという時に、機能が劣っていたり割り切りがあっても、自分で取り回しやすい自作のイディオムが欲しくなったのでコピペ用に書き起こしてみました。
■ツールの仕様・コンセプト
2つのJSON*1ファイルaとbを読み込んで、差異が出たプロパティを出力します。
JSONを比較したい時は、(Pretty形式の行単位の比較ではなく、)まずは差異が出ているプロパティ(ネストされていることが多い)がどこか知りたいよね、というところに注目した分析になっています。
具体的には、
x.y.zというノードで差異が出た場合、
{ x.y.z : [ ファイルaの当該プロパティの値, ファイルbの当該プロパティの値 ] }
という、それ自体がJSONのレポートを吐き出します。
■jsondiff.py(Pythonです)
from itertools import zip_longest import json """ JSONをdiffする関数 """ diff = {} def append(path, a, b): diff['.'.join(path)] = [a, b] def d(a, b, path=[]): if type(a) is not type(b): append(path, a, b) return if type(a) is list: d4list(a, b, path) return if type(a) is not dict: if a != b: append(path, a, b) return for i in a.keys(): if i in b.keys(): d(a[i], b[i], path + [i]) else: append(path + [i], a[i], None) for i in b.keys(): if i not in a.keys(): append(path + [i], None, b[i]) def make_pathsimbol(path, cnt): _path = path[:-2] + [path[-1] + '[' + str(cnt) + ']'] return _path def d4list(a, b, path): cnt = 0 for i, j in zip_longest(a, b): d(i, j, make_pathsimbol(path, cnt)) cnt += 1 def jsondiff(a, b): d(a, b) return diff if __name__ == "__main__": a = {"a": 1, "b": 2, "c": {"d": 3, "x": "ああ"}, "e": [{"f": 4}, {"g": 5}, {"g": 9, "y": [1, 2]}, {"z": "ない"}], "h": 3} b = {"a": 1, "b": 22, "c": {"d": 3, "x": "いい"}, "e": [{"f": 4}, {"g": 55}, {"g": 99, "y": 9}], "h": "3", "w": "ないない"} print(json.dumps(jsondiff(a, b), ensure_ascii=False, indent=4, sort_keys=True))
■jsondiff.pyで食わせているインプットJSON(相当)の例(再掲)
ファイルa = { "a": 1, "b": 2, "c": { "d": 3, "x": "ああ" }, "e": [ { "f": 4 }, { "g": 5 }, { "g": 9, "y": [1, 2] }, { "z": "ない" } ], "h": 3 } ファイルb = { "a": 1, "b": 22, "c": { "d": 3, "x": "いい" }, "e": [ { "f": 4 }, { "g": 55 }, { "g": 99, "y": 9 } ], "h": "3", "w": "ないない" }
※プロパティbやプロパティc.xがdiff検知されてほしいという例になります。
■jsondiff.pyの実行結果
{ "b": [ 2, 22 ], "c.x": [ "ああ", "いい" ], "e[1].g": [ 5, 55 ], "e[2].g": [ 9, 99 ], "e[2].y": [ [ 1, 2 ], 9 ], "e[3]": [ { "z": "ない" }, null ], "h": [ 3, "3" ], "w": [ null, "ないない" ] }
今回の目的の範囲ではうまく行っていると思いますが、コレは恥ずかしいッ!!系のバグがあるかもしれません。
ですが、「答案用紙を提出した後に閃めく理論」により、「公開する」と思わぬ不具合に自分で気づけるので、見込みでポストしちゃうこととしました。