cJSON代码阅读(4)——解析JSON数据的流程

时间:2022-12-07 20:19:45
解析JSON数据的主函数是cJSON_Parse,这个函数默认调用不带选项的cJSON_ParseWithOpts函数。

cJSON_ParseWithOpts函数首先创建一个JSON节点,然后跳过空白字符,接着调用parse_value函数进行数据的解析,然后判断解析是否出错,如果出错,那么释放内存,然后返回空指针,全局变量ep(char*类型)记录了出错的位置。如果没有出错,那么返回树形结构的JSON节点。

/* Parse an object - create a new root, and populate. */
// 带选项解析json数据
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
{
    // 是否到达末尾
    const char *end=0;

    // 创建一个新的json节点
    cJSON *c=cJSON_New_Item();

    // ep是一个全局的静态变量(这个参数的作用目前还不知道:好象是记录解析达到的最终位置)
    ep=0;

    // 分配内存失败,返回
    if (!c)
        return 0;       /* memory fail */

    // 开始解析
    // parse_value是进行解析的主要函数
    // 它里面会根据节点的不同类型调用不同的解析函数
    // 如果遇到数组或者对象,可能还会进行递归调用
    end=parse_value(c,skip(value));

    // end==0,出错,返回0
    if (!end)
    {
        // 删除节点(以及它的子节点)
        cJSON_Delete(c);
        return 0;
    }	/* parse failure. ep is set. */

    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
    // 判断是否需要以null结束
    if (require_null_terminated)
    {
        // 跳过空白字符
        end=skip(end);
        // 如果最后end还有字符,表示格式错误等,返回0
        if (*end)
        {
            cJSON_Delete(c);
            ep=end;
            return 0;
        }
    }

    // 判断是否需要返回解析的尾部
    if (return_parse_end)
        *return_parse_end=end;

    // 返回json节点
    return c;
}

skip函数的作用是跳过字符串中的控制字符(和空白字符)
/* Utility to jump whitespace and cr/lf */
// 跳过一切的空白字符
static const char *skip(const char *in)
{
    while (in && *in && (unsigned char)*in<=32)
        in++;

    return in;
}


parse_value函数事实上进行数据解析的函数,会根据不同字符串内容的不同,调用不同的解析函数(例如parse_object等函数,parse_object这些函数内部可能又会递归调用parse_value进行解析)进行具体的解析

/* Parser core - when encountering text, process appropriately. */
// 解析json格式的主要函数,解析值
static const char *parse_value(cJSON *item,const char *value)
{
    if (!value)
        return 0;	/* Fail on null. */

    // 如果这个值是null,表明是null节点
    if (!strncmp(value,"null",4))
    {
        item->type=cJSON_NULL;
        return value+4;
    }

    // 如果这个值是false,那么表示这是一个布尔节点
    if (!strncmp(value,"false",5))
    {
        item->type=cJSON_False;
        return value+5;
    }

    // 如果这个值是true,表示这个节点是布尔节点
    if (!strncmp(value,"true",4))
    {
        item->type=cJSON_True;
        item->valueint=1;
        return value+4;
    }

    // 如果是双引号开头,那么表示这个是一个字符串
    if (*value=='\"')
    {
        // 开始解析字符串
        return parse_string(item,value);
    }

    // 如果以负号开头或者以数字开头,那么表示这是一个数值
    if (*value=='-' || (*value>='0' && *value<='9'))
    {
        // 开始解析数值
        return parse_number(item,value);
    }

    // 如果以左中括号开头,那么表示是一个数组
    if (*value=='[')
    {
        // 开始解析数组
        return parse_array(item,value);
    }

    // 如果以左大括号开头,那么表示是一个对象
    if (*value=='{')
    {
        return parse_object(item,value);
    }

    // 记录解析的位置
    ep=value;

    // 到达这里表示解析出错
    return 0;	/* failure. */
}