如何将JSON反序列化为平面,类似Map的结构? [英] How to deserialize JSON into flat, Map-like structure?

查看:198
本文介绍了如何将JSON反序列化为平面,类似Map的结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



例如, p>

以下JSON

  {
端口:
{
@alias:defaultHttp,
已启用:true,
数字:10092,
协议: http,
KeepAliveTimeout:20000,
ThreadPool:
{
@enabled:false,
Max: 150,
ThreadPriority:5
},
ExtendedProperties:
{
物业:
[
{
@ name:connectionTimeout,
$:20000
}
]
}
}
}

应该反序列化为类似Map的结构,其中包含键(不是全部)以上简称包括:

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

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

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

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

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

虽然我需要使用点平展键的平面地图符号,就像上面那样。



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

解决方案

您可以执行此操作来遍历树并跟踪您找出点符号属性名称的深度:

  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;

公共类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+
\ \\:\ 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是任意的。


Have in mind that the JSON structure is not known before hand i.e. it is completely arbitrary, we only know that it is JSON format.

For example,

The following JSON

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

Should be deserialized into Map-like structure having keys like (not all of the above included for brevity):

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

I am looking into Jackson currently, so there we have:

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

However, the resulting Map instance is basically a Map of nested Maps:

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

While I need flat Map with flatten keys using "dot notation", like the above.

I would rather not implement this myself, although at the moment I don't see any other way...

解决方案

You can do this to traverse the tree and keep track of how deep you are to figure out dot notation property names:

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());
    }
  }
}

It produces the following map:

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

It should be easy enough to strip out @ and $ in the property names, although you could end up with collisions in key names since you said the JSON was arbitrary.

这篇关于如何将JSON反序列化为平面,类似Map的结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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