Merge (Concat) Multiple JSONObjects

匿名 (未验证) 提交于 2019-12-03 02:08:02

问题:

I am consuming some JSON from two different sources, I end up with two JSONObjects 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 puts?

回答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(); } 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!