【读码练习/JSON-java】(一)解析JSON的过程
什么是JSON
官网的解释是JSON (JavaScript Object Notation) is a lightweight data-interchange format 。
JSON的格式
键值对的集合 {k:v}
值得有序列表 [1,2]
什么是JSON-java
JSON官网提供的java语言处理json数据的小框架。
阅读该源码的目的
1、学习解析类工具的原理
2、锻炼读代码的能力
解析JSON的原理
1、JSON-java最重要的类有三个。
JSONObject : 包装一个map。 用来表示一个{k:v,k2:v2,k3:[1,2]}形式的json数据
JSONArray :包装一个ArrayList。用来表示一个[1,2,{k:v}]形式的json数据
JSONTokener:包装一个Reader。用来存储、读取、操作一个表示JSON数据的字符串
2、原理
1、JSONObject和JSONArray都可以用一个JSONTokener作为构造参数去实例化。
2、解析时可能会产生多个JSONObject或者JSONArray。但是他们都是操作同一个JSONTokener。
3、JSONObject和JSONArray可以分别通过JSONTokener提供的方法解析出对方。可以实现嵌套。
例子
new JSONObject("{k:v,k2:v2,k3:[1,{k4:V4}]}");
解析出{
解析出k和v存入map
解析出k2和v2存入map
解析出k3 然后发现一个数组的左标记[
new JSONArray 开始解析[1,{k4:V4}]}
解析出[
解析出1 放入list
解析出json对象的左标记{
new JSONObject 开始解析 {k4:V4}]}
解析出k4和v4放入map
发现}一个JSONObject解析结束
解析出 {k4:V4} 放入list。
发现 ] 一个JSONArray解析结束
解析出[1,{k4:V4}] 和k3 一起放入map (第一个JSONObject)。
解析出}
全部解析结束。
3、实现
JSONTokener 重要的Field(数据)和Method(操作)
private int character; // 当前行字符的index
private boolean eof; // 标记读到尾部
private int index; // 所有行字符的index
private int line; // 行数
private char previous; // 缓存
private Reader reader; // JSON数据
private boolean usePrevious; // 使用缓存标志
public char next() throws JSONException
从reader或者缓存(previous)里读取一个char,并且设置和统计重要的Field。
public void back() throws JSONException
将各种统计的field恢复到上一个的状态。并且把userPrevious设置成true(即下次使用next()时从缓存里拿一个char)
next和back使的JSONTokener有了一个向前探测一个字符的能力。
public char nextClean() throws JSONException
读取一个可见字符串或者一个结束符\0。(看了人家的代码才意识到空格之前的都是不可见字符)
public String nextString(String quote) throws JSONException
读一个封闭的引用符内的字符串。(这里会做一个转义处理)
如果碰到\ 作转义处理:转义处理:往后读一位
1、如果后面的是b t n f r 往buff里添加相应的转义字符
2、如果后面的是u 则next(4) 转成 16进制Int 转成char 添加到buff
3、如果后面的是u 则next(4) 转成 16进制Int 转成char 添加到buff
4、后面如果是‘ “ \ / 直接把该字符添加到buff
5、其他情况抛出Illegal escape.
public Object nextValue() throws JSONException
这个方法很重要! 读取下一个封闭引用符号括起来的值,或者各种基本的数据类型,或者一个JSONObject和JSONArray。(嵌套的关键)
public Object nextValue() throws JSONException {
char c = nextClean(); // 探测
String string;
switch (c) {
case '"':
case '\'':
return nextString(c);
case '{':
back(); // 探测到回退
return new JSONObject(this);
case '[':
back();
return new JSONArray(this);
}
StringBuffer sb = new StringBuffer();
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
sb.append(c);
c = next();
}
back();
string = sb.toString().trim();
if (string.equals("")) {
throw syntaxError("Missing value");
}
return JSONObject.stringToValue(string);
}
JSONArray的构造器(注意JSON-java支持非正规的JSON格式可以用多种符号分隔数据)
public JSONArray(JSONTokener x) throws JSONException {
this();
if (x.nextClean() != '[') {
throw x.syntaxError("A JSONArray text must start with '['");
}
if (x.nextClean() != ']') {
x.back();
for (;;) {
if (x.nextClean() == ',') {
x.back();
this.myArrayList.add(JSONObject.NULL);
} else {
x.back();
this.myArrayList.add(x.nextValue());
}
switch (x.nextClean()) {
case ';':
case ',':
if (x.nextClean() == ']') {
return;
}
x.back();
break;
case ']':
return;
default:
throw x.syntaxError("Expected a ',' or ']'");
}
}
}
}
JSONObject的构造器(注意JSON-java支持非正规的JSON格式可以用多种符分隔数据)
public JSONObject(JSONTokener x) throws JSONException {
this();
char c;
String key;
if (x.nextClean() != '{') {
throw x.syntaxError("A JSONObject text must begin with '{'");
}
for (;;) {
c = x.nextClean();
switch (c) {
case 0:
throw x.syntaxError("A JSONObject text must end with '}'");
case '}':
return;
default:
x.back();
key = x.nextValue().toString();
}
// The key is followed by ':'. We will also tolerate '=' or '=>'.
c = x.nextClean();
if (c == '=') {
if (x.next() != '>') {
x.back();
}
} else if (c != ':') {
throw x.syntaxError("Expected a ':' after a key");
}
putOnce(key, x.nextValue());
// Pairs are separated by ','. We will also tolerate ';'.
switch (x.nextClean()) {
case ';':
case ',':
if (x.nextClean() == '}') {
return;
}
x.back();
break;
case '}':
return;
default:
throw x.syntaxError("Expected a ',' or '}'");
}
}
}