cjson原始碼解讀 (二)解析流程

來源:互聯網
上載者:User

標籤:

先從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, 所以這個函數應該不止會調用一次的. 接下來就是數字, 字串, 數組, 字典的解析.

這個會在後面講.

 

cjson原始碼解讀 (二)解析流程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.