2014-06-25 104 views
4

我有一个JSON字符串,我从包含重复键的数据库中获取。我想通过将它们的值组合到一个数组中来移除重复的键。将具有重复键的JSON对象转换为JSON数组

例如

输入

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

输出

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

的实际数据是可以被嵌套在较大的文件。我不会提前知道什么或有多少对。

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

如果可能的话,我想做到这一点,而无需编辑任何库代码

+1

JSON对象不能包含具有相同键的2个项目。在你的例子json中,c的第一个外观将被覆盖。你可以通过http://jsonlint.com/ –

+0

验证你的json来看到这一点。从技术上讲,你从数据库获得的东西不是“JSON”。您需要重新评估数据的写入方式,或者更可能需要自己为数据编写某种解析器。我想不出一个期望通过这种方式来转换数据的库。 – Tejs

+0

根据这个问题,它是有效的,尽管解析器不允许出于显而易见的原因。我真的不在乎,如果它不是有效的JSON,只要我可以将重复值的字符串格式转换为字符串格式没有重复值http://stackoverflow.com/questions/21832701/does-json-syntax-allow-duplicate-键入对象 – adamF

回答

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

输出:
{
“一”: “B”,
“c”:[“d”,“e”],
“f”:“g”
}

+0

真棒!不再需要它,但只是我很久以前想要的:) – adamF

+0

认为是这样,因为问题是3岁,但嘿它可以对别人有用:) – Kainix

0

为了完成你想要什么,你需要创建某种自定义类的,因为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; 
} 
} 

然后,您可以从数据库中检索值,从数据库中调用.add(String key, Object o)功能与列名和值(为Object PARAM)。完成后请致电.toJson()

+0

这太难编码了。我给出的例子只是为了说明问题。我的实际数据是一个很大的嵌套文件,我不知道提前了解什么或有多少字段。即使我将它抽象出来,我仍然需要一种可靠地解析json字符串的方法。 – adamF

+0

使其具有通用性。在JSON中可以有任何类型的值。 – Braj

+0

使用地图进行通用化。每次读入一个键值对,检查键是否存在于映射中,如果存在,则将该值添加到该键的列表中,如果没有,则创建一个包含该值的新列表并添加它在那个关键。然后,在toJSON中,遍历每个'Entry' –

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"] 
} 
0

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