合并两个JSON为JSONObject,而不是JSONArray。

huangapple go评论70阅读模式
英文:

Merge two JSONs to JSONObject instead of JSONArray

问题

我需要找到一种方法,将两个(或更多)JSON对象合并为单个JSON对象,而不使用JSON数组。

以下是代码示例:

public static void mergeJSONs() {
    JSONObject jsonObject1 = new JSONObject("{\"1level1\":{\"1level2\":{\"1label1\":\"1value1\"}}}");
    JSONObject jsonObject2 = new JSONObject("{\"1level1\":{\"1level2\":{\"1label2\":\"1value2\"}}}");
    JSONObject jsonObject3 = new JSONObject("{\"2level1\":{\"2level2\":{\"2level3\":{\"2label1\":\"2value1\"}}}}");
    JSONObject jsonObject4 = new JSONObject("{\"2level1\":{\"2level2\":{\"2label2\":\"2value2\"}}}");

    JSONObject combined = new JSONObject();
    combined.put("strings", jsonObject1);
    combined.put("strings", jsonObject2);
    combined.put("strings", jsonObject3);
    combined.put("strings", jsonObject4);

    System.out.println(combined.toString());
}
``}

这段代码的输出

```plaintext
{"strings":{"2level1":{"2level2":{"2label2":"2value2"}}}}

期望的输出:

{
   "strings":{
      "1level1":{
         "1level2":{
            "1label1":"1value1",
            "1label2":"1value2"
         }
      },
      "2level1":{
         "2level2":{
            "2level3":{
               "2label1":"2value1"
            },
            "2label2":"2value2"
         }
      }
   }
}

或者在一行中:

{"strings":{"1level1":{"1level2":{"1label1":"1value1","1label2":"1value2"}},"2level1":{"2level2":{"2level3":{"2label1":"2value1"},"2label2":"2value2"}}}}

问题在于我永远不会知道JSON对象的名称以及最终JSON会有多深,因为这将用于转换文件,所以我无法为此创建POJO。

目前我正在使用org.json库进行操作,但如果有其他库可以更轻松地实现,那也可以。

库的依赖:

<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20180813</version>
</dependency>

更新#1:
这些对象仅供示例使用,在实际情况下,JSON会更大更深。问题在于我永远不会知道JSON有多深,哪些键在JSON中匹配。因此,需要递归方法,该方法会遍历两个对象,直到存在匹配的键并且其中一个对象不包含该键为止,然后应将所有嵌套对象合并到该对象中。

更新#2:
更新了示例代码和预期输出,以使图像更清晰。

英文:

I need to find a way how to merge two (or more) JSON objects into a single JSON object without JSON arrays.

There's code example:

public static void mergeJSONs() {
    JSONObject jsonObject1 = new JSONObject(&quot;{\&quot;1level1\&quot;:{\&quot;1level2\&quot;:{\&quot;1label1\&quot;:\&quot;1value1\&quot;}}}&quot;);
    JSONObject jsonObject2 = new JSONObject(&quot;{\&quot;1level1\&quot;:{\&quot;1level2\&quot;:{\&quot;1label2\&quot;:\&quot;1value2\&quot;}}}&quot;);
    JSONObject jsonObject3 = new JSONObject(&quot;{\&quot;2level1\&quot;:{\&quot;2level2\&quot;:{\&quot;2level3\&quot;:{\&quot;2label1\&quot;:\&quot;2value1\&quot;}}}}&quot;);
    JSONObject jsonObject4 = new JSONObject(&quot;{\&quot;2level1\&quot;:{\&quot;2level2\&quot;:{\&quot;2label2\&quot;:\&quot;2value2\&quot;}}}&quot;);

    JSONObject combined = new JSONObject();
    combined.put(&quot;strings&quot;, jsonObject1);
    combined.put(&quot;strings&quot;, jsonObject2);
    combined.put(&quot;strings&quot;, jsonObject3);
    combined.put(&quot;strings&quot;, jsonObject4);

    System.out.println(combined.toString());
}

Output for this code:

{&quot;strings&quot;:{&quot;2level1&quot;:{&quot;2level2&quot;:{&quot;2label2&quot;:&quot;2value2&quot;}}}}

Expected output:

{
   &quot;strings&quot;:{
      &quot;1level1&quot;:{
         &quot;1level2&quot;:{
            &quot;1label1&quot;:&quot;1value1&quot;,
            &quot;1label2&quot;:&quot;1value2&quot;
         }
      },
      &quot;2level1&quot;:{
         &quot;2level2&quot;:{
            &quot;2level3&quot;:{
               &quot;2label1&quot;:&quot;2value1&quot;
            },
            &quot;2label2&quot;:&quot;2value2&quot;
         }
      }
   }
}

or in one line:

{&quot;strings&quot;:{&quot;1level1&quot;:{&quot;1level2&quot;:{&quot;1label1&quot;:&quot;1value1&quot;,&quot;1label2&quot;:&quot;1value2&quot;}},&quot;2level1&quot;:{&quot;2level2&quot;:{&quot;2level3&quot;:{&quot;2label1&quot;:&quot;2value1&quot;},&quot;2label2&quot;:&quot;2value2&quot;}}}}

The thing is that I will never know the names of the JSON objects and how deep will this JSON be in the end as this will be used to convert files, so I am not able to create POJO for this.

Currently I'm using org.json library for this but if there is an easy way how to do that with other libraries - it works for me as well.

Library:

&lt;dependency&gt;
    &lt;groupId&gt;org.json&lt;/groupId&gt;
    &lt;artifactId&gt;json&lt;/artifactId&gt;
    &lt;version&gt;20180813&lt;/version&gt;
&lt;/dependency&gt;

UPDATE #1:
Those objects are provided just for example, in reality JSONs will be larger and deeper. Problem is that I will never know how deep and which keys matches in JSON. So here recursive method is needed which would go through both object until there is any key that matches and one of object doesn't contain that key then all the nested objects should be merged to that one.

UPDATE #2:
Updated sample code and expected output to make image more clear

答案1

得分: 1

我推荐使用来自谷歌的 Gson

最新发布的版本是 2019年10月2.8.6

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.6</version>
</dependency>

始终在 Maven 中央仓库 上检查最新版本:


示例:

public static void mergeJSONs() {
  String JSON1 = "{\"1level1\":{\"1level2\":{\"1label1\":\"1value1\"}}}";
  String JSON2 = "{\"1level1\":{\"1level2\":{\"1label2\":\"1value2\"}}}";
  String JSON3 = "{\"2level1\":{\"2level2\":{\"2level3\":{\"2label1\":\"2value1\"}}}}";
  String JSON4 = "{\"2level1\":{\"2level2\":{\"2label2\":\"2value2\"}}}";
  String finalJson = organizeJson(JSON1, JSON2, JSON3, JSON4);
  System.out.println(finalJson);
}

该方法可以接收一组 JSON 负载,添加一个根元素并进行合并:

public String organizeJson(String... jsonList) throws Exception {
    JsonObject jsonObj = null;
    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    for (String json : jsonList) {
        if (jsonObj != null) {
            jsonObj = jsonMerge(jsonObj, gson.fromJson(json, JsonObject.class));
        } else {
            jsonObj = gson.fromJson(json, JsonObject.class);
        }
    }
    JsonObject jsonStringsRoot = new JsonObject();
    /* 添加 "strings" 作为根元素 */
    jsonStringsRoot.add("strings", jsonObj);
    return gson.toJson(jsonStringsRoot);
}

使用递归调用来查找嵌套对象中的最后一层(深度合并)的方法:

public static JsonObject jsonMerge(JsonObject jsonA, JsonObject jsonB) throws Exception {
    for (Map.Entry<String, JsonElement> sourceEntry : jsonA.entrySet()) {
        String key = sourceEntry.getKey();
        JsonElement value = sourceEntry.getValue();
        if (!jsonB.has(key)) {
            if (!value.isJsonNull()) {
                jsonB.add(key, value);
            }
        } else {
            if (!value.isJsonNull()) {
                if (value.isJsonObject()) {
                    jsonMerge(value.getAsJsonObject(), jsonB.get(key).getAsJsonObject());
                } else {
                    jsonB.add(key, value);
                }
            } else {
                jsonB.remove(key);
            }
        }
    }
    return jsonB;
}

参考链接:

英文:

I prefer and recommend use Gson from Google:

The last release is 2.8.6 from Oct of 2019:

&lt;dependency&gt;
	&lt;groupId&gt;com.google.code.gson&lt;/groupId&gt;
	&lt;artifactId&gt;gson&lt;/artifactId&gt;
	&lt;version&gt;2.8.6&lt;/version&gt;
&lt;/dependency&gt;

Always check last version on Maven Central Repository:


Example:

public static void mergeJSONs() {
  String JSON1 = &quot;{\&quot;1level1\&quot;:{\&quot;1level2\&quot;:{\&quot;1label1\&quot;:\&quot;1value1\&quot;}}}&quot;;
  String JSON2 = &quot;{\&quot;1level1\&quot;:{\&quot;1level2\&quot;:{\&quot;1label2\&quot;:\&quot;1value2\&quot;}}}&quot;;
  String JSON3 = &quot;{\&quot;2level1\&quot;:{\&quot;2level2\&quot;:{\&quot;2level3\&quot;:{\&quot;2label1\&quot;:\&quot;2value1\&quot;}}}}&quot;;
  String JSON4 = &quot;{\&quot;2level1\&quot;:{\&quot;2level2\&quot;:{\&quot;2label2\&quot;:\&quot;2value2\&quot;}}}&quot;;
  String finalJson = organizeJson(JSON1, JSON2, JSON3, JSON4);
  System.out.println(finalJson);
}

The method can receive a list of json payloads, add a root element and merge:

public String organizeJson(String... jsonList) throws Exception {
	JsonObject jsonObj = null;
	Gson gson = new GsonBuilder().setPrettyPrinting().create();
	for (String json : jsonList) {
		if (jsonObj != null) {
			jsonObj = jsonMerge(jsonObj, gson.fromJson(json, JsonObject.class));
		} else {
			jsonObj = gson.fromJson(json, JsonObject.class);
		}
	}
	JsonObject jsonStringsRoot = new JsonObject();
	/* Add &quot;strings&quot; as root element */
	jsonStringsRoot.add(&quot;strings&quot;, jsonObj);
	return gson.toJson(jsonStringsRoot);
}

Method using recursive call to find the last level on nested objects (deep merge):

public static JsonObject jsonMerge(JsonObject jsonA, JsonObject jsonB) throws Exception {
	for (Map.Entry&lt;String, JsonElement&gt; sourceEntry : jsonA.entrySet()) {
		String key = sourceEntry.getKey();
		JsonElement value = sourceEntry.getValue();
		if (!jsonB.has(key)) {
			if (!value.isJsonNull()) {
				jsonB.add(key, value);
			}
		} else {
			if (!value.isJsonNull()) {
				if (value.isJsonObject()) {
					jsonMerge(value.getAsJsonObject(), jsonB.get(key).getAsJsonObject());
				} else {
					jsonB.add(key, value);
				}
			} else {
				jsonB.remove(key);
			}
		}
	}
	return jsonB;
}

Reference:

huangapple
  • 本文由 发表于 2020年8月21日 19:27:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/63522037.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定