平展一个JSON字符串,使包含每个关键值的键到Map< String,String>使用Gson或Jackson [英] Flatten a JSON string to make the key including each level key value to Map<String, String> using Gson or Jackson

查看:109
本文介绍了平展一个JSON字符串,使包含每个关键值的键到Map< String,String>使用Gson或Jackson的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于拼合使用Gson或Jackson的地图的JSON字符串

我的方案包含重复的密钥,因此上述问题中的解决方案会导致重写的密钥被覆盖。所以我想通过将每个关卡的关键字组合在一起来构造关键字。

那么如何实现这一点?



例如:

  {
id:123,
name:Tom,
class:{
科目:数学,
老师:杰克
}
}

我想得到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>()));

$ b private void processArrayNode(ArrayNode arrayNode){
for(JsonNode jsonNode:arrayNode){
processObjectNode(jsonNode);



$ b private void mapAppender(Map< String,String> result,Map.Entry< String,JsonNode>节点,List< String>名称) {
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)));



$ div $解析方案

你可以获取JSON作为 JsonNode 并递归遍历所有字段并将键和值字段添加到Map中。当一个值是一个对象而不是字符串时,您可以将字段名称添加到要与最终遇到字符串的句点连接的List中。首先创建一个单独的方法,将Json字段添加到 Map

  void mapAppender(Map< String,String> result,Entry< String,JsonNode> node,List< String>名称){
names.add(node.getKey());
if(node.getValue()。isTextual()){
String name = names.stream()。collect(joining(。));
result.put(name,node.getValue()。asText());
} else {
node.getValue()。fields()
.forEachRemaining(nested - > mapAppender(result,nested,new ArrayList<>(names)));


$ / code $ / pre

并像这样使用它:

  ObjectMapper mapper = new ObjectMapper(); 
Map< String,String> result = new HashMap<>();
mapper.readTree(json).fields()
.forEachRemaining(node - > mapAppender(result,node,new ArrayList< String>()));

其中 fields()返回一个迭代。请注意 StackOverflowErrors ,对于深度嵌套的JSON可能性能较低。


I have an enhanced question regarding Flatten a JSON string to Map using Gson or Jackson.

My scenario included duplicated keys, so the solution in the above question will cause some duplicated keys overwritten. So I am thinking to construct keys by combining each level's key together.

So how to achieve that?

For example:

{
    "id" : "123",
    "name" : "Tom",
    "class" : {
        "subject" : "Math",
        "teacher" : "Jack"
    }
}

I want to get the Map:

"id" : "123",
"name" : "Tom",
"class.subject" : "Math",
"class.teacher" : "Jack"

************************Update Solution*************************************

Based on @Manos Nikolaidis's answer, I am able to achieve the following solution by considering 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)));
    }
}

解决方案

You can get the JSON as JsonNode and go through all fields recursively and add key and value field to a Map. When a value is an object instead of string you can add the field name to List to be joined with periods when a string is finally encountered. First create (for readability) a separate method that add Json fields to a Map:

void mapAppender(Map<String, String> result, Entry<String, JsonNode> node, List<String> names) {
    names.add(node.getKey());
    if (node.getValue().isTextual()) {
        String name = names.stream().collect(joining("."));
        result.put(name, node.getValue().asText());
    } else {
        node.getValue().fields()
            .forEachRemaining(nested -> mapAppender(result, nested, new ArrayList<>(names)));
    }
}

and use it like this:

ObjectMapper mapper = new ObjectMapper();
Map<String, String> result = new HashMap<>();
mapper.readTree(json).fields()
    .forEachRemaining(node -> mapAppender(result, node, new ArrayList<String>()));

Where fields() returns an Iterator. Beware of StackOverflowErrors and perhaps low performance for deeply nested JSON.

这篇关于平展一个JSON字符串,使包含每个关键值的键到Map&lt; String,String&gt;使用Gson或Jackson的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆