最近接触到的一个项目,需要使用json数据格式上传几类数据,于是近期把json格式学习了一下,体会到了json作为一类通用的数据传输格式,能够为不同介质间的数据传输带来多大的便利。
虽然json本身并不复杂,但实际项目中难免遇到许多嵌套层次非常复杂的数据,像本咸鱼这次虽然只封装了5条数据,却写了300行代码。好在借助简洁的cJSON工具,让整个写代码的过程虽然枯燥,但逻辑却不复杂。
json介绍
以下内容摘自百度百科:
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
一款轻量级的json数据解析工具——cJSON
cJSON是一个使用C语言编写的JSON数据解析器,具有超轻便,可移植,单文件的特点,使用MIT开源协议。
cJSON项目托管在Github上,仓库地址如下:
https://github.com/DaveGamble/cJSON
使用Git命令将其拉取到本地:
sudo git clone https://github.com/DaveGamble/cJSON.git
进入cJSON文件夹,输入指令生成相关文件并链接系统库:
make
sudo make install
注:在之后写代码的过程中需要将生成的cJSON.c文件复制到你工程所在的文件夹。
封装多层嵌套的json数据
在学习json时我们会看到很多例子,里面会教你封装一些简单的json数据。但是如果你所需要封装的数据嵌套格式非常多,像下面这样:
{
“msgCnt”: 20,
“timestamp”: 1576800000,
“nodes”:
[
{
“name”: “node1”,
“nodeId”:
{
“region”: 25,
“id”: 1001
},
“refPos”:
{
“lat”: 32.1234567,
“lon”: 112.1234567,
“elevation”: 20.2
},
“inLinks”:
[
{
“name”: “link1”,
“upstreamNodeId”:
{
“region”:25,
“id”: 1002
},
“speedLimits”:
[
{
“type”: 5,
“speed”: 1667
}
],
“laneWidth”: 300,
“lanes”:
[
{
“laneId”: 1
},
{
“laneId”: 2
}
],
“movements”:
[
{
“remoteIntersection”:
{
“region”: 25,
“id”: 1003,
},
“phaseId”: 1
},
{
“remoteIntersection”:
{
“region”: 25,
“id”: 1004
},
“phaseId”: 2
}
]
}
]
}
]
}
该如何去编写代码呢?
我们的cJSON包里有如下几类函数可以调用:
cJSON_AddNullToObject(cJSON * const object, const char * const name);
cJSON_AddTrueToObject(cJSON * const object, const char * const name);
cJSON_AddFalseToObject(cJSON * const object, const char * const name);
cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
cJSON_AddObjectToObject(cJSON * const object, const char * const name);
cJSON_AddArrayToObject(cJSON * const object, const char * const name);
封装JSON数据的过程,其实就是创建链表和向链表中添加节点的过程。
我先放一下我的代码:
#include <stdio.h>
#include <cJSON.h>
int main()
{
char* str;
cJSON* cjson_test = NULL;
cJSON* cjson_address = NULL;
cJSON* cjson_address0 = NULL;
cJSON* cjson_address1 = NULL;
cJSON* cjson_address2 = NULL;
cJSON* cjson_address3 = NULL;
cJSON* cjson_address4 = NULL;
cJSON* cjson_address5 = NULL;
cJSON* cjson_address6 = NULL;
cJSON* cjson_address7 = NULL;
cJSON* cjson_skill = NULL;
cJSON* cjson_skill0 = NULL;
cJSON* cjson_skill1 = NULL;
cJSON* cjson_skill2 = NULL;
cJSON* cjson_skill3 = NULL;
cjson_test = cJSON_CreateObject();
cJSON_AddNumberToObject(cjson_test, "msgCnt", 20);
cJSON_AddNumberToObject(cjson_test, "timeStamp", 1576800000);
cjson_skill = cJSON_CreateArray();
cJSON_AddItemToObject(cjson_test, "nodes", cjson_skill);
cjson_address = cJSON_CreateObject();
cJSON_AddItemToObject(cjson_skill, "nodes", cjson_address);
cJSON_AddStringToObject(cjson_address, "name", "node1");
cjson_address0 = cJSON_CreateObject();
cJSON_AddItemToObject(cjson_address, "nodeId", cjson_address0);
cJSON_AddNumberToObject(cjson_address0, "region", 25);
cJSON_AddNumberToObject(cjson_address0, "id", 1001);
cJSON_AddItemToObject(cjson_address, "refPos", cjson_address7);
cJSON_AddNumberToObject(cjson_address7, "lat", 32.1234567);
cJSON_AddNumberToObject(cjson_address7, "lon", 112.1234567);
cJSON_AddNumberToObject(cjson_address7, "elevation", 20.2);
cjson_skill0 = cJSON_CreateArray();
cJSON_AddItemToObject(cjson_address, "inLinks", cjson_skill0);
cjson_address1 = cJSON_CreateObject();
cJSON_AddItemToObject(cjson_skill0, "inLinks", cjson_address1);
cJSON_AddStringToObject(cjson_address1, "name", "link1");
cjson_address2 = cJSON_CreateObject();
cJSON_AddItemToObject(cjson_address1, "upstreamNodeLd", cjson_address2);
cJSON_AddNumberToObject(cjson_address2, "region", 25);
cJSON_AddNumberToObject(cjson_address2, "id", 1002);
cjson_skill1 = cJSON_CreateArray();
cJSON_AddItemToObject(cjson_address1, "speedLimits", cjson_skill1);
cjson_address3 = cJSON_CreateObject();
cJSON_AddItemToObject(cjson_skill1, "nodes", cjson_address3);
cJSON_AddNumberToObject(cjson_address3, "type", 5);
cJSON_AddNumberToObject(cjson_address3, "speed", 1667);
cJSON_AddNumberToObject(cjson_address3, "laneWidth", 300);
cJSON_AddItemToObject(cjson_address1, "lanes", cjson_skill2);
cJSON_AddItemToObject(cjson_skill2, "lanes", cjson_address3);
cJSON_AddNumberToObject(cjson_address3, "laneId", 1);
cjson_address4 = cJSON_CreateObject();
cJSON_AddItemToObject(cjson_skill2, "lanes", cjson_address4);
cJSON_AddNumberToObject(cjson_address4, "laneId", 2);
cJSON_AddItemToObject(cjson_address1, "movements", cjson_skill3);
cJSON_AddItemToObject(cjson_skill3, "movements", cjson_address3);
cjson_address5 = cJSON_CreateObject();
cJSON_AddItemToObject(cjson_address3, "remoteIntersection", cjson_address5);
cJSON_AddNumberToObject(cjson_address5, "region", 25);
cJSON_AddNumberToObject(cjson_address5, "id", 1003);
cJSON_AddNumberToObject(cjson_address3, "phaseId", 1);
cjson_address6 = cJSON_CreateObject();
cJSON_AddItemToObject(cjson_address3, "remoteIntersection", cjson_address6);
cJSON_AddNumberToObject(cjson_address6, "region", 25);
cJSON_AddNumberToObject(cjson_address6, "id", 1004);
cJSON_AddNumberToObject(cjson_address3, "phaseId", 2);
str = cJSON_Print(cjson_test);
printf("%s\n", str);
return 0;
}
输入编译指令并运行:
gcc test.c cJSON.c -o test
./test
输出结果:
总的来说就是几个关键点:
1)cJSON_AddNumberToObject()和cJSON_AddStringToObject()函数用于添加一个新的结点并赋值(赋数字和字符串);
2)cJSON_AddItemToObject()函数用于添加一个新的结点分支,第一个参数必须为上一个结点的表达式,第三个参数为下一个结点的表达式;
3)新的结点如果是对象(大括号括起来的是对象),结点用cJSON_CreateObject()函数添加;
4)新的结点如果是数组(中括号括起来的是数组),结点用cJSON_CreateArray()函数添加;