我有一个关于Flatten a JSON string to Map using Gson or Jackson的问题。
我的场景包含了重复的密钥,所以上面问题的解决方案会导致一些重复的密钥被覆盖,所以我想通过将每一层的密钥组合在一起来构造密钥。
那么如何实现呢?
例如:
{
"id" : "123",
"name" : "Tom",
"class" : {
"subject" : "Math",
"teacher" : "Jack"
}
}
我想得到Map:
"id" : "123",
"name" : "Tom",
"class.subject" : "Math",
"class.teacher" : "Jack"
基于@Manos Nikolaidis的回答,我能够通过考虑ArrayNode实现以下解决方案。
public void processJsonString(String jsonString) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ArrayNode arrayNode = (ArrayNode) mapper.readTree(jsonString);
processArrayNode(arrayNode);
}
private void processObjectNode(JsonNode jsonNode) {
Map<String, String> result = new HashMap<>();
Iterator<Map.Entry<String, JsonNode>> iterator = jsonNode.fields();
iterator.forEachRemaining(node -> mapAppender(result, node, new ArrayList<String>()));
}
private void processArrayNode(ArrayNode arrayNode) {
for (JsonNode jsonNode : arrayNode) {
processObjectNode(jsonNode);
}
}
private void mapAppender(Map<String, String> result, Map.Entry<String, JsonNode> node, List<String> names) {
names.add(node.getKey());
if (node.getValue().isTextual()) {
String name = names.stream().collect(Collectors.joining("."));
result.put(name, node.getValue().asText());
} else if (node.getValue().isArray()) {
processArrayNode((ArrayNode) node.getValue());
} else if (node.getValue().isNull()) {
String name = names.stream().collect(Collectors.joining("."));
result.put(name, null);
} else {
node.getValue().fields()
.forEachRemaining(nested -> mapAppender(result, nested, new ArrayList<>(names)));
}
}
2条答案
按热度按时间xytpbqjk1#
您可以将JSON表示为
JsonNode
,然后递归地遍历所有字段,并将键和值字段添加到Map中。如果值是对象而不是字符串,则可以将字段名添加到List中,以便在最终遇到字符串时与句点连接。首先创建一个单独的方法(为了可读性),将Json字段添加到Map
中:像这样使用它:
其中
fields()
返回一个Iterator
。注意StackOverflowErrors
,并且对于深度嵌套的JSON可能会降低性能。t5fffqht2#
我使用下面的简单代码解决了这个问题,只认为是需要下载抛弃和展平. JsonFlatener库
参考链接:https://github.com/wnameless/json-flattener