如何将JSON反序列化为平面,类似Map的结构?

 wendy-kiki8 发布于 2023-02-13 10:45

请记住,JSON结构之前是未知的,即它完全是任意的,我们只知道它是JSON格式.

例如,

以下JSON

{
   "Port":
   {
       "@alias": "defaultHttp",
       "Enabled": "true",
       "Number": "10092",
       "Protocol": "http",
       "KeepAliveTimeout": "20000",
       "ThreadPool":
       {
           "@enabled": "false",
           "Max": "150",
           "ThreadPriority": "5"
       },
       "ExtendedProperties":
       {
           "Property":
           [                         
               {
                   "@name": "connectionTimeout",
                   "$": "20000"
               }
           ]
       }
   }
}

应该被反序列化为具有键的类似Map的结构(为了简洁,不包括以上所有内容):

port[0].alias
port[0].enabled
port[0].extendedProperties.connectionTimeout
port[0].threadPool.max

我目前正在调查杰克逊,所以我们有:

TypeReference> typeRef = new TypeReference>() {};
Map o = objectMapper.readValue(jsonString, typeRef);

但是,生成的Map实例基本上是嵌套地图的Map:

{Port={@alias=diagnostics, Enabled=false, Type=DIAGNOSTIC, Number=10033, Protocol=JDWP, ExtendedProperties={Property={@name=suspend, $=n}}}}

虽然我需要使用"点符号"使用展平键的平面地图,如上所述.

我宁愿不自己实现这个,虽然此刻我没有看到任何其他方式......

3 个回答
  • 您可以执行此操作来遍历树并跟踪您有多深,以找出点符号属性名称:

    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ArrayNode;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    import com.fasterxml.jackson.databind.node.ValueNode;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import org.junit.Test;
    
    public class FlattenJson {
      String json = "{\n" +
          "   \"Port\":\n" +
          "   {\n" +
          "       \"@alias\": \"defaultHttp\",\n" +
          "       \"Enabled\": \"true\",\n" +
          "       \"Number\": \"10092\",\n" +
          "       \"Protocol\": \"http\",\n" +
          "       \"KeepAliveTimeout\": \"20000\",\n" +
          "       \"ThreadPool\":\n" +
          "       {\n" +
          "           \"@enabled\": \"false\",\n" +
          "           \"Max\": \"150\",\n" +
          "           \"ThreadPriority\": \"5\"\n" +
          "       },\n" +
          "       \"ExtendedProperties\":\n" +
          "       {\n" +
          "           \"Property\":\n" +
          "           [                         \n" +
          "               {\n" +
          "                   \"@name\": \"connectionTimeout\",\n" +
          "                   \"$\": \"20000\"\n" +
          "               }\n" +
          "           ]\n" +
          "       }\n" +
          "   }\n" +
          "}";
    
      @Test
      public void testCreatingKeyValues() {
        Map<String, String> map = new HashMap<String, String>();
        try {
          addKeys("", new ObjectMapper().readTree(json), map);
        } catch (IOException e) {
          e.printStackTrace();
        }
        System.out.println(map);
      }
    
      private void addKeys(String currentPath, JsonNode jsonNode, Map<String, String> map) {
        if (jsonNode.isObject()) {
          ObjectNode objectNode = (ObjectNode) jsonNode;
          Iterator<Map.Entry<String, JsonNode>> iter = objectNode.fields();
          String pathPrefix = currentPath.isEmpty() ? "" : currentPath + ".";
    
          while (iter.hasNext()) {
            Map.Entry<String, JsonNode> entry = iter.next();
            addKeys(pathPrefix + entry.getKey(), entry.getValue(), map);
          }
        } else if (jsonNode.isArray()) {
          ArrayNode arrayNode = (ArrayNode) jsonNode;
          for (int i = 0; i < arrayNode.size(); i++) {
            addKeys(currentPath + "[" + i + "]", arrayNode.get(i), map);
          }
        } else if (jsonNode.isValueNode()) {
          ValueNode valueNode = (ValueNode) jsonNode;
          map.put(currentPath, valueNode.asText());
        }
      }
    }
    

    它产生以下地图:

    Port.ThreadPool.Max=150, 
    Port.ThreadPool.@enabled=false, 
    Port.Number=10092, 
    Port.ExtendedProperties.Property[0].@name=connectionTimeout, 
    Port.ThreadPool.ThreadPriority=5, 
    Port.Protocol=http, 
    Port.KeepAliveTimeout=20000, 
    Port.ExtendedProperties.Property[0].$=20000, 
    Port.@alias=defaultHttp, 
    Port.Enabled=true
    

    它应该很容易剥离@$在属性名称中,尽管你可能最终会在键名中发生冲突,因为你说JSON是任意的.

    2023-02-13 10:46 回答
  • 如何使用json-flattener.https://github.com/wnameless/json-flattener

    顺便说一下,我是这个lib的作者.

    String flattenedJson = JsonFlattener.flatten(yourJson);
    Map<String, Object> flattenedJsonMap = JsonFlattener.flattenAsMap(yourJson);
    
    // Result:
    {
        "Port.@alias":"defaultHttp",
        "Port.Enabled":"true",
        "Port.Number":"10092",
        "Port.Protocol":"http",
        "Port.KeepAliveTimeout":"20000",
        "Port.ThreadPool.@enabled":"false",
        "Port.ThreadPool.Max":"150",
        "Port.ThreadPool.ThreadPriority":"5",
        "Port.ExtendedProperties.Property[0].@name":"connectionTimeout",
        "Port.ExtendedProperties.Property[0].$":"20000"
    }
    

    2023-02-13 10:46 回答
  • 那个怎么样:

    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    import com.google.gson.Gson;
    
    /**
     * NOT FOR CONCURENT USE
    */
    @SuppressWarnings("unchecked")
    public class JsonParser{
    
    Gson gson=new Gson();
    Map<String, String> flatmap = new HashMap<String, String>();
    
    public Map<String, String> parse(String value) {        
        iterableCrawl("", null, (gson.fromJson(value, flatmap.getClass())).entrySet());     
        return flatmap; 
    }
    
    private <T> void iterableCrawl(String prefix, String suffix, Iterable<T> iterable) {
        int key = 0;
        for (T t : iterable) {
            if (suffix!=null)
                crawl(t, prefix+(key++)+suffix);
            else
                crawl(((Entry<String, Object>) t).getValue(), prefix+((Entry<String, Object>) t).getKey());
        }
    }
    
    private void crawl(Object object, String key) {
        if (object instanceof ArrayList)
            iterableCrawl(key+"[", "]", (ArrayList<Object>)object);
        else if (object instanceof Map)
            iterableCrawl(key+".", null, ((Map<String, Object>)object).entrySet());
        else
            flatmap.put(key, object.toString());
    }
    }
    

    2023-02-13 10:48 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有