Java 使用带有路径的Gson
使用简单的Json文件,例如:Java 使用带有路径的Gson,java,json,gson,jsonpath,Java,Json,Gson,Jsonpath,使用简单的Json文件,例如: {"menu": { "id": "file", "value": "File", "popup": { "menuitem": [ {"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"} ]
{"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}}
我希望能够使用以下路径获取名为menuitem
的JsonArray
:
String path = "menu.popup.menuitem"
我尝试使用以下方法进行此操作:
public static JsonElement fromString(String json, String path) throws JsonSyntaxException {
JsonObject obj = GsonBuilder.create().fromJson(json, JsonObject.class);
String[] seg = path.split(".");
for (String element : seg) {
if (obj != null) {
obj = obj.get(element).getAsJsonObject();
} else {
return null;
}
}
return obj
}
与:
但是当我尝试isJsonArray()
时,返回值是false
。当使用Gson.toJson(jsonElement)
执行额外的健全性检查时,输出是最初输入的完整json字符串(如上)。
出什么问题了?
split
使用正则表达式查找应该拆分字符串的位置,但正则表达式中的
是一个特殊字符,表示“行分隔符旁边的任何字符”,这意味着您实际上在拆分每个字符。所以对于弦状的
"foo"
“foo”。拆分(“.”
将在f
,o
,o
"foo"
^^^
这意味着您将得到带有四个空字符串的结果数组(3次拆分得到4个元素)
实际上,我在这里撒谎是因为split(regex)
做了一件额外的事情:它从结果数组中删除尾随的空字符串,但数组只包含空字符串,这意味着它们都将被删除,因此split(“.”
将只返回空数组[]
,这样循环就不会迭代一次(这就是为什么您的方法返回未修改的obj
)
要解决此问题,您需要将
转换为文字(您需要对其进行转义)。为此,您可以使用例如split(\\”)
或split([.]”)
或split(Pattern.quote(“.”
,其工作原理与split(\\Q.\\E”)
相同-它添加了引号区域
同样,在循环内部,您应该首先检查正在处理的Json类型,因为如果Json是数组,则getAsJsonObject
将失败
public static JsonElement fromString(String json, String path)
throws JsonSyntaxException {
JsonObject obj = new GsonBuilder().create().fromJson(json, JsonObject.class);
String[] seg = path.split("\\.");
for (String element : seg) {
if (obj != null) {
JsonElement ele = obj.get(element);
if (!ele.isJsonObject())
return ele;
else
obj = ele.getAsJsonObject();
} else {
return null;
}
}
return obj;
}
我不确定为什么这没有内置到Gson中,但我编写了一个方法,它返回给定的JsonElement输入和JSON路径:
/**
* Returns a JSON sub-element from the given JsonElement and the given path
*
* @param json - a Gson JsonElement
* @param path - a JSON path, e.g. a.b.c[2].d
* @return - a sub-element of json according to the given path
*/
public static JsonElement getJsonElement(JsonElement json, String path){
String[] parts = path.split("\\.|\\[|\\]");
JsonElement result = json;
for (String key : parts) {
key = key.trim();
if (key.isEmpty())
continue;
if (result == null){
result = JsonNull.INSTANCE;
break;
}
if (result.isJsonObject()){
result = ((JsonObject)result).get(key);
}
else if (result.isJsonArray()){
int ix = Integer.valueOf(key) - 1;
result = ((JsonArray)result).get(ix);
}
else break;
}
return result;
}
要调用它,请使用以下内容:
String jsonString = ...;
Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(jsonString, JsonObject.class);
JsonElement subElement = getJsonElement(jsonObject, "a.b.c[2].d";
可能重复使用,例如,
;
而不是
。或者,path.split([.]])也可以用作[]中包含的文字character@prash是的,答案中已经提到了这一点,还有其他几种方式:)哇,太详细了!抱歉,我注意到我刚刚检查了代码部分..ty指出:-)它没有烘焙到Gson中,因为有一种单独的、更正式的方式来完成它,称为JSON路径。下面是一个流行的实现,下面是对它的介绍
/**
* Returns a JSON sub-element from the given JsonElement and the given path
*
* @param json - a Gson JsonElement
* @param path - a JSON path, e.g. a.b.c[2].d
* @return - a sub-element of json according to the given path
*/
public static JsonElement getJsonElement(JsonElement json, String path){
String[] parts = path.split("\\.|\\[|\\]");
JsonElement result = json;
for (String key : parts) {
key = key.trim();
if (key.isEmpty())
continue;
if (result == null){
result = JsonNull.INSTANCE;
break;
}
if (result.isJsonObject()){
result = ((JsonObject)result).get(key);
}
else if (result.isJsonArray()){
int ix = Integer.valueOf(key) - 1;
result = ((JsonArray)result).get(ix);
}
else break;
}
return result;
}
String jsonString = ...;
Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(jsonString, JsonObject.class);
JsonElement subElement = getJsonElement(jsonObject, "a.b.c[2].d";