【问题标题】:Merge (Concat) Multiple JSONObjects in Java在 Java 中合并(Concat)多个 JSONObjects
【发布时间】:2011-01-25 01:53:01
【问题描述】:

我正在使用来自两个不同来源的一些 JSON,我最终得到了两个 JSONObjects,我想将它们合并为一个。

数据:

"Object1": {
    "Stringkey":"StringVal",
    "ArrayKey": [Data0, Data1]
}

"Object2": {
    "Stringkey":"StringVal",
    "Stringkey":"StringVal",
    "Stringkey":"StringVal",
}

代码,使用http://json.org/java/库:

// jso1 and jso2 are some JSONObjects already instantiated
JSONObject Obj1 = (JSONObject) jso.get("Object1");
JSONObject Obj2 = (JSONObject) jso.get("Object2");

因此,在这种情况下,我想将Obj1Obj2 结合起来,要么创建一个全新的JSONObject,要么将一个连接到另一个。除了将它们全部分开并由puts 单独添加之外,还有什么想法吗?

【问题讨论】:

标签: java json concat


【解决方案1】:

这个问题已经有一段时间了,但现在 JSONObject 实现了“toMap”方法,所以你可以尝试这种方式:

Map<String, Object> map = Obj1.toMap();      //making an HashMap from obj1
map.putAll(Obj2.toMap());                    //moving all the stuff from obj2 to map
JSONObject combined = new JSONObject( map ); //new json from map

【讨论】:

    【解决方案2】:
    An improved version of merge on Gson's JsonObjects - can go any level of nested structure
     /**
     * Merge "source" into "target". 
     * 
     * <pre>
     *     An improved version of merge on Gson's JsonObjects - can go any level of nested structure:
     *             1. merge root & nested attributes.
     *             2. replace list of strings. For. eg.
     *              source -> "listOfStrings": ["A!"]
     *              dest -> "listOfStrings": ["A", "B"]
     *              merged -> "listOfStrings": ["A!", "B"]
     *             3. can merge nested objects inside list. For. eg.
     *              source -> "listOfObjects": [{"key2": "B"}]
     *              dest -> "listOfObjects": [{"key1": "A"}]
     *              merged -> "listOfObjects": [{"key1": "A"}, {"key2": "B"}]
     * </pre>
     * @return the merged object (target).
     */
    public static JsonObject deepMerge(JsonObject source, JsonObject target) {
        for (String key: source.keySet()) {
            JsonElement srcValue = source.get(key);
            if (!target.has(key)) {
                target.add(key, srcValue);
            } else {
                if (srcValue instanceof JsonArray) {
                    JsonArray srcArray = (JsonArray)srcValue;
                    JsonArray destArray = target.getAsJsonArray(key);
                    if (destArray == null || destArray.size() == 0) {
                        target.add(key, srcArray);
                        continue;
                    } else {
                        IntStream.range(0, srcArray.size()).forEach(index -> {
                            JsonElement srcElem = srcArray.get(index);
                            JsonElement destElem = null;
                            if (index < destArray.size()) {
                                destElem = destArray.get(index);
                            }
                            if (srcElem instanceof JsonObject) {
                                if (destElem == null) {
                                    destElem = new JsonObject();
                                }
                                deepMerge((JsonObject) srcElem, (JsonObject) destElem);
                            } else {
                                destArray.set(index, srcElem);
                            }
                        });
                    }
                } else if (srcValue instanceof JsonObject) {
                    JsonObject valueJson = (JsonObject)srcValue;
                    deepMerge(valueJson, target.getAsJsonObject(key));
                } else {
                    target.add(key, srcValue);
                }
            }
        }
        return target;
    }
    

    【讨论】:

    • 我正在尝试使用上述方法。试图确定当源或目标是数组而另一个(目标或源)不是时我需要进行哪些更改。如果您有任何想法或想法,请告诉我。谢谢
    • 该方法是检查srcValue是否是一个数组[第6行],在里面你可以检查dest是一个对象还是一个数组并采取相应的行动。
    【解决方案3】:

    这就是我的工作

    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    
    /**
     * This class has all static functions to merge 2 objects into one
     */
    public class MergeHelper {
        private static ObjectMapper objectMapper = new ObjectMapper();
    
        /**
         * return a merge JsonNode, merge newJson into oldJson; override or insert
         * fields from newJson into oldJson
         * 
         * @param oldJson
         * @param newJson
         * @return
         */
        public static JsonNode mergeJsonObject(JsonNode oldJson, JsonNode newJson) {
            ObjectNode merged = objectMapper.createObjectNode();
            merged.setAll((ObjectNode) oldJson);
            merged.setAll((ObjectNode) newJson);
            return merged;
        }
    }
    

    【讨论】:

    • 不鼓励仅使用代码回答。请添加一些解释,说明这是如何解决问题的,或者这与现有答案有何不同。 From Review
    【解决方案4】:

    上面已经有人提到了。我只是发布一个简短的版本。

    要合并两个 JSONObject json1 & json2 你可以像这样简单地处理它:

    String merged = json1.toString().substring(0, json1.length() - 1) + "," +
    json2.toString().substring(1);
    JSONObject mergedJson = new JSONObject(merged);
    

    当然,不要忘记处理JSONException。 :) 希望对您有所帮助。

    【讨论】:

      【解决方案5】:

      今天,我也在努力合并 JSON 对象,并提出了以下解决方案(使用 Gson 库)。

      private JsonObject mergeJsons(List<JsonObject> jsonObjs) {
          JsonObject mergedJson = new JsonObject();
          jsonObjs.forEach((JsonObject jsonObj) -> {
              Set<Map.Entry<String, JsonElement>> entrySet = jsonObj.entrySet();
              entrySet.forEach((next) -> {
                  mergedJson.add(next.getKey(), next.getValue());
              });
          });
          return mergedJson;
      }
      

      【讨论】:

        【解决方案6】:

        合并类型化的数据结构树并非易事,您需要定义优先级、处理不兼容的类型、定义它们将如何转换和合并...

        所以在我看来,你不会回避

        ...将它们全部分开并通过 puts` 单独添加。

        如果您的问题是:有人帮我完成了吗? 那我想你可以看看我复活的这个YAML merging library/tool。 (YAML 是 JSON 的超集),原则适用于两者。
        (但是,此特定代码返回 YAML 对象,而不是 JSON。请随意扩展项目并发送 PR。)

        【讨论】:

          【解决方案7】:

          对我来说,该功能有效:

          private static JSONObject concatJSONS(JSONObject json, JSONObject obj) {
              JSONObject result = new JSONObject();
          
              for(Object key: json.keySet()) {
                  System.out.println("adding " + key + " to result json");
                  result.put(key, json.get(key));
              }
          
              for(Object key: obj.keySet()) {
                  System.out.println("adding " + key + " to result json");
                  result.put(key, obj.get(key));
              }
          
              return result;
          }
          

          (notice) - 这个 json 连接的实现是为了导入 org.json.simple.JSONObject;

          【讨论】:

            【解决方案8】:

            我使用字符串将新对象连接到现有对象。


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

            【讨论】:

              【解决方案9】:

              一种合并任意数量 JSONObject 的现成方法:

              /**
               * 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;
              }
              

              【讨论】:

              • 对于 JSONArray else if ( added.get(key) instanceof JSONArray && mapped.get(key) instanceof JSONArray) { JSONArray mkeyArray = merge.getJSONArray(key); JSONArray akeyArray = added.getJSONArray(key); for (int i=0;i
              【解决方案10】:

              感谢埃雷尔。这是一个 Gson 版本。

              /**
               * 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}
              
              }
              

              【讨论】:

                【解决方案11】:

                除了@erel 的回答之外,我还必须对外部else 进行此编辑(我使用org.json.simple)以处理JSONArray 的:

                            // 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);
                            }
                

                【讨论】:

                  【解决方案12】:

                  这个包装方法会有所帮助:

                  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;
                  }
                  

                  【讨论】:

                    【解决方案13】:

                    你可以像这样创建一个新的 JSONObject:

                    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));
                        }
                    }
                    

                    使用此代码,如果您在 Obj1Obj2 之间有任何重复键,Obj2 中的值将保留。如果您希望保留 Obj1 中的值,则应反转第 2 行中数组的顺序。

                    【讨论】:

                    • 我不知道静态方法 JSONObject.getNames,它使代码更简单,见下面 Matthew 的回答,它减少了使用它的代码。
                    • 在第一行在JSONObject()之前添加new,6个字符以下不允许编辑。
                    【解决方案14】:

                    在某些情况下,您需要深度合并,即合并具有相同名称的字段的内容(就像在 Windows 中复制文件夹时一样)。此功能可能会有所帮助:

                    /**
                     * 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"}}
                    }
                    

                    【讨论】:

                    • 如果 'source' 中的值是 JSONArray 类型怎么办?在这种情况下,我们需要将此数组与目标对象的等效 JSONArray 合并。
                    【解决方案15】:

                    如果你想要一个有两个键的新对象,Object1 和 Object2,你可以这样做:

                    JSONObject Obj1 = (JSONObject) jso1.get("Object1");
                    JSONObject Obj2 = (JSONObject) jso2.get("Object2");
                    JSONObject combined = new JSONObject();
                    combined.put("Object1", Obj1);
                    combined.put("Object2", Obj2);
                    

                    如果你想合并它们,例如顶级对象有 5 个键(Stringkey1、ArrayKey、StringKey2、StringKey3、StringKey4),我认为您必须手动执行:

                    JSONObject merged = new JSONObject(Obj1, JSONObject.getNames(Obj1));
                    for(String key : JSONObject.getNames(Obj2))
                    {
                      merged.put(key, Obj2.get(key));
                    }
                    

                    如果 JSONObject 实现了Map,并且支持 putAll,这会容易很多。

                    【讨论】:

                    • 我正在尝试在 Android 中使用您的第二个代码 sn-p,但在 JSONObject 上没有看到静态 getNames 函数。这是在更新版本的 org.json 库中添加的吗?
                    • @AustynMahoney,不知道历史,但是对于Android你可以使用实例方法JSONObject.names
                    • @AustynMahoney android json 库中没有我已经试过了。 android文档中也没有提到它。这里只提到json.org/javadoc/org/json/JSONObject.html
                    • JSONObject.getNames() 方法将在 jsonobject 为空时返回 null。您还需要检查这种情况。
                    猜你喜欢
                    • 2021-09-29
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-12-30
                    • 1970-01-01
                    • 2018-04-17
                    • 2016-01-26
                    相关资源
                    最近更新 更多