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