使用cJSON解析JSON字符串

JSON學習-使用cJSON解析

  

使用cJSON解析JSON字符串

 

一、爲何選擇cJSON 

         我們在使用JSON格式時,如果只是處理簡單的協議,可以依據JSON格式,通過對字符串的操作來進行解析與創建。然而隨着協議逐漸複雜起來,經常會遇到一些未考慮周全的地方,需要進一步的完善解析方法,此時,使用比較完善的JSON解析庫的需求就提出來了。

         基於方便引用的考慮,我們希望這個JSON解析庫是用C語言實現的。同時,爲了避免太過複雜的C源碼包含關係,希望最好是一個C文件來實現。通過在網絡上的查找,發現cJSON是比較符合要求的。cJSON只有一個C文件,一個頭文件,包含到項目源碼中非常方便,而且其實現效率也是非常高的。

 

二、cJSON的核心結構體

         cJSON的核心結構體就是一個cJSON,理解了這個結構體,基本上對cJSON的使用就有了個基本概念了。該結構體具體定義如下:

typedef struct cJSON {

       struct cJSON*next,*prev;           /* 遍歷數組或對象鏈的前向或後向鏈表指針*/

       struct cJSON *child;                   /*數組或對象的孩子節點*/

       int type;                                     /* key的類型*/

       char *valuestring;                       /*字符串值*/

       int valueint;                                /* 整數值*/

       double valuedouble;                    /* 浮點數值*/

       char *string;                               /* key的名字*/

} cJSON;

說明:

1、cJSON是使用鏈表來存儲數據的,其訪問方式很像一顆樹。每一個節點可以有兄弟節點,通過next/prev指針來查找,它類似雙向鏈表;每個節點也可以有孩子節點,通過child指針來訪問,進入下一層。只有節點是對象或數組時纔可以有孩子節點。

2、type是鍵(key)的類型,一共有7種取值,分別是:False,Ture,NULL,Number,String,Array,Object。

若是Number類型,則valueint或valuedouble中存儲着值。若期望的是int,則訪問valueint,若期望的是double,則訪問valuedouble,可以得到值。

若是String類型的,則valuestring中存儲着值,可以訪問valuestring得到值。

3、string中存放的是這個節點的名字,可理解爲key的名稱。

 

三、解析JSON格式;

         還是在Linux下,使用c語言編程,先實現讀文件的功能,然後開始JSON字符串的解析。我們還是一步步來,先從簡單的開始,萬丈高樓起於平地嘛。  

1,下載源碼;

可以從如下網站來下載:https://sourceforge.net/projects/cjson/ 。

2,包含cJSON的源碼;

         下載下來,解壓後,從裏面找到兩個文件(cJSON.c、cJSON.h),複製到我們的工程裏面。只需在函數中包含頭文件(#include “cJSON.h”),然後和cJSON.c一起編譯即可使用。 

3,解析一個鍵值對;  

         首先是一個簡單的鍵值對字符串,要解析的目標如下:

{"firstName":"Brett"}

要進行解析,也就是要分別獲取到鍵與值的內容。我們很容易就能看出鍵爲firstName,值爲Brett,可是,使用cJSON怎麼解析呢? 

         對於這個簡單的例子,只需要調用cJSON的三個接口函數就可以實現解析了,這三個函數的原型如下:

cJSON*cJSON_Parse(const char *value);

cJSON*cJSON_GetObjectItem(cJSON *object,const char *string);

voidcJSON_Delete(cJSON *c); 

下面按解析過程來描述一次:

(1)       首先調用cJSON_Parse()函數,解析JSON數據包,並按照cJSON結構體的結構序列化整個數據包。使用該函數會通過malloc()函數在內存中開闢一個空間,使用完成需要手動釋放。

cJSON*root=cJSON_Parse(json_string); 

(2)       調用cJSON_GetObjectItem()函數,可從cJSON結構體中查找某個子節點名稱(鍵名稱),如果查找成功可把該子節點序列化到cJSON結構體中。

cJSON*item=cJSON_GetObjectItem(root,"firstName"); 

(3)       如果需要使用cJSON結構體中的內容,可通過cJSON結構體中的valueint和valuestring取出有價值的內容(即鍵的值)

本例子中,我們直接訪問 item->valuestring 就獲取到 "Brett" 的內容了。

(4)       通過cJSON_Delete(),釋放cJSON_Parse()分配出來的內存空間。

cJSON_Delete(root);

         這樣就完成了一次cJSON接口調用,實現瞭解析工作。使用起來其實也很簡單的啊,呵呵。

4,解析一個結構體;        

         接下來,我們來個複雜一點的,解析一個結構體,要解析的目標如下:

{

         "person":

         {

                   "firstName":"z",

                   "lastName":"jadena",

                   "email":"[email protected]",

                   "age":8,

                   "height":1.17

         }       

}

看起來比一個鍵值對複雜多了,我們又需要學習新的接口函數了嗎?

         答案是不需要!

         還是那三個函數就可以了。當然,解析的步驟要複雜一些了,下面我按解析過程來描述一次: 

(1)根據JSON串中的對象,我們定義一個相應的結構體如下:

typedefstruct

{

         char firstName[32];

         char lastName[32];

         char email[64];

         int age;

         float height;

} PERSON;

具體的對應關係,一目瞭然,我就不羅嗦了。讓我們直奔主題,解析!     

(2)還是調用cJSON_Parse()函數,解析JSON數據包。

cJSON*root=cJSON_Parse(json_string); 

(3)調用一次cJSON_GetObjectItem()函數,獲取到對象person。

cJSON *object=cJSON_GetObjectItem(root,"person"); 

(4)對我們剛取出來的對象person,多次調用cJSON_GetObjectItem()函數,來獲取對象的成員。此時要注意,不同的成員,訪問的方法不一樣:

cJSON*item;

PERSONperson;

item=cJSON_GetObjectItem(object,"firstName");

memcpy(person.firstName,item->valuestring,strlen(item->valuestring));

item=cJSON_GetObjectItem(object,"lastName");

memcpy(person.lastName,item->valuestring,strlen(item->valuestring));

item=cJSON_GetObjectItem(object,"email");

memcpy(person.email,item->valuestring,strlen(item->valuestring));

item=cJSON_GetObjectItem(object,"age");

person.age=item->valueint;

item=cJSON_GetObjectItem(object,"height");

person.height=item->valuedouble;

這樣,就獲取到了對象的全部內容了。

(5)       通過cJSON_Delete(),釋放cJSON_Parse()分配出來的內存空間。

cJSON_Delete(root);

         至此,我們就使用cJSON接口完成了基於結構體的解析工作。 

5,解析結構體數組的JSON串;          

         最後,我們來個更復雜一些的,來解析一個數組,並且數組的成員是結構體!要解析的JSON串如下:

{

"people":[

{"firstName":"z","lastName":"Jason","email":"[email protected]","height":1.67},

{"lastName":"jadena","email":"[email protected]","age":8,"height":1.17},

{"email":"[email protected]","firstName":"z","lastName":"Juliet","age":36,"height":1.55}

]

         此時,我們真的又需要學習新的接口了,一個是獲取數組長度,一個是取數組成員,函數原型如下:

int    cJSON_GetArraySize(cJSON *array);

cJSON*cJSON_GetArrayItem(cJSON *array,int item); 

         由於前面已經實現了結構體的解析,這裏我們只需要關注下數組的相關調用即可。 

(1)調用cJSON_Parse()函數,解析JSON數據包。

(2)調用一次cJSON_GetObjectItem()函數,獲取到數組people。

(3)對我們剛取出來的數組people,調用cJSON_GetArraySize()函數,來獲取數組中對象的個數。然後,多次調用cJSON_GetArrayItem()函數,逐個讀取數組中對象的內容。

(4)通過cJSON_Delete(),釋放cJSON_Parse()分配出來的內存空間。

         這樣,我們就使用cJSON接口完成了結構體數組的解析工作。

詳細代碼見後文附帶例程。        

說明:

本文所附帶例程,實現了結構體數組的解析,只是一個學習之作,對於初學JSON使用cJSON接口的同學,可以有些借鑑參考的作用。 

附帶例程: 

[cpp] view plain copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <sys/types.h>  
  4. #include <stdlib.h>  
  5. #include <unistd.h>  
  6.   
  7. #include "cJSON.h"  
  8.   
  9. typedef struct  
  10. {  
  11.     int id;  
  12.     char firstName[32];  
  13.     char lastName[32];  
  14.     char email[64];  
  15.     int age;  
  16.     float height;  
  17. }people;  
  18.   
  19. void dofile(char *filename);/* Read a file, parse, render back, etc. */  
  20.   
  21. int main(int argc, char **argv)  
  22. {  
  23.   
  24. //  dofile("json_str1.txt");  
  25. //  dofile("json_str2.txt");  
  26.     dofile("json_str3.txt");  
  27.   
  28.     return 0;  
  29. }  
  30.   
  31. //parse a key-value pair  
  32. int cJSON_to_str(char *json_string, char *str_val)  
  33. {  
  34.     cJSON *root=cJSON_Parse(json_string);  
  35.     if (!root)  
  36.     {  
  37.         printf("Error before: [%s]\n",cJSON_GetErrorPtr());  
  38.         return -1;  
  39.     }  
  40.     else  
  41.     {  
  42.         cJSON *item=cJSON_GetObjectItem(root,"firstName");  
  43.         if(item!=NULL)  
  44.         {  
  45.             printf("cJSON_GetObjectItem: type=%d, key is %s, value is %s\n",item->type,item->string,item->valuestring);  
  46.             memcpy(str_val,item->valuestring,strlen(item->valuestring));  
  47.         }  
  48.         cJSON_Delete(root);  
  49.     }  
  50.     return 0;  
  51. }  
  52.   
  53. //parse a object to struct  
  54. int cJSON_to_struct(char *json_string, people *person)  
  55. {  
  56.     cJSON *item;  
  57.     cJSON *root=cJSON_Parse(json_string);  
  58.     if (!root)  
  59.     {  
  60.         printf("Error before: [%s]\n",cJSON_GetErrorPtr());  
  61.         return -1;  
  62.     }  
  63.     else  
  64.     {  
  65.         cJSON *object=cJSON_GetObjectItem(root,"person");  
  66.         if(object==NULL)  
  67.         {  
  68.             printf("Error before: [%s]\n",cJSON_GetErrorPtr());  
  69.             cJSON_Delete(root);  
  70.             return -1;  
  71.         }  
  72.         printf("cJSON_GetObjectItem: type=%d, key is %s, value is %s\n",object->type,object->string,object->valuestring);  
  73.   
  74.         if(object!=NULL)  
  75.         {  
  76.             item=cJSON_GetObjectItem(object,"firstName");  
  77.             if(item!=NULL)  
  78.             {  
  79.                 printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);  
  80.                 memcpy(person->firstName,item->valuestring,strlen(item->valuestring));  
  81.             }  
  82.   
  83.             item=cJSON_GetObjectItem(object,"lastName");  
  84.             if(item!=NULL)  
  85.             {  
  86.                 printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);  
  87.                 memcpy(person->lastName,item->valuestring,strlen(item->valuestring));  
  88.             }  
  89.   
  90.             item=cJSON_GetObjectItem(object,"email");  
  91.             if(item!=NULL)  
  92.             {  
  93.                 printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);  
  94.                 memcpy(person->email,item->valuestring,strlen(item->valuestring));  
  95.             }  
  96.   
  97.             item=cJSON_GetObjectItem(object,"age");  
  98.             if(item!=NULL)  
  99.             {  
  100.                 printf("cJSON_GetObjectItem: type=%d, string is %s, valueint=%d\n",item->type,item->string,item->valueint);  
  101.                 person->age=item->valueint;  
  102.             }  
  103.             else  
  104.             {  
  105.                 printf("cJSON_GetObjectItem: get age failed\n");  
  106.             }  
  107.   
  108.             item=cJSON_GetObjectItem(object,"height");  
  109.             if(item!=NULL)  
  110.             {  
  111.                 printf("cJSON_GetObjectItem: type=%d, string is %s, valuedouble=%f\n",item->type,item->string,item->valuedouble);  
  112.                 person->height=item->valuedouble;  
  113.             }  
  114.         }  
  115.   
  116.         cJSON_Delete(root);  
  117.     }  
  118.     return 0;  
  119. }  
  120.   
  121. //parse a struct array  
  122. int cJSON_to_struct_array(char *text, people worker[])  
  123. {  
  124.     cJSON *json,*arrayItem,*item,*object;  
  125.     int i;  
  126.   
  127.     json=cJSON_Parse(text);  
  128.     if (!json)  
  129.     {  
  130.         printf("Error before: [%s]\n",cJSON_GetErrorPtr());  
  131.     }  
  132.     else  
  133.     {  
  134.         arrayItem=cJSON_GetObjectItem(json,"people");  
  135.         if(arrayItem!=NULL)  
  136.         {  
  137.             int size=cJSON_GetArraySize(arrayItem);  
  138.             printf("cJSON_GetArraySize: size=%d\n",size);  
  139.   
  140.             for(i=0;i<size;i++)  
  141.             {  
  142.                 printf("i=%d\n",i);  
  143.                 object=cJSON_GetArrayItem(arrayItem,i);  
  144.   
  145.                 item=cJSON_GetObjectItem(object,"firstName");  
  146.                 if(item!=NULL)  
  147.                 {  
  148.                     printf("cJSON_GetObjectItem: type=%d, string is %s\n",item->type,item->string);  
  149.                     memcpy(worker[i].firstName,item->valuestring,strlen(item->valuestring));  
  150.                 }  
  151.   
  152.                 item=cJSON_GetObjectItem(object,"lastName");  
  153.                 if(item!=NULL)  
  154.                 {  
  155.                     printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);  
  156.                     memcpy(worker[i].lastName,item->valuestring,strlen(item->valuestring));  
  157.                 }  
  158.   
  159.                 item=cJSON_GetObjectItem(object,"email");  
  160.                 if(item!=NULL)  
  161.                 {  
  162.                     printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);  
  163.                     memcpy(worker[i].email,item->valuestring,strlen(item->valuestring));  
  164.                 }  
  165.   
  166.                 item=cJSON_GetObjectItem(object,"age");  
  167.                 if(item!=NULL)  
  168.                 {  
  169.                     printf("cJSON_GetObjectItem: type=%d, string is %s, valueint=%d\n",item->type,item->string,item->valueint);  
  170.                     worker[i].age=item->valueint;  
  171.                 }  
  172.                 else  
  173.                 {  
  174.                     printf("cJSON_GetObjectItem: get age failed\n");  
  175.                 }  
  176.   
  177.                 item=cJSON_GetObjectItem(object,"height");  
  178.                 if(item!=NULL)  
  179.                 {  
  180.                     printf("cJSON_GetObjectItem: type=%d, string is %s, value=%f\n",item->type,item->string,item->valuedouble);  
  181.                     worker[i].height=item->valuedouble;  
  182.                 }  
  183.             }  
  184.         }  
  185.   
  186.         for(i=0;i<3;i++)  
  187.         {  
  188.             printf("i=%d, firstName=%s,lastName=%s,email=%s,age=%d,height=%f\n",  
  189.                     i,  
  190.                     worker[i].firstName,  
  191.                     worker[i].lastName,  
  192.                     worker[i].email,  
  193.                     worker[i].age,  
  194.                     worker[i].height);  
  195.         }  
  196.   
  197.         cJSON_Delete(json);  
  198.     }  
  199.     return 0;  
  200. }  
  201.   
  202. // Read a file, parse, render back, etc.  
  203. void dofile(char *filename)  
  204. {  
  205.     FILE *f;  
  206.     int len;  
  207.     char *data;  
  208.       
  209.     f=fopen(filename,"rb");  
  210.     fseek(f,0,SEEK_END);  
  211.     len=ftell(f);  
  212.     fseek(f,0,SEEK_SET);  
  213.     data=(char*)malloc(len+1);  
  214.     fread(data,1,len,f);  
  215.     fclose(f);  
  216.       
  217.     printf("read file %s complete, len=%d.\n",filename,len);  
  218.   
  219. //  char str_name[40];  
  220. //  int ret = cJSON_to_str(data, str_name);  
  221.   
  222. //  people person;  
  223. //  int ret = cJSON_to_struct(data, &person);  
  224.   
  225.     people worker[3]={{0}};  
  226.     cJSON_to_struct_array(data, worker);  
  227.   
  228.     free(data);  
  229. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章