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:  上面第四部分会导致内存泄露,修改方法见贴图:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/405233.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用虚拟路径时出现404问题

今天在做一个小项目的时候使用了如下路径 web.xml如下&#xff1a; 一切配置都正确&#xff0c;可还是404 在折腾了半天之后发现浏览器的地址栏没有项目名&#xff01;也就是说连接到项目外面去了&#xff0c;果断404。然后才记得虚拟路径前面的“/”和通常用的“../”具有同样…

树莓派使用STEP7:安装wiringPi硬件外设驱动C库

基于C/C开发树莓派外设&#xff0c;比较好的一种库是wiringPi&#xff0c;这里记录安装的流程和步骤。 一、在线安装 1、控制命令行 &#xff1a;git clone git://git.drogon.net/wiringPi 克隆git代码仓库 2、控制命令行&#xff1a; git pull origin 拉取最新的wiringPi…

STM32的I2C主从机通信

最近一段时间在做I2C通信协议&#xff0c;需要在两块STM32之间做I2C通信&#xff0c;定的是主机用IO口模拟&#xff0c;从机用的是STM32的硬件I2C&#xff0c;我的项目要求是需要主从机之间能够进行一串数据收发而不出错&#xff0c;实验时在主机方面&#xff0c;利用IO口模拟主…

css垂直居中那点事

这是我技术博客生涯的第一篇文章&#xff0c;想想还是有点小鸡冻。。。菜鸟的征程现在要开始了 学习css的时候经常被各种问题纠结到不要不要的&#xff0c;没办法&#xff0c;只能写写博客帮助整理一下自己的思绪和帮助一下和我遇到同样问题的小伙伴们 不知道各位学习css的小伙…

Windows常用shell命令大全

From: http://blog.csdn.net/yunzhongfeiniao/article/details/6564577 基于鼠标操作的后果就是OS界面外观发生改变&#xff0c;就得多花学习成本。更主要的是基于界面引导Path与命令行直达速度是难以比拟的。另外Geek很大一部分是键盘控&#xff0c;而非鼠标流的。 整理Wind…

div模拟select/option解决兼容性问题及增加可拓展性

个人博客&#xff1a; http://mcchen.club 想到做这个模拟的原因是之前使用select>option标签的时候发现没有办法操控option的很多样式&#xff0c;比如line-height等&#xff0c;还会由此导致在IE8及以下版本浏览器中的各种问题。 这个模拟思路很简单&#xff0c;也很清晰&…

Linux Socket网络通信示例

记录一下Linux 网络通信编程示例&#xff0c;主要用内网穿透和网络调试助手进行调试。 1、源文件&#xff1a; #include <stdlib.h> #include <sys/types.h> #include <stdio.h> #include <netinet/in.h> #incldue <string.h> //bze…

stm32+lwip(四):网页服务器测试

ST官方有lwip的例程&#xff0c;下载地址如下&#xff1a; https://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32-standard-peripheral-library-expansion/stsw-stm32070.html 本文例子参考ST官方给出的例…

Linux 用C/C++创建新文件并写入内容

1、需求 在Linux环境下用C编写一个函数&#xff0c;用于记录运行日志&#xff0c;要求只存在一个同名文件&#xff0c;每次记录前清除已有的信息。 2、思路 需要完成的是&#xff1a; &#xff08;1&#xff09;查找&#xff08;access&#xff09;是否该文件存在&#xff…

如何将Eclipse中的开源项目使用到Android Studio中

近几日&#xff0c;笔者用到了一些开源项目&#xff0c;比如著名的PTR项目。但是在使用的过程中&#xff0c;遇到了一些问题。 这个开源库是在Eclipse上面写的&#xff0c;我们现在开发用的是Android stuido。 两种软件的项目结构是不同的&#xff0c;那么怎么把PTR用到我们的项…

STM32 网络通信Web Server中 SSI与CGI的应用解析

本次主要解析STM32网络通信中WebServer应用&#xff0c;从网页界面的编写到浏览器与STM32之间进行通信的数据来说明SSI与CGI的原理及应用&#xff0c;并对GET与POST指令进行应用解析。 硬件和软件环境&#xff1a; 1.硬件环境&#xff1a;STM32F407&#xff0c;网卡芯片LAN87…

树莓派SSH 连接不上:socket error Event:32 Error:10053

问题如下&#xff1a; 解决办法&#xff1a;ssh文件夹下的文件权限问题。 cd /etc/ssh sudo chmod 0644 * sudo chmod 0600 ssh_host_ecdsa_key ssh_host_rsa_key登陆成功&#xff1a;

嵌入式设备web服务器比较

现在在嵌入式设备中所使用的web服务器主要有&#xff1a;boa、thttpd、mini_httpd、shttpd、lighttpd、goaheand、appweb和apache等。 Boa 1.介绍 Boa诞生于1991年&#xff0c;作者Paul Philips。是开源的&#xff0c;应用很广泛&#xff0c;特别适合于嵌入式设备&#xff0c…

UML造型——使用EA时序图工具的开发实践和经验

Enterprise Architect&#xff08;下面简称EA&#xff09;是一款基于OMG UML的可视化模型与设计工具。提供了对软件系统的设计和构建、业务流程建模和基于领域建模的支持&#xff0c;被企业和组织不仅应用于对系统的建模&#xff0c;还用于推进模型在整个应用程序开发周期中实现…

Qt QInputDialog文本输入对话框示例

1、代码如下 //引入头文件: #include <QInputDialog>//...//...//...//具体用法&#xff1a; bool isOK;//QInputDialog 是否成功得到输入 QString text QInputDialog::getText(NULL, "参数设定", "输入单次召测统计时间&#xff0c;eg.\"0:0:…

单元测试工具Numega BoundsChecker

From: http://blog.csdn.net/wangweitingaabbcc/article/details/7794985 1 前言 我在本文中详细介绍了测试工具NuMega Devpartner(以下简称NuMega)的使用方法。 NuMega是一个动态测试工具&#xff0c;主要应用于白盒测试。该工具的特点是学习简单、使用方便、功能有效。NuM…

在Codeigniter框架中使用NuSOAP

0、NuSOAP的简介 NuSOAP 是一组功能强大的PHP类&#xff0c;这个工具的发布让使用和创建SOAP消息变得相当简单。 NuSOAP有Dirtrich Ayala编写&#xff0c;可以无缝的与许多最流行的SOAP服务实现交互&#xff0c;它以LGPL协议进行发布。NuSOAP的主要特性包括&#xff1a; 简单&a…

Keil使用PC-Lint

Keil使用PC-Lint 随着项目的推进与迭代&#xff0c;一个Project的代码量往往会不知不觉增长&#xff0c;当项目代码达到数万行&#xff0c;迭代经历较长时间后&#xff0c;仅靠开发人员自身的代码质量已不能满足对整体质量的把控。难以避免会出现一些潜在的逻辑错误与非逻辑错误…

嵌入式产品开发流程

嵌入式产品&#xff0c;与普通电子产品一样&#xff0c;开发过程都需要遵循一些基本的流程&#xff0c;都是一个从需求分析到总体设计&#xff0c;详细设计到最后产品完成的过程。但是&#xff0c;与普通电子产品相比&#xff0c;嵌入式产品的开发流程又有其特殊之处。它包含嵌…

Codeforces 478B 6thweek contest_B

Random teams 题意&#xff1a; 有n个选手和m个队伍&#xff0c;让你分配&#xff0c;条件是每个队伍至少要有1个选手。分配完之后&#xff0c;每队伍里2个人可以组成一组&#xff0c;求分配完之后最多的组数和最少的组数 分析&#xff1a; 1. 最多的情况就是&#xff0c;先每…