JSONObject解析json字符串实现

来源:互联网 发布:淘宝网手套 编辑:程序博客网 时间:2024/04/30 16:44
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<String, Object>();
}


    /**
     * 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<CategoryBean>();
}
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<CategoryBean>();
}
list.add(infoBean);
}
}
1 0
原创粉丝点击