JSONObject解析json字符串实现
1.题目:从最简单的使用开始
{
"name1": "休闲",
"name2": "棋牌",
"name3": "益智",
"url1": "image/category_game_0.jpg",
"url2": "image/category_game_1.jpg",
"url3": "image/category_game_2.jpg"
},
2.研究JSONObject的实现:既如何解析上述json字符串
// 获取title的节点数据
// Creates a new {@code JSONObject} with name/value mappings from the next object in the tokener.
JsonObject jsonObject = new JSONObject(jsonStr); // jsonStr是上述字符串
titleBean.title = jsonObject.getString("title");
// JSONObject实现如下:
// 复杂保存键值对
public JSONObject(String json) throws JSONException {
this(new JSONTokener(json));
}
// 负责具体解析
public JSONTokener(String in) {
// Token:代币;象征;记号
this.in = in;
}
public JSONObject(JSONTokener readFrom) throws JSONException {
/*
* Getting the parser to populate this could get tricky. Instead, just
* parse to temporary JSONObject and then steal the data from that.
*/
Object object = readFrom.nextValue();
if (object instanceof JSONObject) {
this.nameValuePairs = ((JSONObject) object).nameValuePairs;
} else {
throw JSON.typeMismatch(object, "JSONObject");
}
}
public JSONObject() {
// 使用键值对保存节点序列
nameValuePairs = new HashMap();
}
/**
* Returns the next value from the input.
*
* @return a {@link JSONObject}, {@link JSONArray}, String, Boolean,
* Integer, Long, Double or {@link JSONObject#NULL}.
* @throws JSONException if the input is malformed.
*/
public Object nextValue() throws JSONException {
int c = nextCleanInternal();
switch (c) {
case -1:
throw syntaxError("End of input");
case '{':
// 一开始就解析Object--解析的核心代码在这里
return readObject();
case '[':
return readArray();
case '"':
return nextString((char) c);
...
}
}
/* 读取一个字符 */
private int nextCleanInternal() throws JSONException {
while (pos < in.length()) {
int c = in.charAt(pos++);
// 此时pos从0变为1
switch (c) {
case '\t':
case ' ':
case '\n':
case '\r':
continue;
...
default:
return c;
}
}
return -1;
// 读到文件末尾
}
/**
* 核心代码:读取一个Object
* Reads a sequence of key/value pairs and the trailing closing brace '}' of
* an object. The opening brace '{' should have already been read.
*/
private JSONObject readObject() throws JSONException {
JSONObject result = new JSONObject();
// new出一个键值对
/* Peek to see if this is the empty object. */
int first = nextCleanInternal(); // pos由1变为2
if (first == '}') {
return result;
} else if (first != -1) {
// pos由2变为1
pos--;
}
while (true) {
// 走一次解析出一个键值对--->"name1": "休闲",
// 获得"name1"
Object name = nextValue();
// 获取name
获取""或''之间的数据
/*
* Expect the name/value separator to be either a colon ':', an
* equals sign '=', or an arrow "=>". The last two are bogus but we
* include them because that's what the original implementation did.
*/
int separator = nextCleanInternal();
if (separator != ':' && separator != '=') {
throw syntaxError("Expected ':' after " + name);
}
if (pos < in.length() && in.charAt(pos) == '>') {
// 跳过":"
pos++;
}
// 获得"休闲",并加入到键值对中
result.put((String) name, nextValue());
// 设置Map键值对
switch (nextCleanInternal()) {
// 跳过","
case '}':
return result;
case ';':
case ',':
continue;
default:
throw syntaxError("Unterminated object");
}
}
}
/*
获取""或''之间的数据
*/
public String nextString(char quote) throws JSONException {
/*
* For strings that are free of escape sequences, we can just extract
* the result as a substring of the input. But if we encounter an escape
* sequence, we need to use a StringBuilder to compose the result.
*/
StringBuilder builder = null;
/* the index of the first character not yet appended to the builder. */
int start = pos;
while (pos < in.length()) {
int c = in.charAt(pos++);
if (c == quote) {
// 走该分支--提取出两个:""之间的数据
if (builder == null) {
// a new string avoids leaking memory
return new String(in.substring(start, pos - 1));
} else {
builder.append(in, start, pos - 1);
return builder.toString();
}
}
...
}
}
总结:
1.解析实现主要由两个类实现:JSONObject和JSONTokener
其中:JSONObject复杂保存解析出来的键值对的map序列
JSONTokener负责底层具体解析工作(解析出对象,数组,简单键值对...)
--------------------------------------------------------------------------------------
3.复杂解析:(解析过程是递归进行的)
原始数据:
[{title:'游戏',infos:[{url1:'image/category_game_0.jpg',url2:'image/category_game_1.jpg',url3:'image/category_game_2.jpg',name1:'休闲',name2:'棋牌',name3:'益智'},{url1:'image/category_game_3.jpg',url2:'image/category_game_4.jpg',url3:'image/category_game_5.jpg',name1:'射击',name2:'体育',name3:'儿童'},{url1:'image/category_game_6.jpg',url2:'image/category_game_7.jpg',url3:'image/category_game_8.jpg',name1:'网游',name2:'角色',name3:'策略'},{url1:'image/category_game_9.jpg',url2:'image/category_game_10.jpg',url3:'',name1:'经营',name2:'竞速',name3:''}]},{title:'应用',infos:[{url1:'image/category_app_0.jpg',url2:'image/category_app_1.jpg',url3:'image/category_app_2.jpg',name1:'浏览器',name2:'输入法',name3:'健康'},{url1:'image/category_app_3.jpg',url2:'image/category_app_4.jpg',url3:'image/category_app_5.jpg',name1:'效率',name2:'教育',name3:'理财'},{url1:'image/category_app_6.jpg',url2:'image/category_app_7.jpg',url3:'image/category_app_8.jpg',name1:'阅读',name2:'个性化',name3:'购物'},{url1:'image/category_app_9.jpg',url2:'image/category_app_10.jpg',url3:'image/category_app_11.jpg',name1:'资讯',name2:'生活',name3:'工具'},{url1:'image/category_app_12.jpg',url2:'image/category_app_13.jpg',url3:'image/category_app_14.jpg',name1:'出行',name2:'通讯',name3:'拍照'},{url1:'image/category_app_15.jpg',url2:'image/category_app_16.jpg',url3:'image/category_app_17.jpg',name1:'社交',name2:'影音',name3:'安全'}]}]
解析过程:
// 获取根节点的对象
JSONArray array = new JSONArray(json);
// 遍历节点
for (int i = 0; i < array.length(); i++)
{
JSONObject jsonObject = array.getJSONObject(i);
CategoryBean titleBean = new CategoryBean();
titleBean.isTitle = true;
// 获取title的节点数据
titleBean.title = jsonObject.getString("title");
// 将 bean添加到集合
if (list == null)
{
list = new ArrayList();
}
list.add(titleBean);
// 获取infos节点
JSONArray infosArray = jsonObject.getJSONArray("infos");
// 遍历infosArray集合
for (int j = 0; j < infosArray.length(); j++)
{
JSONObject infoObject = infosArray.getJSONObject(j);
CategoryBean infoBean = new CategoryBean();
infoBean.isTitle = false;
infoBean.name1 = infoObject.getString("name1");
infoBean.name2 = infoObject.getString("name2");
infoBean.name3 = infoObject.getString("name3");
infoBean.url1 = infoObject.getString("url1");
infoBean.url2 = infoObject.getString("url2");
infoBean.url3 = infoObject.getString("url3");
if (list == null)
{
list = new ArrayList();
}
list.add(infoBean);
}
}