Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将具有重复键的JSON对象转换为JSON数组_Java_Json_Duplicates_Gson_Arrays - Fatal编程技术网

Java 将具有重复键的JSON对象转换为JSON数组

Java 将具有重复键的JSON对象转换为JSON数组,java,json,duplicates,gson,arrays,Java,Json,Duplicates,Gson,Arrays,我有一个JSON字符串,它来自一个包含重复键的数据库。我想通过将重复的键的值组合到一个数组中来删除它们 比如说 输入 输出 { "a":"b", "c":["d","e"], "f":"g" } 实际数据是一个可能嵌套的大文件。我不会提前知道有什么或多少对 我需要使用Java来实现这一点。由于重复的键,org.json抛出异常,gson可以解析字符串,但每个重复的键都会覆盖最后一个。我需要保留所有的数据 如果可能的话,我希望在不编辑任何库代码的情况下执行此操作。为了实现您想要的功能,您需要创建

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

比如说

输入

输出

{
"a":"b",
"c":["d","e"],
"f":"g"
}
实际数据是一个可能嵌套的大文件。我不会提前知道有什么或多少对

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


如果可能的话,我希望在不编辑任何库代码的情况下执行此操作。为了实现您想要的功能,您需要创建某种自定义类,因为从技术上讲,
JSON
不能在一个键上有两个值。以下是一个例子:

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;
}
}
公共类SomeClass{
映射值=新的HashMap();
公共void添加(字符串键,对象o){
列表值=新的ArrayList();
if(值。容器(键)){
value=values.get(键);
}
增值(o);
value.put(键、值);
}
公共JSONObject toJson()抛出JSONException{
JSONObject json=新的JSONObject();
JSONArray tempArray=null;
对于(条目en:values.entrySet()){
tempArray=newjsonarray();
对于(对象o:en.getValue()){
添加(o);
}
put(en.getKey(),tempArray);
}
返回json;
}
}
然后,您可以从数据库中检索值,使用数据库中的列名和值(作为
对象
参数)调用
.add(字符串键,对象o)
函数。完成后,调用
.toJson()

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

考虑JSON解析库之外的其他问题。这是一个非常简单的Java程序,它使用
String.split()
方法将Json字符串转换为
Map
,而不使用任何库

示例代码:

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

感谢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();
}
publicstaticstringrepeatedkeystarray(stringjsonin)抛出JSONException
{
//这假设json是平面的
字符串jsonString=jsonIn.substring(2,jsonIn.length()-2);
JSONObject obj=新的JSONObject();
对于(字符串值:jsonString.split(“\”,\”)){
字符串[]keyValue=values.split(“\”:\”);
字符串键=键值[0];
字符串值=”;
如果(keyValue.length>1)值=keyValue[1];
如果(!对象有(键)){
对象put(键、值);
}否则{
对象Oold=obj.get(键);
ArrayList newlist=新的ArrayList();
//尝试转换为JSONArray。否则,假设它是一个字符串
if(Oold.getClass().equals(JSONArray.class)){
JSONArray old=(JSONArray)Oold;
//建立重置价值

对于(int i=0;i到今天为止,
org.json
库版本
20170516
提供了
acculate()
方法,该方法将重复的键条目存储到
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"  
}

JSON对象不能包含两个具有相同键的项。在您的示例JSON中,c的第一个外观将被覆盖。您可以通过验证JSON来了解这一点,从技术上讲,您从数据库获得的内容不是“JSON”然后。你需要重新评估数据是如何写入的,或者更可能的是,自己为数据编写某种解析器。我想不出一个库会期望以这种方式转换数据。根据这个问题,它是有效的,尽管解析器出于明显的原因不允许这样做。我真的不在乎它是否正确无效的JSON,只要我能将带有重复值的字符串格式转换为没有重复值的字符串格式,这太难了。我给出的示例只是为了说明这个问题。我的实际数据是一个大型嵌套文件,我不知道提前有什么或多少字段。即使我抽象了其中的一些字段如果不这样做,我仍然需要一种可靠地解析json字符串的方法。使其通用。json中可以有任何类型的值。使用映射使其通用。一次读取一个键-值对,检查键是否存在于映射中,如果存在,将值添加到该键的列表中,如果不存在,则使用该值创建一个新列表,并将其添加到然后,在toJSON中,迭代每个
条目
我已经更新了我的答案,展示了如何使用地图使其通用。太棒了!不再需要它了,但正是我很久以前一直在寻找的:)我这么认为,因为这个问题已经3年了,但是嘿,它对其他人可能有用:)
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"  
}