【问题标题】:Convert JSON object with duplicate keys to JSON array将具有重复键的 JSON 对象转换为 JSON 数组
【发布时间】:2014-08-16 12:08:24
【问题描述】:

我有一个从包含重复键的数据库中获取的 JSON 字符串。我想通过将它们的值组合到一个数组中来删除重复的键。

例如

输入

{
"a":"b",
"c":"d",
"c":"e",
"f":"g"
}

输出

{
"a":"b",
"c":["d","e"],
"f":"g"
}

实际数据是一个可能嵌套的大文件。我不会提前知道有什么或有多少对。

我需要为此使用 Java。 org.json 由于重复键引发异常,gson 可以解析字符串但每个重复的键都会覆盖最后一个。我需要保留所有数据。

如果可能,我想在不编辑任何库代码的情况下这样做

【问题讨论】:

  • JSON 对象不能包含具有相同键的 2 个项目。在您的示例 json 中,c 的第一次出现将被覆盖。您可以通过在 jsonlint.com 验证您的 json 来查看这一点
  • 从技术上讲,您从数据库中获取的内容不是“JSON”。您需要重新评估数据是如何写入的,或者更有可能自己为您的数据编写某种解析器。我想不出一个库会期望以这种方式转换数据。
  • 根据这个问题,它是有效的,尽管解析器出于明显的原因不允许这样做。我真的不在乎它是否不是有效的 JSON,只要我可以将具有重复值的字符串格式转换为没有重复值的字符串格式stackoverflow.com/questions/21832701/…

标签: java json duplicates gson arrays


【解决方案1】:

截至今天,org.json 库版本 20170516 提供了 accumulate() 方法,可将重复的键条目存储到 JSONArray

JSONObject jsonObject = new JSONObject();
jsonObject.accumulate("a", "b");
jsonObject.accumulate("c", "d");
jsonObject.accumulate("c", "e");
jsonObject.accumulate("f", "g");
System.out.println(jsonObject);

输出:

{  
    "a":"b",  
    "c":["d","e"],  
    "f":"g"  
}

【讨论】:

  • 太棒了!不再需要它,但正是我很久以前在寻找的东西:)
  • 是这样想的,因为这个问题已经 3 岁了,但它对其他人可能有用:)
【解决方案2】:

我想通过将它们的值组合到一个数组中来删除重复的键。

想想 JSON 解析库以外的东西。这是一个非常简单的 Java 程序,使用 String.split() 方法将 Json 字符串转换为 Map<String, List<String>> 不使用任何库

示例代码:

String jsonString = ...
// remove enclosing braces and double quotes
jsonString = jsonString.substring(2, jsonString.length() - 2);

Map<String, List<String>> map = new HashMap<String, List<String>>();
for (String values : jsonString.split("\",\"")) {
    String[] keyValue = values.split("\":\"");
    String key = keyValue[0];
    String value = keyValue[1];

    if (!map.containsKey(key)) {
        map.put(key, new ArrayList<String>());
    }
    map.get(key).add(value);
}

输出:

{
  "f": ["g"],
  "c": ["d","e"],
  "a": ["b"]
}

【讨论】:

    【解决方案3】:

    为了完成你想要的,你需要创建某种自定义类,因为JSON 在技术上不能在一个键上有 2 个值。下面是一个例子:

    public class SomeClass {
    
    Map<String, List<Object>> values = new HashMap<String, List<Object>>();
    
    public void add(String key, Object o) {
        List<Object> value = new ArrayList<Object>();
        if (values.containsKey(key)) {
            value = values.get(key);
        }
        value.add(o);
        values.put(key, value);
    }
    
    public JSONObject toJson() throws JSONException {
        JSONObject json = new JSONObject();
        JSONArray tempArray = null;
    
        for (Entry<String, List<Object>> en : values.entrySet()) {
            tempArray = new JSONArray();
            for (Object o : en.getValue()) {
                tempArray.add(o);
            }
            json.put(en.getKey(), tempArray);
        }
    
        return json;
    }
    }
    

    然后您可以从数据库中检索值,使用数据库中的列名和值(作为Object 参数)调用.add(String key, Object o) 函数。完成后致电.toJson()

    【讨论】:

    • 这编码太难了。我举的例子只是为了说明问题。我的实际数据是一个大的嵌套文件,我不提前知道有什么或有多少字段。即使我将其中的一些抽象出来,我仍然需要一种方法来可靠地解析 json 字符串。
    • 让它通用。 JSON 中可以有任何类型的值。
    • 使用地图使其通用。一次读取一个键值对,检查该键是否存在于映射中,如果存在,则将该值添加到该键的列表中,如果不存在,则使用该值创建一个新列表并添加它在那个关键。然后,在 toJSON 中,遍历每个 Entry
    • 我已经更新了我的答案,展示了如何使用地图使其通用。
    【解决方案4】:

    感谢 Mike Elofson 和 Braj 帮助我朝着正确的方向前进。我只想让具有多个值的键成为数组,所以我不得不稍微修改一下代码。最终我希望它也适用于嵌套的 JSON,因为它目前假设它是平坦的。但是,下面的代码可以满足我目前的需要。

    public static String repeatedKeysToArrays(String jsonIn) throws JSONException 
    {
        //This assumes that the json is flat
        String jsonString = jsonIn.substring(2, jsonIn.length() - 2);
    
        JSONObject obj = new JSONObject();
        for (String values : jsonString.split("\",\"")) {
            String[] keyValue = values.split("\":\"");
            String key = keyValue[0];
            String value = ""; 
            if (keyValue.length>1) value = keyValue[1];
    
            if (!obj.has(key)) {
                obj.put(key, value);
            } else {
                Object Oold = obj.get(key);
                ArrayList<String> newlist = new ArrayList<String>();
    
                //Try to cast as JSONArray. Otherwise, assume it is a String
                if (Oold.getClass().equals(JSONArray.class)) {
                    JSONArray old = (JSONArray)Oold;
                    //Build replacement value
                    for (int i=0; i<old.length(); i++) {
                        newlist.add( old.getString(i) );
                    }
                }
                else if (Oold.getClass().equals(String.class)) newlist = new ArrayList<String>(Arrays.asList(new String[] {(String)Oold})); 
                newlist.add(value);
    
                JSONArray newarr = new JSONArray( newlist );
                obj.put(key,newarr);                
            }
        }
        return obj.toString();
    }
    

    【讨论】:

      猜你喜欢
      • 2020-11-02
      • 2020-10-01
      • 2020-11-26
      • 1970-01-01
      • 2020-02-06
      • 2015-04-21
      • 2021-11-08
      • 1970-01-01
      • 2022-08-03
      相关资源
      最近更新 更多