6

我有一个带有重复值的 Json 字符串:

String json = "{\"Sign_In_Type\":\"Action\",\"Sign_In_Type\":\"Action\"}";

当我尝试创建 JSONObject 时正确抛出异常:

   尝试 {
            JSONObject json_obj = 新 JSONObject(json);
            字符串类型 = json_obj.getString("Sign_In_Type");
        } 捕捉(JSONException e){
            抛出新的 RuntimeException(e);
        }

错误:

线程“主”java.lang.RuntimeException 中的异常:org.json.JSONException:重复键“Sign_In_Type”
    在 com.campanja.app.Upload.main(Upload.java:52)
引起:org.json.JSONException:重复键“Sign_In_Type”
    在 org.json.JSONObject.putOnce(JSONObject.java:1076)
    在 org.json.JSONObject.(JSONObject.java:205)
    在 org.json.JSONObject.(JSONObject.java:402)
    在 com.campanja.app.Upload.main(Upload.java:49)

在将其转换为 JSONOBject 之前,是否有一种删除或检查重复项的智能方法?我试图创建:

Set set = new HashSet(Arrays.asList(json));

但这给了我:

[{"Sign_In_Type":"Action","Sign_In_Type":"Action"}]

欢迎任何建议,谢谢!

4

6 回答 6

3

我可以立即想到两个选项:

  • 使用 wither regex 或 tokens 解析字符串,将每个键值对添加到 hashmap,最后重新创建 JSON 文档并删除重复项。在这种情况下,虽然我只会删除完全相同的键值对。
  • 下载 的源代码org.json.JSONObject,并对代码稍作修改以自动删除重复项。不过这有点危险。另一种选择是创建一个简单验证和修改的修改版本。

扩展 JSONObject 工作示例

下面的代码允许您使用包含重复键的字符串创建 JSONOBbject。仅当您有两个具有相同键但值不同的键值时才会引发异常。这是因为我认为随机选择应该分配两者中的哪一个是一个问题(例如,后面的值?)。当然,这可以更改为您希望的工作(例如,保留多个键的最后一个值)。

修改类

import org.json.JSONException;
import org.json.JSONObject;


public class JSONObjectIgnoreDuplicates extends JSONObject {

     public JSONObjectIgnoreDuplicates(String json) {
        super(json);
    }

    public JSONObject putOnce(String key, Object value) throws JSONException {
            Object storedValue;
            if (key != null && value != null) {
                if ((storedValue = this.opt(key)) != null ) {
                    if(!storedValue.equals(value))                          //Only through Exception for different values with same key
                        throw new JSONException("Duplicate key \"" + key + "\"");
                    else
                        return this;
                }
                this.put(key, value);
            }
            return this;
        }
}

主要方法

String json = "{\"Sign_In_Type\":\"Action\",\"Sign_In_Type\":\"Action\"}";
           try {
                JSONObject json_obj = new JSONObjectIgnoreDuplicates(json);
                String type = json_obj.getString("Sign_In_Type");
            } catch (JSONException e) {
                throw new RuntimeException(e);
            }   
于 2013-09-25T09:38:33.510 回答
0

您可以使用 Jackson 库来解析 JSON。使用 org.json 的包执行与您相同的任务时,我会遇到问题,但我求助于杰克逊并解决了它:http ://wiki.fasterxml.com/JacksonHome

于 2014-12-04T11:56:02.687 回答
0

假设 String json = "{\"Sign_In_Type\":\"Action\",\"Sign_In_Type\":\"Action\"}"; 是测试的虚构,我可以问一下将数据创建为字符串是否是最好的选择?为什么不使用 HashMap 或其他一些结构,它们要么覆盖名称的后续重用,要么忽略它们,或者在添加它们时抛出错误?不要等到转换为 JSON 才能使您的数据有效。

于 2013-09-25T09:40:24.950 回答
0

使用Google Gson,您可以决定如何处理输入字符串中的重复项。您需要注册自己TypeAdapter负责对象的序列化/反序列化。它看起来像这样:

// this implementation converts the json string to a Map<String, String>,
// saving only the first duplicate key and dropping the rest
class NoDuplicatesAdapter extends TypeAdapter<HashMap<String, String>> {
    @Override
    public void write(JsonWriter out, HashMap<String, String> value) throws IOException {
        out.beginObject();
        for (Map.Entry<String, String> e: value.entrySet()) {
            out.name(e.getKey()).value(e.getValue());
        }
        out.endObject();
    }
    @Override
    public HashMap<String, String> read(JsonReader in) throws IOException {
        final HashMap<String, String> map = new HashMap<>();
        in.beginObject();
        while (in.hasNext()) {
            String name = in.nextName();
            // putting value to the map only if this key is not present;
            // here you can actually find duplicate keys and decide what to do with them
            map.putIfAbsent(name, in.nextString());
        }
        in.endObject();
        return map;
    }
}

然后你可以解析你的字符串:

String json = "{\"Sign_In_Type\":\"Action\",\"Sign_In_Type\":\"Action\"}";

Type mapType = new TypeToken<Map<String, String>>() {}.getType();

Map<String, String> map = new GsonBuilder()
        .registerTypeAdapter(mapType, new NoDuplicatesAdapter())
        .create()
        .fromJson(str, mapType);

该地图将仅包含第一个"Sign_In_Type".

于 2017-12-19T08:02:03.687 回答
0

抱歉,由于声誉<50,我无法评论 Menelaos Bakopoulos 的回应......愚蠢的系统

不幸的是,您的解决方案在这里不起作用:

SEVERE: ERROR converting JSON to XML org.json.JSONException: Duplicate key "id"
org.json.JSONObject.putOnce(JSONObject.java:1076)
org.json.JSONObject.<init>(JSONObject.java:205)
org.json.JSONTokener.nextValue(JSONTokener.java:344)
org.json.JSONArray.<init>(JSONArray.java:125)
org.json.JSONTokener.nextValue(JSONTokener.java:348)
org.json.JSONObject.<init>(JSONObject.java:205)
JSONUtilities.JSONObjectIgnoreDuplicates.<init>(JSONUtilities.java:38)

似乎调用super(json)inJSONObjectIgnoreDuplicates的构造函数将代码发送到内部的循环中JSONObject,而不是JSONObjectIgnoreDuplicates;{

我目前正在尝试 Asaf Bartov 的解决方案,但是没有调用 from JSONObjectIgnoreDuplicatesto JsonDupTokener,所以除了重载JSONObjectIgnoreDuplicates如下构造函数之外,我看不到它是如何工作的:

    public JSONObjectIgnoreDuplicates(String json) throws JSONException {
        this(new JSONDupTokener(json));
    }

编辑:我可以确认这个工作:))))

谢谢大家!!!!

于 2017-09-06T15:56:38.133 回答
0

我扩展了 Menelaos Bakopoulos 的答案,因此如果内部值也具有重复项,则不会产生问题。前一个解决方案仅在第一级有效。

public class JSONObjectIgnoreDuplicates extends JSONObject {

    public JSONObjectIgnoreDuplicates(JSONTokener x) throws JSONException {
        super(x);
    }

    @Override
    public JSONObject putOnce(String key, Object value) throws JSONException {
        Object storedValue;
        if (key != null && value != null) {
            if ((storedValue = this.opt(key)) != null) {
                if (!storedValue.toString().equals(value.toString())) //Only throw Exception for different values with same key
                    throw new JSONException("Duplicate key \"" + key + "\"");
                else
                    return this;
            }
            this.put(key, value);
        }
        return this;
    }
}

private class JsonDupTokener extends JSONTokener {

    public JsonDupTokener(String s) {
        super(s);
    }

    @Override
    public Object nextValue() throws JSONException {
        char c = this.nextClean();
        switch (c) {
            case '\"':
            case '\'':
                return this.nextString(c);
            case '[':
                this.back();
                return new JSONArray(this);
            case '{':
                this.back();
                return new JSONObjectIgnoreDuplicates(this);
            default:
                StringBuffer sb;
                for (sb = new StringBuffer(); c >= 32 && ",:]}/\\\"[{;=#".indexOf(c) < 0; c = this.next()) {
                    sb.append(c);
                }

                this.back();
                String string = sb.toString().trim();
                if ("".equals(string)) {
                    throw this.syntaxError("Missing value");
                } else {
                    return JSONObject.stringToValue(string);
                }
        }
    }
}
于 2017-02-20T14:55:47.087 回答