牛骨文教育服务平台(让学习变的简单)
博文笔记

JSONObject解析json字符串实现

创建时间:2016-04-28 投稿人: 浏览次数:2803
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 " ":
                case " ":
                case " ":
                case " ":
                    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);
}
}
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。