【问题标题】:Convert a JSON object to a Map object将 JSON 对象转换为 Map 对象
【发布时间】:2015-10-12 06:37:05
【问题描述】:

我有一个 JSON 对象,如下所示:

[{"var1":"value1","var2":"value2"},{"var2":"value22","var3":[["0","1","2"],["3","4","5"],["6","7","8"]]}]

(注意:var2在例子中出现了两次以及var3的值的复数形式。)

所需的输出应该是一个地图对象,例如:

key   value
var1  value1
var2  value2,value22
var3  [["0","1","2"],["3","4","5"],["6","7","8"]]

我想要将其转换为一个地图对象,其中第一个元素(var1var2var3)作为键,相应的值作为地图中的值。如果具有相同的键(例如:var2),属于此键的两个值应连接,但应分隔,例如,用逗号分隔。

有人可以帮我解决这个问题吗?

【问题讨论】:

  • 首先,String 不是有效的 json。其次,向我们展示所需的输出以及迄今为止您尝试过的内容
  • 我拥有的数据与示例的结构相似。对于我的尝试:由于我对 java 完全陌生,到目前为止我还没有尝试太多,因为它对我来说有点太复杂了
  • 所以在尝试解决这个复杂的主题之前,也许您应该先获得一些使用该语言完成更简单任务的经验?
  • @sharonbn 原因是我必须这样做
  • 字符串实际上是 JSON 还是类似于 JSON?您发布的示例不是,在这种情况下,您需要编写自己的解析器。但是,如果实际输入是有效的 JSON,您可以使用像 gson 这样的库来处理数据。

标签: java json dictionary


【解决方案1】:

您不需要适配器来解析 json。你只需要告诉 ObjectMapper 到底要解析成什么类型​​。您还需要一些后期处理,因为您需要一些关于重复键的特殊处理

你从 GIT 得到 Jackson:https://github.com/FasterXML/jackson

这里有一个完整的解决方案:

import java.util.*;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.type.TypeFactory;

public class Test
{
    public static void main(String[] args)
    {
        String input = "[{\"var1\":\"value1\",\"var2\":\"value2\"},{\"var2\":\"value22\",\"var3\":[[\"0\",\"1\",\"2\"],[\"3\",\"4\",\"5\"],[\"6\",\"7\",\"8\"]]}]" ;
        Map<String, String> result = new HashMap<>();  // final result, with duplicate keys handles and everything

        try {
            // ObjectMapper is Jackson json parser 
            ObjectMapper om = new ObjectMapper();
            // we need to tell ObjectMapper what type to parse into 
            // in this case: list of maps where key is string and value is some cimplex Object
            TypeFactory tf = om.getTypeFactory();
            JavaType mapType = tf.constructMapType(HashMap.class, String.class, Object.class);
            JavaType listType = tf.constructCollectionType(List.class, mapType);
            @SuppressWarnings("unchecked")
            // finally we parse the input into the data struct 
            List<Map<String, Object>> list = (List<Map<String, Object>>)om.readValue(input, listType);

            // post procesing: populate result, taking care of duplicates 
            for (Map<String, Object> listItem : list) {
                for (Map.Entry<String, Object> mapItem : listItem.entrySet()) {
                    String key = mapItem.getKey();
                    String value = mapItem.getValue().toString();
                    if (result.containsKey(key)) value = result.get(key) + "," + value;
                    result.put(key, value);
                }
            }

            // result sohuld hold expected outut now 
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出:

{var3=[[0, 1, 2], [3, 4, 5], [6, 7, 8]], var2=value2,value22, var1=value1}

【讨论】:

  • 加了cmets讲解全过程
  • 谢谢 sharonbn!看起来很有希望,只需要为我的情况实施它......我会尽快提供反馈
  • 我安装了所需的 jar,但现在出现一个错误:它与 List&lt;Map&lt;String, Object&gt;&gt; list = (List&lt;Map&lt;String, Object&gt;&gt;)om.readValue(input, listType); 行有关,并说:此行有多个标记 - com.fasterxml.jackson.core.type.TypeReference 类型不能解决。它是从所需的 .class 文件中间接引用的..... - ObjectMapper 类型中的方法 readValue(String, JavaType) 指的是缺少的类型 JsonParseException,om.readValue(input, listType) 部分带有红色下划线
  • 解决了错误!但现在在 Eclipse 中看不到任何错误,但在运行脚本后我得到: 线程“main”中的异常 java.lang.NoClassDefFoundError: com/fasterxml/jackson/annotation/JsonAutoDetect at com.fasterxml.jackson.databind.introspect.VisibilityChecker$ Std.(VisibilityChecker.java:170) 在 com.fasterxml.jackson.databind.ObjectMapper.(ObjectMapper.java:261) 在 my_hive_project2.json_to_map.main(json_to_map.java:17)
【解决方案2】:

您可以使用 Jackson 在 JSON 和 Map 之间进行转换。使用如下代码实例化JSonAdapter类,使用marshal(String)方法将json字符串转换为map,unmarshall(Map)反之。

import java.io.IOException;
import java.util.Map;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonAdapter {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    public String unmarshal(final Map<?, ?> jsonList) throws Exception {
        return MAPPER.writeValueAsString(jsonList);
    }

    public Map<?, ?> marshal(final String jsonString) throws Exception {

        try {
            return MAPPER.readValue(jsonString, new TypeReference<Map<?, ?>>() {
            });
        } catch (final IOException e) {
            e.printStackTrace();
        }

        return null;
    }

}

【讨论】:

  • 为什么 JsonAdapter 扩展 XmlAdapter? xml和它有什么关系?
  • 我还必须扩展另一个类,UDF 类,因为这是一个用于 hive 的 UDF。据我所知,我只能扩展一个类。我怎么能把它集成到这段代码中?谢谢!
  • 我已经编辑了代码,请看一下...理想情况下是使用 MAPPER.writeValueAsString 和 MAPPER.readValue 方法的问题,谢谢。
  • @sharonbn,xml在这里无关。 “Jackson 是“100% JSON”,不会尝试模仿或模拟 XML。属性名称映射基于标准 Java Bean 命名约定(尽管可以使用注释或自定义命名策略覆盖)。”
  • 我不明白如何将这段代码呈现为答案。键位于 json 列表中的单独项目内。重复键的处理在哪里?
【解决方案3】:

没有预定义的 API 来执行您的操作,您必须编写自己的解析器来将 JSONObject 转换为 Map

请看下面的一些提示:

public static Map<String, Object> toMap(JSONObject object) throws JSONException{
    Map<String, List<String>> map = new HashMap<String, List<String>>();
    Iterator<String> keysIterator = object.keys();
    while(keysIterator .hasNext()) {
        String key = keysIterator.next();
        Object value = object.get(key);

        if(map.contains(key)){
         ... //do your task
        }

       ... //get value of the key 

      map.put(key, yourValue)
    }

【讨论】:

  • 仅供参考,Jackson 库能够将 json 字符串解析为 Map。
  • @sharonbn 但它会在相同键的情况下解析成连接字符串。
  • 不,不会。仍然需要一些后期处理。但是,与您的文本相反,提供了 json 到 map 的简单转换
  • 不应该有课吗?
猜你喜欢
  • 2011-12-23
  • 2016-09-23
  • 1970-01-01
  • 1970-01-01
  • 2015-01-02
  • 1970-01-01
  • 1970-01-01
  • 2017-06-16
  • 2016-04-24
相关资源
最近更新 更多