【发布时间】:2012-03-27 18:03:12
【问题描述】:
是否可以将两个 JSON 文档与 Jackson JSON 库合并?我基本上是在使用带有简单 Java 地图的 Jackson 映射器。
我尝试在 Google 和 Jackson 的文档中进行搜索,但找不到任何内容。
【问题讨论】:
是否可以将两个 JSON 文档与 Jackson JSON 库合并?我基本上是在使用带有简单 Java 地图的 Jackson 映射器。
我尝试在 Google 和 Jackson 的文档中进行搜索,但找不到任何内容。
【问题讨论】:
受 StaxMans answer 的启发,我实现了这种合并方法。
public static JsonNode merge(JsonNode mainNode, JsonNode updateNode) {
Iterator<String> fieldNames = updateNode.fieldNames();
while (fieldNames.hasNext()) {
String fieldName = fieldNames.next();
JsonNode jsonNode = mainNode.get(fieldName);
// if field exists and is an embedded object
if (jsonNode != null && jsonNode.isObject()) {
merge(jsonNode, updateNode.get(fieldName));
}
else {
if (mainNode instanceof ObjectNode) {
// Overwrite field
JsonNode value = updateNode.get(fieldName);
((ObjectNode) mainNode).put(fieldName, value);
}
}
}
return mainNode;
}
希望这对某人有所帮助。
【讨论】:
thank you 评论多一点,从Jackson 2.4 开始,put() 已被弃用,应替换为replace()。此外,对于 JDK8 用户,代码可以更加简洁,只需在迭代器上直接调用 forEachRemaining() 并传入更短的 lambda 表达式。
一种方法是像这样使用ObjectReader:
MyBean defaults = objectMapper.readValue(defaultJson, MyBean.class);
ObjectReader updater = objectMapper.readerForUpdating(defaults);
MyBean merged = updater.readValue(overridesJson);
这将结合来自两个来源的数据。这只会进行浅拷贝,即不对包含的对象进行递归合并。
否则,您可能需要将 JSON 读取为树 (JsonNode),循环内容并手动合并。无论如何,这通常是有道理的,因为合并规则并非微不足道,而且每个人对合并应该如何工作都有自己的想法。
编辑:(2017 年 4 月 3 日)
根据@Fernando Correia 的评论,实际上在即将发布的 Jackson 2.9(将于 2017 年 4 月或 5 月发布)中添加了一个新的 feature,最终确实允许深度合并。
【讨论】:
受 Arn 回答的启发。编辑它以添加节点中可能包含节点数组的情况。
public static JsonNode merge(JsonNode mainNode, JsonNode updateNode) {
Iterator<String> fieldNames = updateNode.fieldNames();
while (fieldNames.hasNext()) {
String updatedFieldName = fieldNames.next();
JsonNode valueToBeUpdated = mainNode.get(updatedFieldName);
JsonNode updatedValue = updateNode.get(updatedFieldName);
// If the node is an @ArrayNode
if (valueToBeUpdated != null && valueToBeUpdated.isArray() &&
updatedValue.isArray()) {
// running a loop for all elements of the updated ArrayNode
for (int i = 0; i < updatedValue.size(); i++) {
JsonNode updatedChildNode = updatedValue.get(i);
// Create a new Node in the node that should be updated, if there was no corresponding node in it
// Use-case - where the updateNode will have a new element in its Array
if (valueToBeUpdated.size() <= i) {
((ArrayNode) valueToBeUpdated).add(updatedChildNode);
}
// getting reference for the node to be updated
JsonNode childNodeToBeUpdated = valueToBeUpdated.get(i);
merge(childNodeToBeUpdated, updatedChildNode);
}
// if the Node is an @ObjectNode
} else if (valueToBeUpdated != null && valueToBeUpdated.isObject()) {
merge(valueToBeUpdated, updatedValue);
} else {
if (mainNode instanceof ObjectNode) {
((ObjectNode) mainNode).replace(updatedFieldName, updatedValue);
}
}
}
return mainNode;
}
【讨论】:
valueToBeUpdated 转换为ArrayNode 是不安全的。例如,您可以获得TextNode,而不是该变量中的ArrayNode。
以下是 Scala 中的实现。源节点和目标节点大多是可交换的,除非在源节点和目标节点中都存在分支。
def mergeYamlObjects(source: ObjectNode, target: ObjectNode, overwrite: Boolean = true): ObjectNode = {
if (target == null)
source
else if (source == null)
target
else {
val result = source.deepCopy
val fieldlist = source.fieldNames.asScala.toList ++ target.fieldNames.asScala.toList
for (item <- fieldlist) {
if (!(source has item)) {
result put(item, target get item)
} else {
if ((source get item).isValueNode) {
if (target has item)
if (overwrite)
result.put(item, target get item)
} else {
result.put(item, mergeYamlObjects(source.get(item).asInstanceOf[ObjectNode],
target.get(item).asInstanceOf[ObjectNode], overwrite = overwrite))
}
}
}
result
}
}
【讨论】:
如果有人只是想将两个或多个 JsonNode 对象添加到一个 JsonNode 中,这可以是一种方法:
ArrayNode arrayNode = objectMapper.createArrayNode();
arrayNode.add(firstJsonNode);
arrayNode.add(secondJsonNode);
arrayNode.add(thirdJsonNode);
JsonNode root = JsonNodeFactory.instance.objectNode();
((ObjectNode) root).put("", arrayNode);
System.out.println("merged array node #: " + root);
【讨论】:
这里是合并两个 JSON 树为一的完整实现。希望对您有所帮助:)
/**
* Merge two JSON tree into one i.e mergedInTo.
*
* @param toBeMerged
* @param mergedInTo
*/
public static void merge(JsonNode toBeMerged, JsonNode mergedInTo) {
Iterator<Map.Entry<String, JsonNode>> incomingFieldsIterator = toBeMerged.fields();
Iterator<Map.Entry<String, JsonNode>> mergedIterator = mergedInTo.fields();
while (incomingFieldsIterator.hasNext()) {
Map.Entry<String, JsonNode> incomingEntry = incomingFieldsIterator.next();
JsonNode subNode = incomingEntry.getValue();
if (subNode.getNodeType().equals(JsonNodeType.OBJECT)) {
boolean isNewBlock = true;
mergedIterator = mergedInTo.fields();
while (mergedIterator.hasNext()) {
Map.Entry<String, JsonNode> entry = mergedIterator.next();
if (entry.getKey().equals(incomingEntry.getKey())) {
merge(incomingEntry.getValue(), entry.getValue());
isNewBlock = false;
}
}
if (isNewBlock) {
((ObjectNode) mergedInTo).replace(incomingEntry.getKey(), incomingEntry.getValue());
}
} else if (subNode.getNodeType().equals(JsonNodeType.ARRAY)) {
boolean newEntry = true;
mergedIterator = mergedInTo.fields();
while (mergedIterator.hasNext()) {
Map.Entry<String, JsonNode> entry = mergedIterator.next();
if (entry.getKey().equals(incomingEntry.getKey())) {
updateArray(incomingEntry.getValue(), entry);
newEntry = false;
}
}
if (newEntry) {
((ObjectNode) mergedInTo).replace(incomingEntry.getKey(), incomingEntry.getValue());
}
}
ValueNode valueNode = null;
JsonNode incomingValueNode = incomingEntry.getValue();
switch (subNode.getNodeType()) {
case STRING:
valueNode = new TextNode(incomingValueNode.textValue());
break;
case NUMBER:
valueNode = new IntNode(incomingValueNode.intValue());
break;
case BOOLEAN:
valueNode = BooleanNode.valueOf(incomingValueNode.booleanValue());
}
if (valueNode != null) {
updateObject(mergedInTo, valueNode, incomingEntry);
}
}
}
private static void updateArray(JsonNode valueToBePlaced, Map.Entry<String, JsonNode> toBeMerged) {
toBeMerged.setValue(valueToBePlaced);
}
private static void updateObject(JsonNode mergeInTo, ValueNode valueToBePlaced,
Map.Entry<String, JsonNode> toBeMerged) {
boolean newEntry = true;
Iterator<Map.Entry<String, JsonNode>> mergedIterator = mergeInTo.fields();
while (mergedIterator.hasNext()) {
Map.Entry<String, JsonNode> entry = mergedIterator.next();
if (entry.getKey().equals(toBeMerged.getKey())) {
newEntry = false;
entry.setValue(valueToBePlaced);
}
}
if (newEntry) {
((ObjectNode) mergeInTo).replace(toBeMerged.getKey(), toBeMerged.getValue());
}
}
【讨论】: