从Java中的Json字符串中删除重复项?

时间:2013-09-25 09:33:49

标签: java json duplicate-removal

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

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

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


   try {
            JSONObject json_obj = new JSONObject(json);
            String type = json_obj.getString("Sign_In_Type");
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }

错误:

Exception in thread "main" java.lang.RuntimeException: org.json.JSONException: Duplicate key "Sign_In_Type"
    at com.campanja.app.Upload.main(Upload.java:52)
Caused by: org.json.JSONException: Duplicate key "Sign_In_Type"
    at org.json.JSONObject.putOnce(JSONObject.java:1076)
    at org.json.JSONObject.(JSONObject.java:205)
    at org.json.JSONObject.(JSONObject.java:402)
    at com.campanja.app.Upload.main(Upload.java:49)

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

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

但是这给了我:

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

欢迎任何建议,谢谢!

6 个答案:

答案 0 :(得分: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);
            }   

答案 1 :(得分:0)

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

答案 2 :(得分:0)

您可以使用Jackson库来解析JSON。我使用org.json的包完成了与你相同的任务,但我转向Jackson并解决了它:http://wiki.fasterxml.com/JacksonHome

答案 3 :(得分: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);
                }
        }
    }
}

答案 4 :(得分:0)

抱歉,我无法对Menelaos Bakopoulos&#39;发表评论。声誉响应&lt; 50 ...愚蠢的系统

遗憾的是,您的解决方案无效:

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)的构造函数中调用JSONObjectIgnoreDuplicates会将代码发送到JSONObject内的循环,而不是JSONObjectIgnoreDuplicates; {

我目前正在尝试使用Asaf Bartov的解决方案,但是JSONObjectIgnoreDuplicates没有给JsonDupTokener打电话,因此重载了JSONObjectIgnoreDuplicates的构造函数如下,我不知道它是如何工作的:

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

编辑:我可以确认这是有效的:))))

谢谢大家!!!!

答案 5 :(得分: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"