Python
Python で JSON をマージするのに誰でも思いつく簡単な方法は、
JSON を辞書(dict)として読みこんで、dict(dict1, **dict2) の方法でマージする方法である。
簡単なサンプル
import json j1 = ''' { "a": 1, "ary": [ 10, 11 ], "b":{ "b1": 20 } } ''' j2 = ''' { "a": 2, "ary": [ 12, 13 ], "b":{ "b2": 21 } } ''' j3 = json.dumps(dict(json.loads(j1), **json.loads(j2))) print(j3)
結果は、
{"a": 2, "ary": [12, 13], "b": {"b2": 21}}
これでは、ただの上書きだ!期待するのは、少なくとも配列は追加してほしい
{'a': 2, 'ary': [10, 11, 12, 13], 'b': {'b1': 20, 'b2': 21}}
dictknife · PyPI deepmerge というのを使えば、期待する結果を得ることができる。
from dictknife import deepmerge j3 = deepmerge(json.loads(j1), json.loads(j2))
Java
Python と違って Java では、配列維持のマージだけでなく、
同じキーがマージ先に存在する場合、上書きではなく配列として追加するマージをすることも可能である。
Jackson を使用するので、JsonNode でマージを行う。。。
配列維持のマージ
public static JsonNode updateArrayMerge(JsonNode baseNode, JsonNode upNode) { ObjectNode node = JsonNodeFactory.instance.objectNode(); Map<String, Integer> map = new HashMap<>(); for(Iterator<String> it = baseNode.fieldNames(); it.hasNext();){ map.put(it.next(), 1); } for(Iterator<String> it = upNode.fieldNames(); it.hasNext();){ map.put(it.next(), 2); } map.entrySet().stream().forEach(e->{ String key = e.getKey(); if (e.getValue()==1){ node.set(e.getKey(), baseNode.get(key)); }else{ JsonNode n = baseNode.get(key); if (n==null){ node.set(key, upNode.get(key)); }else{ JsonNode n1 = baseNode.get(key); JsonNode n2 = upNode.get(key); if (n1.isArray() && n2.isArray()){ ArrayNode array = JsonNodeFactory.instance.arrayNode(); for(Iterator<JsonNode> it = n1.elements(); it.hasNext();){ array.add(it.next()); } for(Iterator<JsonNode> it = n2.elements(); it.hasNext();){ array.add(it.next()); } node.set(key, array); }else if(n1.isObject() && n2.isObject()){ node.set(key, updateArrayMerge(n1, n2)); }else{ node.set(key, n2); } } } }); return node; }
{"a":2,"b":{"b2":21,"b1":20},"ary":[10,11,12,13]}
同じキーがマージ先に存在する場合、上書きではなく配列として追加するマージ
public static JsonNode merge(JsonNode baseNode, JsonNode upNode) { ObjectNode node = JsonNodeFactory.instance.objectNode(); Map<String, Boolean> map = new HashMap<>(); for(Iterator<String> it = baseNode.fieldNames(); it.hasNext();){ map.put(it.next(), false); } for(Iterator<String> it = upNode.fieldNames(); it.hasNext();){ String s = it.next(); map.put(s, map.get(s)==null ? false : true); } map.entrySet().stream().forEach(e->{ String key = e.getKey(); if (e.getValue()){ JsonNode n = baseNode.get(key); if (n==null){ node.set(key, upNode.get(key)); }else{ JsonNode n1 = baseNode.get(key); JsonNode n2 = upNode.get(key); ArrayNode array = JsonNodeFactory.instance.arrayNode(); if (n1.isArray()) { for(Iterator<JsonNode> it = n1.elements(); it.hasNext();){ array.add(it.next()); } }else{ array.add(n1); } if (n2.isArray()) { for(Iterator<JsonNode> it = n2.elements(); it.hasNext();){ array.add(it.next()); } }else{ array.add(n2); } node.set(key, array); } }else{ node.set(key, upNode.get(key)); } }); return node; }
{"a":[1,2],"b":[{"b1":20},{"b2":21}],"ary":[10,11,12,13]}
同じキー'a' に対しての上書きにならずに、配列としてマージすることができる。
今回のメソッドは、Git-Hub で公開している。
yipuran-jack/JsonClip.java at master · yipuran/yipuran-jack · GitHub