缘      起      

最近在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

需要注意的是: 上面的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);  /* JSON 格式化该子对象,以供 cJSON_Parse 解析对象,另一种方法就是去除 24-25行,26-31行 it 由 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 使用笔记的更多相关文章

  1. cJSON学习笔记

    1.JSON格式简述 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.易于人阅读和编写,同时也易于机器解析和生成.它基于JavaScript(Standa ...

  2. cJSON学习笔记 续集

    0.前言     本文试图说明怎样使用CJSON构造各种各样的JSON数据包.在前段时间已经写过一篇cJSON的文章,所以本文成为"续集".     [相关博文]     [前端学 ...

  3. cJSON 使用笔记

    缘      起 最近在stm32f103上做一个智能家居的项目,其中选择的实时操作系统是 rt_thread OS v1.2.2稳定版本,其中涉及到C和java(android)端数据的交换问题,经 ...

  4. cJSON使用笔记

    将cJSON用到STM32f103上 cJSON内存管理使用的是标准库stdlib.h的malloc()free()realloc()动态内存管理函数,我STM32F103使用的是正点原子的mallo ...

  5. JSON构造/解析(by C)---cJSON和json-c

    背景 JSON即JavaScript Object Notation,是一种轻量级的数据交换格式. JSON建构于两种结构: "名称/值"对的集合(A collection of ...

  6. PHP再学习5——RESTFul框架 远程控制LED

    0.前言     去年(2013年)2月第一次接触yeelink平台,当时该平台已经运行了一些时间也吸引了不少极客.试想自己也将投身IoT(物联网)行业,就花了些时间研究了它.陆陆续续使用和研究了一年 ...

  7. 【转】cJSON 源码阅读笔记

    前言 cjson 的代码只有 1000+ 行, 而且只是简单的几个函数的调用. 而且 cjson 还有很多不完善的地方, 推荐大家看完之后自己实现一个 封装好的功能完善的 cjson 程序. json ...

  8. cJSON笔记

    github地址: https://github.com/DaveGamble/cJSON 需要将cJSON.h 和 cJSON.c拷贝到路径下,并且连接所需库文件 -lm 步骤:1.先将普通的jso ...

  9. cJSON 库的使用和优化

    部门的产品使用自己公司研发的系统,嵌入式web服务器移植的是goahead2.5的,服务器和前端使用JSON交互,移植的cJSON库,所以这段时间对JSON的使用做个简单的笔记,cJSON.h提供出来 ...

随机推荐

  1. C# 枚举基本用法及扩展方法

    没什么好说的,都是些基础! 代码如下: using System; using System.Collections.Generic; using System.ComponentModel; usi ...

  2. Springboot 2.0.4 整合Mybatis出现异常Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required

    在使用Springboot 2.0.4 整合Mybatis的时候出现异常Property 'sqlSessionFactory' or 'sqlSessionTemplate' are require ...

  3. EZ 2018 06 02 NOIP2018 模拟赛(十七)

    这次的比赛是真心比较狗,我TM的写了30min的树剖ZZ地直接memset超时了 话说我既然想到差分就应该去写差分的啊! 好了不过这次Rank还挺高的,终于要打进前10了当然是假的了. 好了下面开始讲 ...

  4. Linux-C-Program:makefile

    注:本文参照博客:https://blog.csdn.net/initphp/article/details/7692923 1. 概述2. 示例说明2.1 无makefile编译2.2 有makef ...

  5. zifutongji

    第三次作业要求我们自己写程序,我算我们班写的比较晚的了,我听他们写的都是在文件中写一段代码,然后读出来.我们班大部分都是,所以,我就想可不可以跟他们不一样呢,写一个属于自己的思路. 所以我想到了数组. ...

  6. Linux内核分析第五周学习总结

    扒开系统调用的三层皮(下) 20135237朱国庆+ 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/UST ...

  7. 20135337——linux第四次实践:字符集总结与分析

    ASCII & GB2312 & UTF-8 ASCII 主要用于显示现代英语和其他西欧语言.它是现今最通用的单字节编码系统,并等同于国际标准ISO 646: 7位(bits)表示一个 ...

  8. Laravel Exception处理逻辑解析

    Laravel Exception处理逻辑解析 vendor/laravel/framework/src/Illuminate/Foundation/Application.php app首先继承了c ...

  9. shell脚本--显示文本内容

    shell脚本显示文本内容及相关的常用命令有cat.more.less.head.tail.nl 首先是cat,cat最常用的就是一次性显示文件的所有内容,如果一个文件的内容很多的话,那么就不是很方便 ...

  10. Activiti的BPMN演示工具

    场景是这样的:产品经理不懂技术,又不想安装Java以及Eclipse(需要安装Activiti BPMN Designer的插件). 这两天解决.bpmn的解析(BPMNParser)时顺带找到一个顺 ...