问题描述
鉴于此 JSON:
{
"contact_data": [
"address/all","telephone/us"
],"financial_data": [
"bank_account_number/all","bank_account_number/uk","credit_card_numbers"
]
}
和这个 JSON:
{
"financial_data": [
"credit_card_numbers","bank_account_number/ca","bank_account_number/all"
],"government_id": [
"driving_license/americas"
],"sensitive_data": [
"racial_ethnic_origin"
]
}
我想合并这些看起来像这样:
{
"contact_data": [
"address/all","financial_data": [
"credit_card_numbers","sensitive_data": [
"racial_ethnic_origin"
]
}
我有以下几乎有效:
import org.json.JSONObject;
...
final List<String> jsonStrings = ...; // A list of the above sample JSONs
final List<JSONObject> jsonObjects = jsonStrings
.stream()
.map(JSONObject::new)
// JSONObject.getNames() (called later on) will return null if JSONObject is empty,so filter out empty objects.
.filter(jsonObject -> !jsonObject.isEmpty())
.collect(Collectors.toList());
if (jsonObjects..size() > 1) {
// Merge multiple JSONObjects: https://stackoverflow.com/a/2403453/12177456
final JSONObject firstJsonObject = jsonObjects.get(0);
final JSONObject merged = new JSONObject(firstJsonObject,JSONObject.getNames(firstJsonObject));
final List<JSONObject> remainingJsonObjects = jsonObjects.subList(1,jsonObjects.size());
for (final JSONObject nextJsonObject : remainingJsonObjects) {
for (final String nextJsonObjectFieldName : JSONObject.getNames(nextJsonObject)) {
merged.put(nextJsonObjectFieldName,nextJsonObject.get(nextJsonObjectFieldName));
}
}
return merged;
}
但是,我希望在 financial_data
中看到 4 个条目:
...
"financial_data": [
"bank_account_number/all","credit_card_numbers"
]
...
相反,我只看到 3 个,bank_account_number/uk
不在合并结果中:
...
"financial_data": [
"bank_account_number/all","credit_card_numbers"
]
...
我并没有坚持使用 org.json
,如果使用 gson、jackson、普通 Java 地图更简单,我可以接受。
解决方法
实际上,这是行不通的。问题出在这里:
merged.put(nextJsonObjectFieldName,nextJsonObject.get(nextJsonObjectFieldName))
这会将带有键 nextJsonObjectFieldName
的条目替换为后面的条目。这就是您从第二个对象进入 financial_data
的原因。
{
"financial_data": [
"credit_card_numbers","bank_account_number/ca","bank_account_number/all"
]
}
您看到其他键没问题,因为其他键在两个 JSON 中具有完全相同的值。如果您在第二个 json 中也更改了其他键的值,您将看到合并的 JSON 将具有与第二个 json 相同的键的值。也就是说,它行不通。
您可以做的是,您可以检查该键是否已经在地图中具有值。如果此键没有现有的 JSONobject,只需将它放入 merged
中即可。否则,我们还有更多工作要做:
JSONObject jsonObject = merged.get(nextJsonObjectFieldName);
if (jsonObject != null) {
final JSONObject finalObj = mergeJsonObjectCheckingFieldValues(jsonObject,nextJsonObject.get(nextJsonObjectFieldName));
merged.put(nextJsonObjectFieldName,finalObj);
} else {
merged.put(nextJsonObjectFieldName,nextJsonObject.get(nextJsonObjectFieldName));
}
mergeJsonObjectCheckingFieldValues
方法检查给定的两个 JSONObject 之间的每个元素,并比较它们是否相同。根据您的示例以及简单地回答这个问题,我假设每个 JSONObject 只不过是一个字符串列表。为此,我们将需要 objectMapper
。因此,请确保您的项目中有 com.fasterxml.jackson.databind.ObjectMapper
。因此,检查将是:
ObjectMapper mapper = new ObjectMapper();
public JSONObject mergeJsonObjectCheckingFieldValues(JSONObject jsonObject,JSONObject nextJsonObject)) {
List<String> existingList = Arrays.asList(mapper
.readValue(jsonObject.toString(),String[].class));
List<String> newList = Arrays.asList(mapper
.readValue(nextJsonObject.toString(),String[].class));
List<String> toBeAdded = newList
.stream()
.filter(x -> !existingList.contains(x))
.collect(Collectors.toList());
if(toBeAdded.size() > 0) {
existingList.addAll(toBeAdded);
}
return new JSONObject(JSONArray.toJSONString(existingList));
}
这是您问题的可能解决方案。我还没有测试过,但代码应该差不多。
,我在这里使用 gson 接受了已接受的答案:
https://stackoverflow.com/a/34092374/12177456
- 处理递归合并 JsonObjects
- 当密钥存在于两个映射中时处理冲突
- 对非原始值(如数组)有特殊处理