可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am consuming some JSON from two different sources, I end up with two JSONObject
s and I'd like to combine them into one.
Data:
"Object1": { "Stringkey":"StringVal", "ArrayKey": [Data0, Data1] } "Object2": { "Stringkey":"StringVal", "Stringkey":"StringVal", "Stringkey":"StringVal", }
Code, using http://json.org/java/ library:
// jso1 and jso2 are some JSONObjects already instantiated JSONObject Obj1 = (JSONObject) jso.get("Object1"); JSONObject Obj2 = (JSONObject) jso.get("Object2");
So in this situation I'd like to combine Obj1
and Obj2
, either to make a totally new JSONObject
or concat one to the other. Any ideas besides pulling them all apart and individually adding in by put
s?
回答1:
If you want a new object with two keys, Object1 and Object2, you can do:
JSONObject Obj1 = (JSONObject) jso1.get("Object1"); JSONObject Obj2 = (JSONObject) jso2.get("Object2"); JSONObject combined = new JSONObject(); combined.put("Object1", Obj1); combined.put("Object2", Obj2);
If you want to merge them, so e.g. a top level object has 5 keys (Stringkey1, ArrayKey, StringKey2, StringKey3, StringKey4), I think you have to do that manually:
JSONObject merged = new JSONObject(Obj1, JSONObject.getNames(Obj1)); for(String key : JSONObject.getNames(Obj2)) { merged.put(key, Obj2.get(key)); }
This would be a lot easier if JSONObject implemented Map, and supported putAll.
回答2:
You can create a new JSONObject like this:
JSONObject merged = new JSONObject(); JSONObject[] objs = new JSONObject[] { Obj1, Obj2 }; for (JSONObject obj : objs) { Iterator it = obj.keys(); while (it.hasNext()) { String key = (String)it.next(); merged.put(key, obj.get(key)); } }
With this code, if you have any repeated keys between Obj1
and Obj2
the value in Obj2
will remain. If you want the values in Obj1
to be kept you should invert the order of the array in line 2.
回答3:
In some cases you need a deep merge, i.e., merge the contents of fields with identical names (just like when copying folders in Windows). This function may be helpful:
/** * Merge "source" into "target". If fields have equal name, merge them recursively. * @return the merged object (target). */ public static JSONObject deepMerge(JSONObject source, JSONObject target) throws JSONException { for (String key: JSONObject.getNames(source)) { Object value = source.get(key); if (!target.has(key)) { // new value for "key": target.put(key, value); } else { // existing value for "key" - recursively deep merge: if (value instanceof JSONObject) { JSONObject valueJson = (JSONObject)value; deepMerge(valueJson, target.getJSONObject(key)); } else { target.put(key, value); } } } return target; } /** * demo program */ public static void main(String[] args) throws JSONException { JSONObject a = new JSONObject("{offer: {issue1: value1}, accept: true}"); JSONObject b = new JSONObject("{offer: {issue2: value2}, reject: false}"); System.out.println(a+ " + " + b+" = "+JsonUtils.deepMerge(a,b)); // prints: // {"accept":true,"offer":{"issue1":"value1"}} + {"reject":false,"offer":{"issue2":"value2"}} = {"reject":false,"accept":true,"offer":{"issue1":"value1","issue2":"value2"}} }
回答4:
This wrapper method will help :
private static JSONObject merge(JSONObject... jsonObjects) throws JSONException { JSONObject jsonObject = new JSONObject(); for(JSONObject temp : jsonObjects){ Iterator<String> keys = temp.keys(); while(keys.hasNext()){ String key = keys.next(); jsonObject.put(key, temp.get(key)); } } return jsonObject; }
回答5:
A ready method to merge any number of JSONObjects:
/** * Merges given JSONObjects. Values for identical key names are merged * if they are objects, otherwise replaced by the latest occurence. * * @param jsons JSONObjects to merge. * * @return Merged JSONObject. */ public static JSONObject merge( JSONObject[] jsons) { JSONObject merged = new JSONObject(); Object parameter; for (JSONObject added : jsons) { for (String key : toStringArrayList(added.names())) { try { parameter = added.get(key); if (merged.has(key)) { // Duplicate key found: if (added.get(key) instanceof JSONObject) { // Object - allowed to merge: parameter = merge( new JSONObject[]{ (JSONObject) merged.get(key), (JSONObject) added.get(key)}); } } // Add or update value on duplicate key: merged.put( key, parameter); } catch (JSONException e) { e.printStackTrace(); } } } return merged; } /** * Convert JSONArray to ArrayList<String>. * * @param jsonArray Source JSONArray. * * @return Target ArrayList<String>. */ public static ArrayList<String> toStringArrayList(JSONArray jsonArray) { ArrayList<String> stringArray = new ArrayList<String>(); int arrayIndex; for ( arrayIndex = 0; arrayIndex < jsonArray.length(); arrayIndex++) { try { stringArray.add( jsonArray.getString(arrayIndex)); } catch (JSONException e) { e.printStackTrace(); } } return stringArray; }
回答6:
In addition to @erel's answer, I had to make this edit (I'm using org.json.simple
) to the outer else
for dealing with JSONArray
's:
// existing value for "key" - recursively deep merge: if (value instanceof JSONObject) { JSONObject valueJson = (JSONObject)value; deepMerge(valueJson, (JSONObject) target.get(key)); } // insert each JSONArray's JSONObject in place if (value instanceof JSONArray) { ((JSONArray) value).forEach( jsonobj -> ((JSONArray) target.get(key)).add(jsonobj)); } else { target.put(key, value); }
回答7:
Thanks to Erel. Here is a Gson version.
/** * Merge "source" into "target". If fields have equal name, merge them recursively. * Null values in source will remove the field from the target. * Override target values with source values * Keys not supplied in source will remain unchanged in target * * @return the merged object (target). */ public static JsonObject deepMerge(JsonObject source, JsonObject target) throws Exception { for (Map.Entry<String,JsonElement> sourceEntry : source.entrySet()) { String key = sourceEntry.getKey(); JsonElement value = sourceEntry.getValue(); if (!target.has(key)) { //target does not have the same key, so perhaps it should be added to target if (!value.isJsonNull()) //well, only add if the source value is not null target.add(key, value); } else { if (!value.isJsonNull()) { if (value.isJsonObject()) { //source value is json object, start deep merge deepMerge(value.getAsJsonObject(), target.get(key).getAsJsonObject()); } else { target.add(key,value); } } else { target.remove(key); } } } return target; } /** * simple test */ public static void main(String[] args) throws Exception { JsonParser parser = new JsonParser(); JsonObject a = null; JsonObject b = null; a = parser.parse("{offer: {issue1: null, issue2: null}, accept: true, reject: null}").getAsJsonObject(); b = parser.parse("{offer: {issue2: value2}, reject: false}").getAsJsonObject(); System.out.println(deepMerge(a,b)); // prints: // {"offer":{},"accept":true} a = parser.parse("{offer: {issue1: value1}, accept: true, reject: null}").getAsJsonObject(); b = parser.parse("{offer: {issue2: value2}, reject: false}").getAsJsonObject(); System.out.println(deepMerge(a,b)); // prints: // {"offer":{"issue2":"value2","issue1":"value1"},"accept":true} }
回答8:
I used string to concatenate new object to an existing object.
private static void concatJSON() throws IOException, InterruptedException { JSONParser parser = new JSONParser(); Object obj = parser.parse(new FileReader(new File(Main.class.getResource("/file/user.json").toURI()))); JSONObject jsonObj = (JSONObject) obj; //usernameJsonObj String [] values = {"0.9" , Date.from(Calendar.getInstance().toInstant()).toLocaleString()}, innermost = {"Accomplished", "LatestDate"}, inner = {"Lesson1", "Lesson2", "Lesson3", "Lesson4"}; String in = "Jayvee Villa"; JSONObject jo1 = new JSONObject(); for (int i = 0; i < innermost.length; i++) jo1.put(innermost[i], values[i]); JSONObject jo2 = new JSONObject(); for (int i = 0; i < inner.length; i++) jo2.put(inner[i], jo1); JSONObject jo3 = new JSONObject(); jo3.put(in, jo2); String merger = jsonObj.toString().substring(0, jsonObj.toString().length()-1) + "," +jo3.toString().substring(1); System.out.println(merger); FileWriter pr = new FileWriter(file); pr.write(merger); pr.flush(); pr.close(); }