google GSON打印json所有叶子节点的路径

1.背景

当我们有一串json字符串,有时候希望能得到json path。

例如JSON.l1.l1_2.l1_2_1 表示节点121的路径。通过GSON提供的功能我们可以快速获取路径。

{
    "l1": {
        "l1_1": [
            "l1_1_1",
            "l1_1_2"
        ],
        "l1_2": {
            "l1_2_1": 121
        }
    },
    "l2": {
        "l2_1": null,
        "l2_2": true,
        "l2_3": {}
    }
}

2. JsonReader

GSON提供的JsonReader是GSON中的流式解析器。通过使用JsonReader可以以符号流的形式读取json字符串。

流式解析器通常有两种模式:推模式和拉模式。拉模式下,代码通过解析器主动获取标识符。

推模式解析器解析JSON标识符,并将结果推送给事件处理器。GSON JsonReader 是一种拉模式解析器。

创建JsonReader:

String json = "{\"brand\" : \"Toyota\", \"doors\" : 5}";
JsonReader jsonReader = new JsonReader(new StringReader(json));

通过JsonReader遍历标识符,通过jsonReader.hasNext()判断流中是否还有标识符。

while(jsonReader.hasNext()) {
}

为了访问流中Json的各类符号,需要进行类型判断。JsonReader peek() 获取当前的符号,但不从流中移除该符号。多次调用peek方法返回结果一致。peek方法会返回JsonToken类型结果,因此可以判断json符号的类型。

String json = "{\"brand\" : \"Toyota\", \"doors\" : 5}";

JsonReader jsonReader = new JsonReader(new StringReader(json));

try {
    while(jsonReader.hasNext()){
        JsonToken nextToken = jsonReader.peek();
        System.out.println(nextToken);

        if(JsonToken.BEGIN_OBJECT.equals(nextToken)){

            jsonReader.beginObject();

        } else if(JsonToken.NAME.equals(nextToken)){

            String name  =  jsonReader.nextName();
            System.out.println(name);

        } else if(JsonToken.STRING.equals(nextToken)){

            String value =  jsonReader.nextString();
            System.out.println(value);

        } else if(JsonToken.NUMBER.equals(nextToken)){

            long value =  jsonReader.nextLong();
            System.out.println(value);

        }
    }
} catch (IOException e) {
    e.printStackTrace();
}

3.打印路径

由第3小节可以知道通过jsonReader可以得到符号的类型,因此当我们访问到了叶子节点,如单独的一个字符串型、布尔型及数值型时,通过reader.getPath()方法可以得到路径。而非这些终结点时,让解析器跳过并继续访问下一个结点即可。

import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;

import java.io.IOException;
import java.io.StringReader;
import java.util.regex.Pattern;

public class Main {

    static final String REGEX = "\\[[0-9]+\\]";
    static final Pattern PATTERN = Pattern.compile(REGEX);
    
    public static void main(String[] args) throws Exception{
        String json = "{\n" +
                "    \"l1\": {\n" +
                "        \"l1_1\": [\n" +
                "            \"l1_1_1\",\n" +
                "            \"l1_1_2\"\n" +
                "        ],\n" +
                "        \"l1_2\": {\n" +
                "            \"l1_2_1\": [\n" +
                "                {\n" +
                "                    \"a\": \"b\"\n" +
                "                },\n" +
                "                122\n" +
                "            ]\n" +
                "        }\n" +
                "    },\n" +
                "    \"l2\": {\n" +
                "        \"l2_1\": null,\n" +
                "        \"l2_2\": true,\n" +
                "        \"l2_3\": {}\n" +
                "    }\n" +
                "}";
        parseJson(json);
    }


    static void parseJson(String json) throws IOException {

        JsonReader reader = new JsonReader(new StringReader(json));
        reader.setLenient(true);
        while (true) {
            JsonToken token = reader.peek();
            switch (token) {
                case BEGIN_ARRAY:
                    reader.beginArray();
                    break;
                case END_ARRAY:
                    reader.endArray();
                    break;
                case BEGIN_OBJECT:
                    reader.beginObject();
                    break;
                case END_OBJECT:
                    reader.endObject();
                    break;
                case NAME:
                    reader.nextName();
                    break;
                case STRING:
                    String s = reader.nextString();
                    print(reader.getPath(), quote(s));
                    break;
                case NUMBER:
                    String n = reader.nextString();
                    print(reader.getPath(), n);
                    break;
                case BOOLEAN:
                    boolean b = reader.nextBoolean();
                    print(reader.getPath(), b);
                    break;
                case NULL:
                    reader.nextNull();
                    break;
                case END_DOCUMENT:
                    return;
            }
        }
    }

    static private void print(String path, Object value) {
        path = path.substring(2);
        path = PATTERN.matcher(path).replaceAll("");
        System.out.println(path + ": " + value);
    }

    static private String quote(String s) {
        return new StringBuilder()
                .append('"')
                .append(s)
                .append('"')
                .toString();
    }
}

4. 参考

[1].jsonreader,http://tutorials.jenkov.com/java-json/gson-jsonreader.html
[2].输出jsonpath,https://stackoverflow.com/questions/26183948/output-list-of-all-paths-to-leaf-nodes-in-a-json-document-in-java?noredirect=1&lq=1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值