日期:2014-05-16  浏览次数:20466 次

解析Json文本——如何将Json文本转化为Java对象

????? Json是一种简单小巧的数据交换格式,在Web开发中获得了广泛应用。网络上有很多Json库,光用Java编写的就不下二十个之多。无论哪一个Json库都必须具有一个基本功能,就是把Json文本转换为用本语言表示的数据结构,本文就是介绍如何把Json文本一字符一字符的解析成Java对象。

????? 如果要问解析Json需要哪些基础知识的话,计算机科班出身的读者立马就能想到大学时学过的编译原理这门课程。解析Json就是需要利用编译原理的知识,不过Json非常简单,解析它不必使用所有的编译技术,只要了解词法分析就可以了。不了解词法分析也不要紧,Json非常简单,不用词法分析也能解析。本文根据bantouyan-json库中解析Json文本的方法编写,不需要词法分析的基础。

?

????? 在介绍怎样解析Json文本之前,我们先回顾一下Json的定义。如果要了解Json的详细定义可以查看RFC4627文档,或者www.json.org网站。本文只作简要的介绍。


Json对象


Json数组

?

Json Value的定义

?

Json String

?

Json Number

????? 上面的五幅图像分别定义了Json的对象、数组、Value、字符串与数字。Json文本由一个Json对象或Json数组构成,无论是Json对象或者Json数组,还是Json字符串或数字,都是一个Json Value。

????? Json文本由构成Json的必要字符和额外的空白字符构成,解析它就要忽略额外的空白字符并将剩余部分转换为Java对象。本文按照bantouyan-json库提供的方法解析Json文本,介绍时做了一些适当的简化。

?

????? bantouyan-json库的解析功能由内部类JsonTextParser提供,JsonTextParser类的定义如下:

class JsonTextParser
{
    private Reader reader;
    private int ch = -1;

    public JsonTextParser(String text)throws IOException
    {
        StringReader strReader = new StringReader(text); 
        this.reader = strReader;
        next();
    }

    private void next() throws IOException
    {
        ch = reader.read();
    }
}

JsonTextParser类的核心成员有reader和ch,reader存储要解析的字符串,ch表示当前被扫描的字符,方法next()每执行一次扫描一个字符,当ch的值是-1时表明字符串扫描结束。

????? 在详细介绍解析算法之前,先介绍JsonTextParser类的几个关键方法,

boolean isBlankCharacter(int ch),判断字符ch是不是空白字符;void parseTailBlank(int endChar)?与void parseTailBlank(int endChar1, int endChar2),扫描并Json文本,在遇到终止字符endChar之前如果已经扫描完Json文本则抛出异常,扫描到第一个终止字符时退出该方法。

?

????? Json文本的解析从方法parse()开始(一个JsonTextParser对象方法parse只能被执行一次,这样设计也许并不合理,但它是内部类,不影响使用),其代码如下:

public Json parse() throws IOException, JsonException
{
    Json json = null;

    while(ch != -1)
    {
        if(ch == '{')
        {
            json = parseObject();
            parseTailBlank(-1);
        }
        else if(ch == '[')
        {
            json = parseArray();
            parseTailBlank(-1);
        }
        else if(! isBlankCharacter(ch))
        {
            // throw exception
        }
                
        next();
    }

    return json;
}

parseTailBlank(-1)表示扫描完整个字符串前不允许出现非空白字符。Json文本只允许表示一个对象或数组,所以在字符“[”、“{”之前不允许出现非空白字符,扫描完第一个对象或数组(正常情况下只有一个)后也不允许再出现非空白字符。

?

????? 方法parseJsonObject负责扫描并解析一个Json对象,调用该方法时正好扫描到Json对象的开始字符'{',得到Json对象后,扫描到对象的结束字符'}'的下一个字符时退出,parseJsonObject的代码如下:

private JsonObject parseObject() throws IOException, JsonException
{
    JsonObject json = new JsonObject();
    boolean needNextElement = false;
        
    next(); //skip character '{'
        
    while(ch != -1)
    {
        //还没有遇到JsonObject的子元素,扫描到'}'可直接结束
     if(needNextElement == false && ch == '}') break;
    
        if(isBlankCharacter(ch))
        {
            next(); //skip blank character
        }
        else
        {