cJSON 使用笔记
最近在stm32f103上做一个智能家居的项目,其中选择的实时操作系统是 rt_thread OS v1.2.2稳定版本,其中涉及到C和java(android)端数据的交换问题,经过讨论和研究,选择了json格式的数据进行交互。当然,如果自己去写一个json解析器,有点重造轮子的嫌疑。于是使用了开源的json解析器。考虑到是嵌入式平台,在一位朋友的推荐下,选择了轻量级别的cJSON。
使 用
cJSON 开源项目位置: http://sourceforge.net/projects/cjson/
cJSON,目前来说,就只有两个文件,一个cJSON.c 一个cJSON.h文件。使用的时候,自己创建好一个main.c文件后,如果是在linux pc上,请使用以下命令进行编译:
1 gcc -g -Wall *.c -l m
就会默认生成一个 a.out文件,执行即可。在linux下编译的时候,注意链接 libm 库。
整个项目都是以极标准的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使用的不同,所以修改了下---不一定非要修改。
所以,这东西说实话,也不存在什么移植不移植的问题了。很轻松的就可以在各个平台使用了。
例 程
不对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: 上面第四部分会导致内存泄露,修改方法见贴图:
cJSON 使用笔记相关推荐
- 【cJSON】CJSON学习笔记(二)
1.重要函数说明 [1]两个创建 [创建JSON对象]cJSON *cJSON_CreateObject(void); [创建JSON数组]cJSON *cJSON_CreateArray(v ...
- 【cJSon】cJSON学习笔记(一)
1.JSON格式简述 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.易于人阅读和编写,同时也易于机器解析和生成.它基于JavaScript(Standa ...
- 【C】cJSON使用以及在stm32中的应用
1. cJSON使用 最近一段时间在整理自己进入研究生阶段后学习过程中的一些内容,之前在进行相关代码调试过程中,也的确耗费了比较大的精力去搜寻资料,然后整合代码到自己所需要的系统中,如在stm32中使 ...
- 几种物联网实现方式之间的比较+转载
这么长时间,自己项目没有一点的进步,而又来研究物联网,好累的说 http://www.open-open.com/lib/view/open1423887376154.html http://www. ...
- cJSON笔记——三种结构的cJSON数组
最近的项目中,涉及对cJSON库的使用,特别是不同结构的cJOSN数组的运用,在此小结以下. 1.指定(路径/文件类型/文件名)读取整个文本 /** * @brief * * @param file_ ...
- cjson 对象是json数组型结构体_C语言 - cJSON解析特定格式 含有数组array类型的数据...
在ESP32中使用了cJSON库,发现很好用.最近服务器端的JSON格式越来越多样,还是有些注意点,需要做下笔记记录下来. cJSON *MAC_arry = cJSON_GetObjectItem( ...
- 乐鑫esp8266学习rtos3.0笔记第11篇:详细分析Esp8266上电信息打印的数据,如何做到串口通讯上电不乱码打印。
本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 序号 SDK版本 内容 链接 1 nonos2.0 搭建 ...
- 乐鑫esp8266学习rtos3.0笔记第3篇: 一篇文章带你搞掂存储技术 NVS 的认识和使用,如何利用NVS保存整型、字符串、数组以及结构体。(附带demo)
本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1. Esp8266之 搭建开发环境,开始一个" ...
- Unity3D 学习笔记4 —— UGUI+uLua游戏框架
Unity3D 学习笔记4 -- UGUI+uLua游戏框架 使用到的资料下载地址以及基础知识 框架讲解 拓展热更过程 在这里我们使用的是uLua/cstolua技术空间所以提供的UGUI+uLua的 ...
最新文章
- 王炸养成记——看Linux 25周年发展变化
- 常用json框架介绍和Jackson返回结果处理
- MySQL常用存储引擎之MyISAM
- ASP.NET Core 中断请求了解一下(翻译)
- mysql实体监听器_GitHub - langjiangit/spring-boot-starter-mysql-binlog: mysql的binlog监听器
- 对象序列化机制的理解
- sender分析之Selector
- python direct_Python Qt.DirectConnection方法代码示例
- Python 地图行政区边界方案
- H5页面实现微信授权登录
- 抖音视频社交产品多闪上架各大应用市场
- 副族元素从上到下原子半径_原子的大小以原子半径来表示
- 锦江展焕新演绎,憬黎公寓住造理想
- 【整理自官方公开资料】CSDN博主排名影响因素
- Scikit-learn机器学习实战之Kmeans
- 我心中的计算机作文500,我眼中的作文500字
- lol人物模型提取(一)
- 【算法-Java实现】 换钱的方法数(暴力递归法)
- 军队文职(数学2+物理)——高等数学 5、导数
- S1110应变电桥信号调理模块
热门文章
- Spring(4)——面向切面编程(AOP模块)
- Spring的7种事务传播行为类型
- Logger PatternLayout 格式
- 编码练习——Java-8-输入/输出
- elasticsearch2.3安装以及集群部署
- Java虚拟机学习(1):体系结构 内存模型
- Java程序员从笨鸟到菜鸟之(一百零九)一步一步学习webservice(三)开发第一个基于XFire的webservice
- 程序员面试题精选100题(35)-两链表的第一个公共结点[数据结构]
- 正则表达式Regular Expression
- boost源码剖析之:boost::multi_array