cjson源代码解读 (二)解析流程

先从test.c 开始说, 我们看到test.c 里面有两个函数用来测试, doit 和dofile,  一个是读char* 一个是读file, 肯定是读字符串的要简单, 所以先看doit.

/* Parse text to JSON, then render back to text, and print! */
void doit(char *text)
{
    char *out;cJSON *json;
    
    json=cJSON_Parse(text);
    if (!json) {printf("Error before: [%s]\n",cJSON_GetErrorPtr());}
    else
    {
        out=cJSON_Print(json);
        cJSON_Delete(json);
        printf("%s\n",out);
        free(out);
    }
}

先是申请了一个cJSON型的指针, 这个指针应该就是主要的存储结构了. 那这个指针是什么构成的呢?

typedef struct cJSON {
    struct cJSON *next,*prev;    /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
    struct cJSON *child;        /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */

    int type;                    /* The type of the item, as above. */

    char *valuestring;            /* The item‘s string, if type==cJSON_String */
    int valueint;                /* The item‘s number, if type==cJSON_Number */
    double valuedouble;            /* The item‘s number, if type==cJSON_Number */

    char *string;                /* The item‘s name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;

1) next和prev是两个指向自己下一个和前一个的指针,  如果next==0 表明是末尾, prev==0表明是开头. 

2) string是自己的值, 也就是 {"name":"v1"} 中的name

3) type是当前节点value的类型, 也就是json默认定义的几种.

4) 根据type的种类, 分别有对应的值 valuestring, valueint, valuedouble和 child. true和false还有null当然不需要定义, 因为他们本来值就是自己.

type定义在 <cJSON.h> 开头

/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6

 然后就是核心parse的过程了, 也就是函数 json=cJSON_Parse(text);  代码如下:

 

/* Default options for cJSON_Parse */
cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}

 

竟然就这么一行, 这不是糊弄我们吗, 那就接着看cJSON_PaarseWithOpts函数.

定义:

/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);

实现:

/* Parse an object - create a new root, and populate. */
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
{
    const char *end=0;
    cJSON *c=cJSON_New_Item();
    ep=0;
    if (!c) return 0;       /* memory fail */

    end=parse_value(c,skip(value));
    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 */
    if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
    if (return_parse_end) *return_parse_end=end;
    return c;
}

不管后面两个参数, 后面两个参数都是0. (应该在子函数里面有用)

先大致明确一下流程, 然后再看函数怎么实现的(有一些是错误输出, 暂不看):

1. cJSON *c = cJSON_New_Item(); 申请一个cJSON对象出来, 也就相当于new一个.

2. end=parse_value(c,skip(value));  我们注意, 看doit代码的时候只有一句parse, 也就是真正的parse在这个地方(脑补一下).

3. 剩下的都是错误处理.

那么怎么申请对象呢, 看cJSON_New_Item()函数.

/* Internal constructor. */
static cJSON *cJSON_New_Item(void)
{
    cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
    if (node) memset(node,0,sizeof(cJSON));
    return node;
}
static void *(*cJSON_malloc)(size_t sz) = malloc;

申请一个sizeof(cJSON)结构体大小的空间. 然后将内容初始化.

 

下面看解析函数

/* Utility to jump whitespace and cr/lf */
static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}

这个非常好理解,  去除最前面的空格等字符. 

 

/* Parser core - when encountering text, process appropriately. */
static const char *parse_value(cJSON *item,const char *value)
{
    if (!value)                        return 0;    /* Fail on null. */
    if (!strncmp(value,"null",4))    { item->type=cJSON_NULL;  return value+4; }
    if (!strncmp(value,"false",5))    { item->type=cJSON_False; return value+5; }
    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. */
}

1. 如果啥都没有, 直接返回了.

2. 然后是只有一个null或false或true的情况.

3. 然后是转义字符.

4. 然后是数字

5. 然后是数组或者字典.

看到这里也能想明白了, value就是指json的单个value, 所以这个函数应该不止会调用一次的. 接下来就是数字, 字符串, 数组, 字典的解析.

这个会在后面讲.

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。