我有一个JSON格式的字符串
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.android.support:design:26.1.0'
implementation 'com.google.android.gms:play-services-maps:11.6.2'
compile 'com.google.android.gms:play-services-auth:9.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}
当我尝试从此字符串
创建对象时String str = "{\"innerkey1\":\"innervalue1\",
\"innerkey2\":\"innervalue2\",\"innerkey1\":\"innervalue3\"}";
我收到错误
try {
JSONObject obj = new JSONObject(str);
} catch(Exception e) {
e.printStackTrace();
}
有没有办法可以通过忽略字符串中的最后一个键来创建JSONObject?
答案 0 :(得分:1)
这是JSON规范的问题。根据使用的规范,可以解释是否允许重复密钥。在this thread中,人们普遍认为定义是一个密钥在JSONObject中必须是唯一的。
因此,您不应尝试解析可能无效的JSON对象,而应使用有效的JSON对象。
但是我对解决方案提出了一个小建议:但是你将它付诸实践,你可以使用(多个出现的)密钥并将存储在那里的所有对象作为一个数组分配给这个(现在唯一的)密钥。因此,您合并了几个相同的键,并将链接的对象合并到一个数组中。这至少会使JSON对象有效:
{
"a" : "x",
"a" : "y"
}
// becomes
{
"a" : ["x", "y"]
}
答案 1 :(得分:0)
不幸的是没有。虽然它在技术上不符合JSON标准,但它并不容易使用/你很难找到一个可以解析它的库。
见这里:https://stackoverflow.com/a/21833017/8972283
如果可能,我建议您更新JSON的创建方式。
答案 2 :(得分:0)
这不是最简单的解决方案,但它允许您在输入字符串中复制并选择如何处理它们(重命名,删除等)。您应该使用Gson库并注册自己的TypeAdapter
负责对象的序列化/反序列化。它看起来像这样:
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;
}
}
这是最复杂的部分,现在我们只需要阅读JSON
字符串:
String str = "{\"innerkey1\":\"innervalue1\", \"innerkey2\":\"innervalue2\",\"innerkey1\":\"innervalue3\"}";
Type mapType = new TypeToken<Map<String, String>>() {}.getType();
Map<String, String> map = new GsonBuilder()
.registerTypeAdapter(mapType, new NoDuplicatesAdapter())
.create()
.fromJson(str, mapType);
map
仅包含第一个"innerkey1"
。
答案 3 :(得分:0)
我有一个JSON parser,它允许使用代码将重复键视为数组中的元素。请参阅&#34;文档构建器代码&#34;。
部分答案 4 :(得分:0)
您可以使用objectMapper跳过此错误
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"test\", \"name\":\"new test\"}";
Map<String, Object> map = new HashMap<String, Object>();
map = mapper.readValue(json, new TypeReference<Map<String, String>>(){});
现在您可以轻松地从地图转换为JSONObject
new JSONObject(map);
答案 5 :(得分:0)
以下代码允许您使用包含重复键的字符串创建JSONObject。仅当您具有两个键值相同但键值不同的键值时,才会引发异常。这是因为我认为随机选择这两者中的哪一个会是一个问题(例如,后面的值?)。当然,可以将其更改为您希望的方式(例如,保留多个键的最后一个值)。
您将需要一个JSONObjectIgnoreDuplicates类来扩展JSONObject:
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) {
//Only throw Exception for different values with same key
if (!storedValue.toString().equals(value.toString()))
throw new JSONException("Duplicate key \"" + key + "\"");
else
return this;
}
this.put(key, value);
}
return this;
}
}
要处理嵌套JSONObject中的重复键,您需要将JSONTokener扩展为JsonDupTokener。
public 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);
}
}
}
}
主要方法如下:
// string "json" with duplicate keys
String json = "{\"Sign_In_Type\": \"Action\", \"Sign_In_Type\": \"Action\"}";
try {
JSONObject json_obj = new JSONObjectIgnoreDuplicates(new JSONDupTokener(json));
String type = json_obj.getString("Sign_In_Type");
} catch (JSONException e) {
throw new RuntimeException(e);
}
希望这会有所帮助。如果您有任何疑问,请告诉我。祝你好运。