在 Java 中合并(Concat)多个 JSONObjects
Posted
技术标签:
【中文标题】在 Java 中合并(Concat)多个 JSONObjects【英文标题】:Merge (Concat) Multiple JSONObjects in Java 【发布时间】:2011-01-25 01:53:01 【问题描述】:我正在使用来自两个不同来源的一些 JSON,我最终得到了两个 JSONObject
s,我想将它们合并为一个。
数据:
"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");
因此,在这种情况下,我想将Obj1
和Obj2
结合起来,要么创建一个全新的JSONObject
,要么将一个连接到另一个。除了将它们全部分开并由put
s 单独添加之外,还有什么想法吗?
【问题讨论】:
相关:Merging YAML 也许这里有一些例子可以解决这个问题? baeldung.com/java-merge-maps 我提到是因为以下答案都没有给出使用 Java 流的解决方案。 【参考方案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));
使用此代码,如果您在 Obj1
和 Obj2
之间有任何重复键,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。您还需要检查这种情况。以上是关于在 Java 中合并(Concat)多个 JSONObjects的主要内容,如果未能解决你的问题,请参考以下文章
pandas使用pd.concat纵向合并多个dataframe实战:多个dataframe的纵向合并为纵向合并的多个dataframe设置标识符指定数据来源
如何使用 pandas 模块合并(即“concat”)100 多个 .csv 文件?
pandas使用pd.concat纵向合并多个dataframe实战:纵向合并(ignore_index参数)为纵向合并的多个dataframe设置标识符指定数据来源(通过字典方式设置数据来源键)