[英]Remove duplicates from a Json String in Java?
I have a Json String with duplicate values: 我有一个重复值的Json字符串:
String json = "{\"Sign_In_Type\":\"Action\",\"Sign_In_Type\":\"Action\"}";
that correctly throws an exception when I try to create a JSONObject: 在我尝试创建JSONObject时正确抛出异常:
try { JSONObject json_obj = new JSONObject(json); String type = json_obj.getString("Sign_In_Type"); } catch (JSONException e) { throw new RuntimeException(e); }
Error: 错误:
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)
Is there a smart way of removing or checking for duplicates before I convert it to a JSONOBject? 在将其转换为JSONOBject之前,是否有一种智能方法可以删除或检查重复项? I have tried to create: 我试图创建:
Set set = new HashSet(Arrays.asList(json));
but that gives me: 但这给了我:
[{"Sign_In_Type":"Action","Sign_In_Type":"Action"}]
Any suggesstions welcome, thanks! 欢迎任何建议,谢谢!
Two options I can think of right off the bat: 我可以想到两个选项:
org.json.JSONObject
, and make a slight modification to the code to automatically leave out duplicates. 下载org.json.JSONObject
的源代码, org.json.JSONObject
代码稍作修改,以自动省去重复项。 This is a bit dangerous though. 这有点危险。 Another option is to create a modified version that simply validates and modifies. 另一种选择是创建一个简单验证和修改的修改版本。 The below code allows you to create a JSONOBbject with a string containing duplicate keys. 下面的代码允许您使用包含重复键的字符串创建JSONOBbject。 Exceptions are thrown only when you have two key-values that have the same key, but different values. 仅当您有两个具有相同键但值不同的键值时,才会抛出异常。 This was because I think it would be a problem to choose at random which of the two should be assigned (eg the later value?). 这是因为我认为随机选择应该分配哪两个(例如后面的值?)是个问题。 Of course this can be changed to work as you wish (eg keep last value for multiple keys). 当然,这可以根据需要更改为工作(例如,保留多个键的最后一个值)。
Modified Class 修改后的类
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;
}
}
Main method 主要方法
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);
}
Assuming that String json = "{\\"Sign_In_Type\\":\\"Action\\",\\"Sign_In_Type\\":\\"Action\\"}"; 假设String json =“{\\”Sign_In_Type \\“:\\”Action \\“,\\”Sign_In_Type \\“:\\”Action \\“}”; is a fiction for testing, can I ask whether creating the data as a String is the best choice in the first place? 是一个测试的小说,我可以问一下,创建数据作为字符串是否是最好的选择? Why not a HashMap, or some other structure that either overwrites the subsequent reuses of a name or ignores them or throws an error when you add them? 为什么不使用HashMap或其他一些结构来覆盖名称的后续重用或忽略它们或在添加它们时抛出错误? Don't wait until the conversion to JSON to make your data valid. 不要等到转换为JSON才能使数据有效。
You can make use of the Jackson library to parse JSON. 您可以使用Jackson库来解析JSON。 I'd problems doing the same task as you with org.json's package, but I turned to Jackson and I solved it: http://wiki.fasterxml.com/JacksonHome 我在使用org.json的软件包时遇到了同样的问题,但我转向杰克逊并解决了它: http ://wiki.fasterxml.com/JacksonHome
I expanded Menelaos Bakopoulos answer, so that if inner values are also with duplicates, it won't create issues. 我扩展了Menelaos Bakopoulos的答案,因此如果内部值也有重复,那么它不会产生问题。 the former solution worked on the first level only. 前一种解决方案仅适用于第一级。
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);
}
}
}
}
Sorry I can't comment on Menelaos Bakopoulos' response due to reputation<50... Stupid system 对不起,由于声誉<50 ...愚蠢的系统,我无法评论Menelaos Bakopoulos的回应
Your solution unfortunately does not work here: 遗憾的是,您的解决方案无效:
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)
It seems that calling super(json)
in JSONObjectIgnoreDuplicates
's constructor sends the code into a loop inside JSONObject
, not JSONObjectIgnoreDuplicates
;{ 似乎在JSONObjectIgnoreDuplicates
的构造函数中调用super(json)
会将代码发送到JSONObject
内部的循环中,而不是JSONObjectIgnoreDuplicates
; {
I'm currently trying Asaf Bartov's solution, but there's no call from JSONObjectIgnoreDuplicates
to JsonDupTokener
, so appart from overloading the constructor of JSONObjectIgnoreDuplicates
as follows, I don't see how it could work: 我目前正在尝试Asaf Bartov的解决方案,但是没有从JSONObjectIgnoreDuplicates
到JsonDupTokener
调用,所以JsonDupTokener
重载JSONObjectIgnoreDuplicates
的构造函数,如下所示,我看不出它是如何工作的:
public JSONObjectIgnoreDuplicates(String json) throws JSONException {
this(new JSONDupTokener(json));
}
EDIT: I can confirm this works :)))) 编辑:我可以确认这是有效的:))))
Thanks everybody!!!! 谢谢大家!!!!
With Google Gson you can decide what to do with duplicates in the input string. 使用Google Gson,您可以决定如何处理输入字符串中的重复项。 You need to register your own TypeAdapter
responsible for serialization/deserialization of objects. 您需要注册自己的TypeAdapter
负责对象的序列化/反序列化。 It would look like this: 它看起来像这样:
// 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;
}
}
Then you can parse your string: 然后你可以解析你的字符串:
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);
The map will contain only the first "Sign_In_Type"
. 地图将仅包含第一个"Sign_In_Type"
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.