java 使用带有路径的 Gson

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26087701/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 09:16:02  来源:igfitidea点击:

Using Gson with a path

javajsongsonjsonpath

提问by Eduardo

Using a simple Json file e.g:

使用一个简单的 Json 文件,例如:

{"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}}

I want to be able to get the JsonArraynamed menuitemusing a path:

我希望能够使用路径获取JsonArray命名menuitem

String path =  "menu.popup.menuitem"

I tried to do this using:

我尝试使用以下方法执行此操作:

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
}

with:

和:

JsonElement jsonElement = fromString(json, path);

But when I try isJsonArray()the return value is false. When doing the extra sanity check using Gson.toJson(jsonElement)the output is the full json String (above) that was inputted originally. What's going wrong?

但是当我尝试isJsonArray()返回值是false. 使用Gson.toJson(jsonElement)输出进行额外的完整性检查时,输出是最初输入的完整 json 字符串(上图)。怎么了?

采纳答案by Pshemo

splituses regex to find places on which string should be split, but .in regex is special character which represents "any character beside line separators", which means that you are actually splitting on each character. So for string like

split使用正则表达式查找应拆分字符串的位置,但.在正则表达式中是特殊字符,表示“行分隔符旁边的任何字符”,这意味着您实际上是在每个字符上拆分。所以对于像这样的字符串

"foo"

"foo".split(".")will split on f, o, o

"foo".split(".")将分裂于f, o,o

"foo"
 ^^^

which means you will get as result array with four empty strings (3 splits give 4 elements).

这意味着您将获得带有四个空字符串的结果数组(3 个拆分给出 4 个元素)。

["", "", "", ""]

Actually I lied here because split(regex)does one additional thing: it removes trailing empty strings from result array, but your array contains only empty strings, which means that they will all be removed, so split(".")will return just empty array []so your loop will not iterate even once (that is why your method returns unmodified obj).

实际上我在这里撒谎是因为split(regex)做了一件额外的事情:它从结果数组中删除了尾随的空字符串,但是你的数组只包含空字符串,这意味着它们都将被删除,所以split(".")只会返回空数组,[]这样你的循环就不会迭代一次(这就是您的方法返回未修改的原因obj)。

To get rid of this problem you will need to make .literal (you need to escape it). To do so you can use for instance split("\\.")or split("[.]")or split(Pattern.quote(".")which work same as split("\\Q.\\E")- it adds quotation area.

为了摆脱这个问题,你需要做.文字(你需要逃避它)。为此,您可以使用例如split("\\.")orsplit("[.]")split(Pattern.quote(".")which 与工作相同split("\\Q.\\E")- 它添加了引用区域。

Also inside loop you should first check type of Json you are handling, because getAsJsonObjectwill fail if Json is array. So your code should probably look like

同样在循环内部,您应该首先检查您正在处理的 Json 类型,因为getAsJsonObject如果 Json 是数组,则会失败。所以你的代码应该看起来像

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;
}

回答by isapir

I'm not sure why this is not built-into Gson, but here is a method that I wrote, which returns a JsonElementgiven a JsonElement input and a JSON Path:

我不确定为什么这不是内置在 Gson 中的,但这是我编写的一个方法,它返回一个JsonElement给定 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;
}

To call it, use something like:

要调用它,请使用以下内容:

String jsonString = ...;

Gson gson = new Gson();
JsonObject  jsonObject = gson.fromJson(jsonString, JsonObject.class);
JsonElement subElement = getJsonElement(jsonObject, "a.b.c[2].d";