缘      起

最近在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上,请使用以下命令进行编译:

 gcc -g -Wall *.c -l m

就会默认生成一个 a.out文件,执行即可。在linux下编译的时候,注意链接 libm 库。

整个项目都是以极标准的C来写的,意思说,可以跨各种平台使用了。不过,还是有两三处需要微调一下<针对stm32f103  + rt_thread >。其中修改一下malloc & free & size_t 这三个东西:

  static void *(*cJSON_malloc)(size_t sz) = malloc;
static void (*cJSON_free)(void *ptr) = free;
----------------------------------------
static void *(*cJSON_malloc)(size_t sz) = rt_malloc;
static void (*cJSON_free)(void *ptr) = rt_free;
  void cJSON_InitHooks(cJSON_Hooks* hooks)
{
if (!hooks) { /* Reset hooks */
cJSON_malloc = malloc;
cJSON_free = free;
return;
} cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
}
----------------------------------------------------
void cJSON_InitHooks(cJSON_Hooks* hooks)
{
if (!hooks) { /* Reset hooks */
cJSON_malloc = rt_malloc;
cJSON_free = rt_free;
return;
} cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:rt_malloc;
cJSON_free = (hooks->free_fn)?hooks->free_fn:rt_free;
}

free & malloc就这么两个地方要修改一下吧,其中size_t 这个应该是在 .h 文件修改,主要是rtt的 rt_malloc 和这里的malloc使用的不同,所以修改了下---不一定非要修改。

所以,这东西说实话,也不存在什么移植不移植的问题了。很轻松的就可以在各个平台使用了。

例       程

不对json的格式进行说明了,下面直接记下使用方法了。

第一,创建json数据串。这数据串,可能是对象,也可能是数组,也可能是它们的各种组合,其中再加上一些键值对。有一点要先说明:它们的组合,符合父子继承格式--这也是json数据串的特点。

<1>  创建一个对象,并在这个对象里面添加一个字符串键值和一个数字键值:

 int create_js(void)
{
cJSON *root;
/*create json string root*/
root = cJSON_CreateObject();
if(!root) {
DEBUG("get root faild !\n");
goto EXIT;
}else DEBUG("get root success!\n"); {
cJSON * js_body ; const char *const body = "body";
cJSON_AddItemToObject(root, body, js_body=cJSON_CreateObject());
cJSON_AddStringToObject(js_body,"name","xiaohui");
cJSON_AddNumberToObject(js_body,"value",);
{
char *s = cJSON_PrintUnformatted(root);
if(s){
DEBUG("create js string is %s\n",s);
free(s);
}
}
cJSON_Delete(root);
} return ;
EXIT:
return -;
} int main(int argc, char **argv)
{
create_js();
return ;
}

运行结果:

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

说明: 创建根对象,使用  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> 创建一个数组,并向数组添加一个字符串和一个数字:

 int create_js(void)
{
cJSON *root, *js_body;
root = cJSON_CreateArray();
cJSON_AddItemToArray(root, cJSON_CreateString("Hello world"));
cJSON_AddItemToArray(root, cJSON_CreateNumber());
{
// char *s = cJSON_Print(root);
char *s = cJSON_PrintUnformatted(root);
if(s){
DEBUG(" %s \n",s);
free(s);
}
}
if(root)
cJSON_Delete(root); return ;
EXIT:
return -;
} int main(int argc, char **argv)
{
create_js();
return ;
}

运行结果:

 ["Hello world",]

<3> 对象里面包括一个数组,数组里面包括对象,对象里面再添加一个字符串和一个数字:

 int create_js(void)
{
cJSON *root, *js_body, *js_list;
root = cJSON_CreateObject();
cJSON_AddItemToObject(root,"body", js_body = cJSON_CreateArray());
cJSON_AddItemToArray(js_body, js_list = cJSON_CreateObject());
cJSON_AddStringToObject(js_list,"name","xiaohui");
cJSON_AddNumberToObject(js_list,"status",); {
// char *s = cJSON_Print(root);
char *s = cJSON_PrintUnformatted(root);
if(s){
DEBUG(" %s \n",s);
free(s);
}
}
if(root)
cJSON_Delete(root); return ;
EXIT:
return -;
} int main(int argc, char **argv)
{
create_js();
return ;
}

运行结果:

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

<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":}

这个字符串这样拿即可:

 char *s = "{\"name\":\"xiao hong\",\"age\":10}";
cJSON *root = cJSON_Parse(s);
if(!root) {
printf("get root faild !\n");
return -;
}
cJSON *name = cJSON_GetObjectItem(root, "name");
if(!name) {
printf("No name !\n");
return -;
}
printf("name type is %d\n",name->type);
printf("name is %s\n",name->valuestring); cJSON *age = cJSON_GetObjectItem(root, "age");
if(!age) {
printf("no age!\n");
return -;
}
printf("age type is %d\n", age->type);
printf("age is %d\n",age->valueint);

显示结果:

 name type is
name is xiao hong
age type is
age is

需要注意的是: 上面的type 已经在cJSON.h里面定义好了,有自己的意义。如果是在严格的场所,应该先判定该 item的type,然后再考虑去拿值。

而如果有父层的话,无非就是接着向下拿就是了,稍微修改下前面的demo吧:

处理这串数据吧:

{\"list\":{\"name\":\"xiao hong\",\"age\":10},\"other\":{\"name\":\"hua hua\"}}
 char *s = "{\"list\":{\"name\":\"xiao hong\",\"age\":10},\"other\":{\"name\":\"hua hua\"}}";
cJSON *root = cJSON_Parse(s);
if(!root) {
printf("get root faild !\n");
return -;
} cJSON *js_list = cJSON_GetObjectItem(root, "list");
if(!js_list) {
printf("no list!\n");
return -;
}
printf("list type is %d\n",js_list->type); cJSON *name = cJSON_GetObjectItem(js_list, "name");
if(!name) {
printf("No name !\n");
return -;
}
printf("name type is %d\n",name->type);
printf("name is %s\n",name->valuestring); cJSON *age = cJSON_GetObjectItem(js_list, "age");
if(!age) {
printf("no age!\n");
return -;
}
printf("age type is %d\n", age->type);
printf("age is %d\n",age->valueint); cJSON *js_other = cJSON_GetObjectItem(root, "other");
if(!js_other) {
printf("no list!\n");
return -;
}
printf("list type is %d\n",js_other->type); cJSON *js_name = cJSON_GetObjectItem(js_other, "name");
if(!js_name) {
printf("No name !\n");
return -;
}
printf("name type is %d\n",js_name->type);
printf("name is %s\n",js_name->valuestring); if(root)
cJSON_Delete(root);
return ;

打印结果:

 list type is
name type is
name is xiao hong
age type is
age is
list type is
name type is
name is hua hua

所谓子子孙孙无穷尽也,按照上面那个方法推下去即可。

3,json 里数组怎么取?

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

代码如下:

 int main(int argc, char **argv)
{
char *s = "{\"list\":[\"name1\",\"name2\"]}";
cJSON *root = cJSON_Parse(s);
if(!root) {
printf("get root faild !\n");
return -;
}
cJSON *js_list = cJSON_GetObjectItem(root, "list");
if(!js_list){
printf("no list!\n");
return -;
}
int array_size = cJSON_GetArraySize(js_list);
printf("array size is %d\n",array_size);
int i = ;
cJSON *item;
for(i=; i< array_size; i++) {
item = cJSON_GetArrayItem(js_list, i);
printf("item type is %d\n",item->type);
printf("%s\n",item->valuestring);
} if(root)
cJSON_Delete(root);
return ;
}

对头,好简单的样子<在别人的库上使用>

4  如果json数组里面又搞了对象怎么办?

不怕搞对象,就怕这样搞对象? 无他,就是稍微复杂了一点,全是体力活儿:

<1> 既然是数组里面,那肯定要先测量数组的大小,然后根据大小循环拿;

<2> 拿到一个数组项,然后把这个项先转化成普通的json字符串,也就是 char *s 能接受的。

<3>再次将这个json字符串,转化成一个json对象

<4> 按照拿普通对象中的东西那样开干就行了。

ps:曾经试过直接在数组项中拿内容,失败了,不知为何,于是就按照这个4步开干了。

比如:

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

是的.list 是一个数组,数组里面有两个对象,那么代码如下:

 int main(int argc, char **argv)
{
char *s = "{\"list\":[{\"name\":\"xiao hong\",\"age\":10},{\"name\":\"hua hua\",\"age\":11}]}";
cJSON *root = cJSON_Parse(s);
if(!root) {
printf("get root faild !\n");
return -;
}
cJSON *js_list = cJSON_GetObjectItem(root, "list");
if(!js_list){
printf("no list!\n");
return -;
}
int array_size = cJSON_GetArraySize(js_list);
printf("array size is %d\n",array_size);
int i = ;
cJSON *item,*it, *js_name, *js_age;
char *p = NULL;
for(i=; i< array_size; i++) {
item = cJSON_GetArrayItem(js_list, i);
if(!item) {
//TODO...
}
p = cJSON_PrintUnformatted(item);
it = cJSON_Parse(p);
if(!it)
continue ;
js_name = cJSON_GetObjectItem(it, "name");
printf("name is %s\n",js_name->valuestring);
js_age = cJSON_GetObjectItem(it, "age");
printf("age is %d\n",js_age->valueint); } if(root)
cJSON_Delete(root);
return ;
}

按理说,应该释放下 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. appdata文件夹有什么用途?C盘appdata可以删除吗?

    在内存紧张的时候,我们都会选择删除一些无关紧要的大文件来释放内存,有不少网友发现在系统C盘下有一个appdata文件夹,而且体积挺大的,不知道能不能删除,针对此问题,本文就为大家介绍appdata文件 ...

  2. php的header()大全

    <?php /*** Function: PHP header() examples (PHP) ** Desc: Some examples on how to use the header( ...

  3. pthread_attr_t 线程属性(二)

    一.函数: 1.线程属性的初始化与销毁:#include <pthread.h>int pthread_attr_init(pthread_attr_t *attr);int pthrea ...

  4. FreeMarker笔记 第四章 其它

    4.1 自定义指令 4.1.1 简介 自定义指令可以使用macro指令来定义.Java程序员若不想在模板中实现定义指令,而是在Java语言中实现指令的定义,这时可以使用freemarker.templ ...

  5. centos配置中文显示和中文输入

    我现在使用虚拟机运行centos,但是安装完成后系统显示英文,而且无法进行中文输入,这使我感到很烦躁,虽然我对自己说,这样可以逼迫自己适应全英文的环境,但作为一个中国人还是难以忍受,所以记录一下解决办 ...

  6. Chapter9:顺序容器

    现代C++程序应该使用标准库容器,而不是更原始的数据结构,例如内置数组. 新标准库容器的性能几乎肯定与最精心优化过的同类数据结构一样好. 当我们用一个对象来初始化容器时,或将一个对象插入到容器中时,实 ...

  7. 开源框架DNN简介以及安装

    donetnuke 是一款免费的开源cms框架,目前也有收费版,不过免费版也可以适应大家大部分的需求.我前些阵子是老板让我在20天内,做好一个官网并且发布,并且指定使用dnn这个框架,考虑到又可以学习 ...

  8. python用法笔记(数组(list、touple、dict)、字符串)

    1.产生n个全为1的数组a=[1]*n2.字符数字转化int('12')float('12.5')str(123.45)ASCII码转为相应的字符:chr(97)字符转化为相应的ASCII码:ord( ...

  9. 通用数据链接(UDL)的用法

    偶然看到UDL,决定看一下其用法. UDL:通用数据链接.此文件中提供 OleDbConnection 的连接信息.也就是说UDL只能在OleDbConnection中使用. 微软不建议使用UDL 因 ...

  10. ajax 第一个程序

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...