使用cJSON解析JSON字符串

使用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":"jadena@126.com",

                   "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":"bbbb@126.com","height":1.67},

{"lastName":"jadena","email":"jadena@126.com","age":8,"height":1.17},

{"email":"cccc@126.com","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接口的同学,可以有些借鉴参考的作用。 

附带例程: 

 
  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. }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值