物联网数据解析实战:掌握CJSON库核心函数,精准处理JSON数据
CJSON库是一个轻量级的JSON解析库,专为C语言设计,适用于嵌入式系统和物联网应用。它提供了简单易用的API,使得开发者能够轻松地解析和生成JSON数据。在本教程中,我们将深入探讨CJSON库的核心函数,并学习如何使用它们来处理物联网数据。
CJSON库简介
CJSON是一个用于解析和生成JSON数据的C语言库。它由Lloyd Hilaiel编写,旨在提供简单、快速、高效的JSON处理能力。CJSON库的核心函数包括解析JSON字符串、生成JSON字符串、遍历JSON对象等,这些函数使得开发者能够轻松地处理JSON数据,满足物联网应用的各种需求。
希望这篇博客能够帮助到大家。点点关注,不迷路哦!
墨小羽ovo个人主页
json和cJSON的区别
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。JSON数据通常以字符串的形式表示,例如:
{
"name": "John",
"age": 30,
"city": "New York"
}
而CJSON是一个用于解析和生成JSON数据的C语言库。它提供了简单易用的API,使得开发者能够轻松地处理JSON数据。例如,使用CJSON库可以解析上述JSON字符串,并获取其中的"name"、"age"和"city"字段的值。
CJSON库的安装和使用
1.CJSON库的安装和使用非常简单。你可以从CJSON的官方网站(https://github.com/DaveGamble/cJSON) 下载源代码。
2.只需要CJSON.c和CJSON…h两个文件,复制粘贴到我的keil代码中即可。
CJSON库的解析函数
-
cJSON_Parse
函数原型:cJSON *cJSON_Parse(const char *value);
功能描述:将JSON格式的字符串解析为cJSON结构体。
使用场景:当您从网络、文件或其他来源接收到JSON格式的字符串时,可以使用此函数将其解析为C语言可操作的cJSON结构体。
参数说明:value:JSON格式的字符串。
返回值:解析成功返回指向cJSON结构体的指针,解析失败返回NULL。
示例代码:
char *json_str = "{\"name\":\"John\",\"age\":30,\"city\":\"New York\"}"; cJSON *json = cJSON_Parse(json_str); if (json == NULL) { printf("Error parsing JSON\n"); return 1; } //打印下这个json的值 printf("%s\n", cJSON_Print(json)); ```//运行结果 ```bash { "name": "John", "age": 30, "city": "New York" }
-
cJSON_GetObjectItem
函数原型:cJSON *cJSON_GetObjectItem(cJSON *object, const char *string);
功能描述:从cJSON结构体中获取指定字段的值。
使用场景:当您需要获取JSON对象中某个字段的值时,可以使用此函数。
参数说明:object:指向cJSON结构体的指针。string:要获取的字段名。
返回值:返回指向cJSON结构体的指针,如果字段不存在则返回NULL。
示例代码:
cJSON *name = cJSON_GetObjectItem(json, "name");
printf("Name: %s\n", name->valuestring);
运行结果
Name: John
`
2.嵌套的json数据,解析下这个json中的gps中的lon字段
#include <stdio.h>
#include "cJSON.h"
int main() {
}
char *json_str = "{\"id\":\"1702723082863\",\"version\":\"1.0\",\"params\":{\"gps\":{\"value\":{\"lon\":112,\"lat\":23}},\"humi\":{\"value\":31},\"lat\":{\"value\":23},\"led_state\":{\"value\":1},\"lng\":{\"value\":23},\"temp\":{\"value\":13}}}";
cJSON *json = cJSON_Parse(json_str);
if (json == NULL) {
printf("Error parsing JSON\n");
return 1;
}
cJSON *params = cJSON_GetObjectItem(json, "params");
cJSON *gps = cJSON_GetObjectItem(params, "gps");
cJSON *value = cJSON_GetObjectItem(gps, "value");
cJSON *lon = cJSON_GetObjectItem(value, "lon");
printf("lon: %d\n", lon->valueint);
cJSON_Delete(json);
return 0;
}
运行结果
lon: 112
3.cJSON_Delete
函数原型:void cJSON_Delete(cJSON *item);
功能描述:释放cJSON结构体所占用的内存。
使用场景:当您不再需要使用cJSON结构体时,应该调用此函数释放内存。
参数说明:item:指向cJSON结构体的指针。
返回值:无。
示例代码:
cJSON_Delete(json);
4.cJSON_Print
函数原型:char *cJSON_Print(const cJSON *item);
功能描述:将cJSON结构体转换为JSON格式的字符串。
使用场景:当您需要将cJSON结构体转换为JSON格式的字符串时,可以使用此函数。
参数说明:item:指向cJSON结构体的指针。
返回值:返回指向JSON格式的字符串的指针。
示例代码:
char *json_str = cJSON_Print(json);
printf("%s\n", json_str);
运行结果:
{"name":"John","age":30,"city":"New York"}
CJSON库的示例代码
#include <stdio.h>
#include "cJSON.h"
int main() {
char *json_str = "{\"name\":\"John\",\"age\":30,\"city\":\"New York\"}";
cJSON *json = cJSON_Parse(json_str);
if (json == NULL) {
printf("Error parsing JSON\n");
return 1;
}
cJSON *name = cJSON_GetObjectItem(json, "name");
cJSON *age = cJSON_GetObjectItem(json, "age");
cJSON *city = cJSON_GetObjectItem(json, "city");
printf("Name: %s\n", name->valuestring);
printf("Age: %d\n", age->valueint);
printf("City: %s\n", city->valuestring);
cJSON_Delete(json);
return 0;
运行结果:
Name: John
Age: 30
City: New York
`
4. 添加cJSON对象到链表
函数原型:cJSON *cJSON_CreateObject(void);
功能描述:创建一个空的cJSON对象。
使用场景:当您需要创建一个新的JSON对象时,可以使用此函数。
参数说明:无。
返回值:返回指向cJSON结构体的指针。
示例代码:
cJSON *object = cJSON_CreateObject();
cJSON_AddStringToObject(object, "name", "John");
cJSON_AddNumberToObject(object, "age", 30);
cJSON_AddStringToObject(object, "city", "New York");
//运行一下这个结果
char *json_str = cJSON_Print(object);
printf("%s\n", json_str);
运行结果:
{"name":"John","age":30,"city":"New York"}
//添加到链表
cJSON *array = cJSON_CreateArray();
cJSON_AddItemToArray(array, object);
//打印链表
char *array_str = cJSON_Print(array);
printf("%s\n", array_str);
运行结果:
[{"name":"John","age":30,"city":"New York"}]
//删除链表
cJSON_Delete(array);
//删除对象
cJSON_Delete(object);
-
cJSON_GetArrayItem
函数原型:cJSON *cJSON_GetArrayItem(const cJSON *array, int item);功能描述:获取数组中指定位置的元素。
使用场景:当您需要获取数组中指定位置的元素时,可以使用此函数。
参数说明:array:指向cJSON数组的指针。item:要获取的元素的位置。
返回值:返回指向cJSON结构体的指针。
示例代码:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main() {
// 创建一个JSON对象
cJSON *root = cJSON_CreateObject();
// 向JSON对象中添加数据
cJSON_AddStringToObject(root, "wxl", "boy");
cJSON_AddNumberToObject(root, "nianling", 20);
cJSON_AddNumberToObject(root, "shengao", 178.0); // 假设身高是浮点数
// 创建一个数组
cJSON *array = cJSON_CreateArray();
cJSON_AddItemToArray(array, cJSON_CreateNumber(1));
cJSON_AddItemToArray(array, cJSON_CreateNumber(3));
cJSON_AddItemToArray(array, cJSON_CreateNumber(5));
cJSON_AddItemToArray(array, cJSON_CreateNumber(7));
cJSON_AddItemToArray(array, cJSON_CreateNumber(9));
// 将数组添加到JSON对象中
cJSON_AddItemToObject(root, "array", array);
// 打印整个JSON对象
char *rendered = cJSON_Print(root);
printf("%s\n", rendered);
// 释放分配的内存
cJSON_Delete(root);
free(rendered);
return 0;
}
运行结果:
{"wxl":"boy","nianling":20,"shengao":178,"array":[1,3,5,7,9]}
实战案例
为了更好地理解CJSON库的应用,我们将通过一个实战案例来展示如何使用CJSON库解析和生成JSON数据。
假设您正在开发一个物联网设备,该设备需要接收来自云端的JSON格式的控制指令,并返回当前状态给云端。我们可以使用CJSON库来解析云端发送的JSON指令,并根据指令内容执行相应的操作
这里使用的是我之前一个项目,用到的云平台是onenet
我收到的是这样的json数据
```json
`{
"title": "属性上报",
"timestamp": "2024-07-05 09:46:21",
"message":
"{\"topic\":\"$sys/squ938zsi0/device_hyw/thing/property/post\",\"data\":{
\"id\":\"1720144597063\",
\"version\":\"1.0\"
,\"params\":
{\"gps\":{\"value\":{\"lon\":115,\"lat\":23}},
\"heart_rate\":{\"value\":113},
\"lat\":{\"value\":112},
\"led_state\":{\"value\":1},
\"lng\":{\"value\":23},
\"n_sp02\":{\"value\":56},
\"old_man_fell_down\":{\"value\":1},
\"old_temp\":{\"value\":37}
}
}
}"
}
```
当解析到led_state等于1时候,进入自动模式,PC13的led灯打开,led_state等于0时候,进入手动模式,同时打印输出当前的心率、血氧、温度、经纬度、老人跌倒状态
void OneNet_RevPro(unsigned char *cmd)
{
char *req_payload = NULL;
char *cmdid_topic = NULL;
unsigned short topic_len = 0;
unsigned short req_len = 0;
unsigned char qos = 0;
static unsigned short pkt_id = 0;
unsigned char type = 0;
short result = 0;
cJSON *root = NULL;
cJSON *params = NULL;
cJSON *led_state_obj = NULL;
type = MQTT_UnPacketRecv(cmd);
switch(type)
{
case MQTT_PKT_PUBLISH:
result = MQTT_UnPacketPublish(cmd, &cmdid_topic, &topic_len, &req_payload, &req_len, &qos, &pkt_id);
if(result == 0)
{
root = cJSON_Parse(req_payload);
if (root != NULL)
{
// 假设 message 是一个包含完整 JSON 数据的字符串
cJSON *message_obj = cJSON_GetObjectItemCaseSensitive(root, "message");
if (cJSON_IsString(message_obj) && (message_obj->valuestring != NULL))
{
cJSON *inner_root = cJSON_Parse(message_obj->valuestring);
if (inner_root != NULL)
{
params = cJSON_GetObjectItemCaseSensitive(inner_root, "data");
if (params != NULL)
{
led_state_obj = cJSON_GetObjectItemCaseSensitive(params, "led_state");
if (led_state_obj != NULL && cJSON_IsNumber(led_state_obj))
{
int led_state = led_state_obj->valueint;
if (led_state == 1)
{
// 进入自动模式,打开 LED
LED_Control(GPIOC, GPIO_Pin_13, Enable);
}
else if (led_state == 0)
{
// 进入手动模式,关闭 LED(如果需要)
LED_Control(GPIOC, GPIO_Pin_13, Disable);
// 打印输出
printf("LED is off, manual mode\n");
}
}
// ... 其他参数处理 ...
//当前的心率
heart_rate_obj = cJSON_GetObjectItemCaseSensitive(params, "heart_rate");
if (heart_rate_obj != NULL && cJSON_IsNumber(heart_rate_obj))
{
int heart_rate = heart_rate_obj->valueint;
// 打印输出
printf("Heart rate: %d\n", heart_rate);
}
}
cJSON_Delete(inner_root);
}
}
cJSON_Delete(root);
}
}
MQTT_FreeBuffer(req_payload);
break;
// ... 其他 case ...
}
MQTT_FreeBuffer(cmdid_topic);
ESP8266_Clear();
}
参考文章
总结
我们详细讲解了CJSON库的核心函数,包括如何创建JSON对象、添加键值对、解析JSON字符串以及遍历JSON对象等,为读者打下了坚实的理论基础。随后,通过实际操作解析OneNET平台返回的JSON数据,希望本教程能够对大家在物联网开发过程中有所帮助。最后呢,在编写博客的过程中,我尽量保持内容的准确性和完整性,但也难免会有疏漏或错误之处。欢迎各位读者指出其中的问题,帮助我不断进步。谢谢大家的阅读,