cJSON

cJSON是很好用的json處理工具,github地址:https://github.com/kbranigan/cJSON.git  ,如下是轉載的一篇文章:http://www.cnblogs.com/chineseboy/p/3959852.htmlhtml

cJSON 使用筆記

 

                                                                                                        緣      起                                                                                                     java

      最近在stm32f103上作一個智能家居的項目,其中選擇的實時操做系統是 rt_thread OS v1.2.2穩定版本,其中涉及到C和java(android)端數據的交換問題,通過討論和研究,選擇了json格式的數據進行交互。固然,若是本身去寫一個json解析器,有點重造輪子的嫌疑。因而使用了開源的json解析器。考慮到是嵌入式平臺,在一位朋友的推薦下,選擇了輕量級別的cJSON。linux

                                                                                                        使      用                                                                                                     android

       cJSON 開源項目位置:  http://sourceforge.net/projects/cjson/git

       cJSON,目前來講,就只有兩個文件,一個cJSON.c 一個cJSON.h文件。使用的時候,本身建立好一個main.c文件後,若是是在linux pc上,請使用如下命令進行編譯:github

 

1 gcc -g -Wall *.c -l m

就會默認生成一個 a.out文件,執行便可。在linux下編譯的時候,注意連接 libm 庫。json

       整個項目都是以極標準的C來寫的,意思說,能夠跨各類平臺使用了。不過,仍是有兩三處須要微調一下<針對stm32f103  + rt_thread >。其中修改一下malloc & free & size_t 這三個東西:數組

 46 static void *(*cJSON_malloc)(size_t sz) = malloc;
 47 static void (*cJSON_free)(void *ptr) = free;
----------------------------------------
 46 static void *(*cJSON_malloc)(size_t sz) = rt_malloc;
 47 static void (*cJSON_free)(void *ptr) = rt_free;
複製代碼
 60 void cJSON_InitHooks(cJSON_Hooks* hooks)
 61 {
 62     if (!hooks) { /* Reset hooks */
 63         cJSON_malloc = malloc;
 64         cJSON_free = free;
 65         return;
 66     }
 67 
 68     cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
 69     cJSON_free   = (hooks->free_fn)?hooks->free_fn:free;
 70 }
----------------------------------------------------
 60 void cJSON_InitHooks(cJSON_Hooks* hooks)
 61 {
 62     if (!hooks) { /* Reset hooks */
 63         cJSON_malloc = rt_malloc;
 64         cJSON_free = rt_free;
 65         return;
 66     }
 67 
 68     cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:rt_malloc;
 69     cJSON_free   = (hooks->free_fn)?hooks->free_fn:rt_free;
 70 }
複製代碼

free & malloc就這麼兩個地方要修改一下吧,其中size_t 這個應該是在 .h 文件修改,主要是rtt的 rt_malloc 和這裏的malloc使用的不一樣,因此修改了下---不必定非要修改。工具

因此,這東西說實話,也不存在什麼移植不移植的問題了。很輕鬆的就能夠在各個平臺使用了。post

                                                                                                   例       程                                                                                                          

      不對json的格式進行說明了,下面直接記下使用方法了。

      第一,建立json數據串。這數據串,多是對象,也多是數組,也多是它們的各類組合,其中再加上一些鍵值對。有一點要先說明:它們的組合,符合父子繼承格式--這也是json數據串的特色。

     <1>  建立一個對象,並在這個對象裏面添加一個字符串鍵值和一個數字鍵值:

複製代碼
 1 int create_js(void)
 2 {
 3     cJSON *root;
 4     /*create json string root*/
 5     root = cJSON_CreateObject();
 6     if(!root) {
 7         DEBUG("get root faild !\n");
 8         goto EXIT;
 9     }else DEBUG("get root success!\n");
10 
11     {
12         cJSON * js_body ;
13 
14         const char *const body = "body";
15         cJSON_AddItemToObject(root, body, js_body=cJSON_CreateObject());
16         cJSON_AddStringToObject(js_body,"name","xiaohui");
17         cJSON_AddNumberToObject(js_body,"value",600);
18         {
19         char *s = cJSON_PrintUnformatted(root);
20         if(s){
21             DEBUG("create js string is %s\n",s);
22             free(s);
23         }
24         }
25         cJSON_Delete(root);
26     }
27 
28     return 0;
29 EXIT:
30     return -1;
31 }
32 
33 int main(int argc, char **argv)
34 {
35     create_js();
36     return 0;
37 }
複製代碼

運行結果:

1 create js string is  {"body":{"name":"xiaohui","value":600}}

說明: 建立根對象,使用  cJSON_CreateObject(); 這個API,返回的是一個 cJSON的指針,注意,在這個指針用完了之後,須要手工調用 cJSON_Delete(root); 進行內存回收。

建立body對象的時候,是在根對象的基礎上進行建立,而插入name 和value的時候,是以body爲父節點。須要注意的是  json 格式的數據,雖然也是一個字符串的樣子,但這個時候仍是沒法當成普通的字符串進行使用,須要調用 cJSON_PrintUnformatted(root) 或者 cJSON_Print(root);來將json對象轉換成普通的字符串,而且都是以該json對象的根爲基點。兩個API的區別便是:一個是沒有格式的:也就是轉換出的字符串中間不會有"\n" "\t"之類的東西存在,而cJSON_Print(root);打印出來是人看起來很舒服的格式。僅此而已。

<2> 建立一個數組,並向數組添加一個字符串和一個數字:

複製代碼
 1 int create_js(void)
 2 {
 3     cJSON *root, *js_body;
 4     root = cJSON_CreateArray();
 5     cJSON_AddItemToArray(root, cJSON_CreateString("Hello world"));
 6     cJSON_AddItemToArray(root, cJSON_CreateNumber(10)); 
 7     {
 8 //        char *s = cJSON_Print(root);
 9         char *s = cJSON_PrintUnformatted(root);
10         if(s){
11             DEBUG(" %s \n",s);
12             free(s);
13         }
14     }
15     if(root)
16     cJSON_Delete(root);
17 
18     return 0;
19 EXIT:
20     return -1;
21 }
22 
23 int main(int argc, char **argv)
24 {
25     create_js();
26     return 0;
27 }
複製代碼

運行結果:

1 ["Hello world",10]

<3> 對象裏面包括一個數組,數組裏麪包括對象,對象裏面再添加一個字符串和一個數字:

複製代碼
 1 int create_js(void)
 2 {
 3     cJSON *root, *js_body, *js_list;
 4     root = cJSON_CreateObject();
 5     cJSON_AddItemToObject(root,"body", js_body = cJSON_CreateArray());
 6     cJSON_AddItemToArray(js_body, js_list = cJSON_CreateObject());
 7     cJSON_AddStringToObject(js_list,"name","xiaohui");
 8     cJSON_AddNumberToObject(js_list,"status",100);
 9 
10     {
11         //        char *s = cJSON_Print(root);
12         char *s = cJSON_PrintUnformatted(root);
13         if(s){
14             DEBUG(" %s \n",s);
15             free(s);
16         }
17     }
18     if(root)
19         cJSON_Delete(root);
20 
21     return 0;
22 EXIT:
23     return -1;
24 }
25 
26 int main(int argc, char **argv)
27 {
28     create_js();
29     return 0;
30 }
複製代碼

運行結果:

1 {"body":[{"name":"xiaohui","status":100}]}

<4>其餘組合就依次類推,只要搞清楚父子關係便可。隨便嵌套隨便玩。再也不貼了。

   <第二, 解析json數據串>

   步驟: 1  先將普通的json 字符串 處理成 json對象格式。 2  根據關鍵字進行解析,解析的時候,須要根據關鍵字值的類型進行判斷,而這些類型,已經在cJSON.h裏面寫明白了,包括:對象、數組、普通字符串、普通變量等等。

   <偷個懶吧,將本身學習的時候用的資料現貼過來,後面休息一下再詳細補充本身在工程中的解析方法>

http://blog.csdn.net/xukai871105/article/details/17094113

http://blog.sina.com.cn/s/blog_a6fb6cc90101ffme.html

 

<固然,他寫的比較簡潔,還有些能夠補充的---其實我已經在上面使用文字進行補充過了。固然,不一樣的工程,可能解析的方法和側重點並不相同>

 

 

或許,是時候把解析的部分補充上來了:

處理流程:

1, 先將普通的json串處理成json對象,也就是所謂的建立json root的過程,只有一行代碼便可:

cJSON *root;
root = cJSON_Parse(js_string);

ps:須要注意的是,這個root在解析完成後,須要釋放掉,代碼以下:

if (root)
  cJSON_Delete(root);

2,開始拿關鍵字,但若是關鍵字還有父層或者祖層,那就須要先從父層開拿,所謂剝洋蔥是也!

先說沒有父層的:

{"name":"xiaohong","age":10}

這個字符串這樣拿便可:

複製代碼
 1 char *s = "{\"name\":\"xiao hong\",\"age\":10}";
 2 cJSON *root = cJSON_Parse(s);
 3 if(!root) {
 4     printf("get root faild !\n");
 5     return -1;
 6 }
 7 cJSON *name = cJSON_GetObjectItem(root, "name");
 8 if(!name) {
 9     printf("No name !\n");
10     return -1;
11 }
12 printf("name type is %d\n",name->type);
13 printf("name is %s\n",name->valuestring);
14 
15 cJSON *age = cJSON_GetObjectItem(root, "age");
16 if(!age) {
17     printf("no age!\n");
18     return -1;
19 }
20 printf("age type is %d\n", age->type);
21 printf("age is %d\n",age->valueint);
複製代碼

顯示結果:

1 name type is 4
2 name is xiao hong
3 age type is 3
4 age is 10

須要注意的是: 上面的type 已經在cJSON.h裏面定義好了,有本身的意義。若是是在嚴格的場所,應該先斷定該 item的type,而後再考慮去拿值。

而若是有父層的話,無非就是接着向下拿就是了,稍微修改下前面的demo吧:

處理這串數據吧:

{\"list\":{\"name\":\"xiao hong\",\"age\":10},\"other\":{\"name\":\"hua hua\"}}
複製代碼
 1 char *s = "{\"list\":{\"name\":\"xiao hong\",\"age\":10},\"other\":{\"name\":\"hua hua\"}}";
 2 cJSON *root = cJSON_Parse(s);
 3 if(!root) {
 4     printf("get root faild !\n");
 5     return -1;
 6 }
 7 
 8 cJSON *js_list = cJSON_GetObjectItem(root, "list");
 9 if(!js_list) {
10     printf("no list!\n");
11     return -1;
12 }
13 printf("list type is %d\n",js_list->type);
14 
15 cJSON *name = cJSON_GetObjectItem(js_list, "name");
16 if(!name) {
17     printf("No name !\n");
18     return -1;
19 }
20 printf("name type is %d\n",name->type);
21 printf("name is %s\n",name->valuestring);
22 
23 cJSON *age = cJSON_GetObjectItem(js_list, "age");
24 if(!age) {
25     printf("no age!\n");
26     return -1;
27 }
28 printf("age type is %d\n", age->type);
29 printf("age is %d\n",age->valueint);
30 
31 cJSON *js_other = cJSON_GetObjectItem(root, "other");
32 if(!js_other) {
33     printf("no list!\n");
34     return -1;
35 }
36 printf("list type is %d\n",js_other->type);
37 
38 cJSON *js_name = cJSON_GetObjectItem(js_other, "name");
39 if(!js_name) {
40     printf("No name !\n");
41     return -1;
42 }
43 printf("name type is %d\n",js_name->type);
44 printf("name is %s\n",js_name->valuestring);
45 
46 if(root)
47     cJSON_Delete(root);
48     return 0;
複製代碼

打印結果:

複製代碼
1 list type is 6
2 name type is 4
3 name is xiao hong
4 age type is 3
5 age is 10
6 list type is 6
7 name type is 4
8 name is hua hua
複製代碼

所謂子子孫孫無窮盡也,按照上面那個方法推下去便可。

3,json 裏數組怎麼取?

1 {\"list\":[\"name1\",\"name2\"]}

代碼以下:

複製代碼
 1 int main(int argc, char **argv)
 2 {
 3 char *s = "{\"list\":[\"name1\",\"name2\"]}";
 4 cJSON *root = cJSON_Parse(s);
 5 if(!root) {
 6     printf("get root faild !\n");
 7     return -1;
 8 }
 9 cJSON *js_list = cJSON_GetObjectItem(root, "list");
10 if(!js_list){
11     printf("no list!\n");
12     return -1;
13 }
14 int array_size = cJSON_GetArraySize(js_list);
15 printf("array size is %d\n",array_size);
16 int i = 0;
17 cJSON *item;
18 for(i=0; i< array_size; i++) {
19     item = cJSON_GetArrayItem(js_list, i);
20     printf("item type is %d\n",item->type);
21     printf("%s\n",item->valuestring);
22 }
23 
24 if(root)
25     cJSON_Delete(root);
26     return 0;
27 }
複製代碼

對頭,好簡單的樣子<在別人的庫上使用>

 

4  若是json數組裏面又搞了對象怎麼辦? 

不怕搞對象,就怕這樣搞對象? 無他,就是稍微複雜了一點,全是體力活兒:

<1> 既然是數組裏面,那確定要先測量數組的大小,而後根據大小循環拿;

<2> 拿到一個數組項,而後把這個項先轉化成普通的json字符串,也就是 char *s 能接受的。

<3>再次將這個json字符串,轉化成一個json對象

<4> 按照拿普通對象中的東西那樣開幹就好了。

ps:曾經試過直接在數組項中拿內容,失敗了,不知爲什麼,因而就按照這個4步開幹了。

好比:

1 {\"list\":[{\"name\":\"xiao hong\",\"age\":10},{\"name\":\"hua hua\",\"age\":11}]}

是的.list 是一個數組,數組裏面有兩個對象,那麼代碼以下:

複製代碼
 1 int main(int argc, char **argv)
 2 {
 3 char *s = "{\"list\":[{\"name\":\"xiao hong\",\"age\":10},{\"name\":\"hua hua\",\"age\":11}]}";
 4 cJSON *root = cJSON_Parse(s);
 5 if(!root) {
 6     printf("get root faild !\n");
 7     return -1;
 8 }
 9 cJSON *js_list = cJSON_GetObjectItem(root, "list");
10 if(!js_list){
11     printf("no list!\n");
12     return -1;
13 }
14 int array_size = cJSON_GetArraySize(js_list);
15 printf("array size is %d\n",array_size);
16 int i = 0;
17 cJSON *item,*it, *js_name, *js_age;
18 char *p  = NULL;
19 for(i=0; i< array_size; i++) {
20     item = cJSON_GetArrayItem(js_list, i);
21     if(!item) {
22         //TODO...
23     }
24     p = cJSON_PrintUnformatted(item);
25     it = cJSON_Parse(p);
26     if(!it)
27         continue ;
28     js_name = cJSON_GetObjectItem(it, "name");
29     printf("name is %s\n",js_name->valuestring);
30     js_age = cJSON_GetObjectItem(it, "age");
31     printf("age is %d\n",js_age->valueint);
32 
33 }
34 
35 if(root)
36     cJSON_Delete(root);
37     return 0;
38 }
複製代碼

按理說,應該釋放下 it 變量纔對,但彷佛事實不是這樣,僅僅能夠釋放根root。

好了,json 解析,無非就是上面的組合了,還能有什麼呢?

 

解析和封裝都有了,此文結束了。

看這裏:

https://github.com/boyisgood86/learning/tree/master/cjson

 

good luck !

 

 

update:  上面第四部分會致使內存泄露,修改方法見貼圖:

相關文章
相關標籤/搜索