物联网数据解析实战:掌握CJSON库核心函数,精准处理JSON数据

物联网数据解析实战:掌握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库的解析函数

  1. 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"
    }
  2. 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);
  1. 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();  
}  

参考文章

  1. C语言中cJSON的使用
  2. C语言利用cJSON解析JSON格式全过程

总结

我们详细讲解了CJSON库的核心函数,包括如何创建JSON对象、添加键值对、解析JSON字符串以及遍历JSON对象等,为读者打下了坚实的理论基础。随后,通过实际操作解析OneNET平台返回的JSON数据,希望本教程能够对大家在物联网开发过程中有所帮助。最后呢,在编写博客的过程中,我尽量保持内容的准确性和完整性,但也难免会有疏漏或错误之处。欢迎各位读者指出其中的问题,帮助我不断进步。谢谢大家的阅读,

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

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

相关文章

部署Gunicorn + Flask应用到Docker

部署Gunicorn Flask应用到Docker中涉及几个步骤&#xff0c;下面是一个基本的指南&#xff1a; 1. 创建Flask应用 首先&#xff0c;确保你有一个可用的Flask应用。这里有一个简单的示例&#xff1a; from flask import Flask app Flask(__name__)app.route(/) def hello_w…

pandas,dataframe使用笔记

目录 新建一个dataframe不带列名带列名 dataframe添加一行内容查看dataframe某列的数据类型新建dataframe时设置了列名&#xff0c;则数据类型为object dataframe的保存保存为csv文件保存为excel文件 dataframe属于pandas 新建一个dataframe 不带列名 df pd.DataFrame() 带…

GuLi商城-商品服务-API-品牌管理-效果优化与快速显示开关

<template><div class"mod-config"><el-form :inline"true" :model"dataForm" keyup.enter.native"getDataList()"><el-form-item><el-input v-model"dataForm.key" placeholder"参数名&qu…

华为交换机 LACP协议

华为交换机支持的LACP协议&#xff0c;即链路聚合控制协议&#xff0c;是一种基于IEEE 802.3ad标准的动态链路聚合与解聚合的协议。它允许设备根据自身配置自动形成聚合链路并启动聚合链路收发数据。 在LACP模式下&#xff0c;链路聚合组能够自动调整链路聚合&#xff0c;维护…

java集合(1)

目录 一.集合概述 二. 集合体系概述 1. Collection接口 1.1 List接口 1.2 Set接口 2. Map接口 三. ArrayList 1.ArrayList常用方法 2.ArrayList遍历 2.1 for循环 2.2 增强for循环 2.3 迭代器遍历 一.集合概述 我们经常需要存储一些数据类型相同的元素,之前我们学过…

Java 基础语法

Java 是一种面向对象的编程语言&#xff0c;具有简单、健壮、安全、跨平台等特点。下面是Java基础语法的详细介绍&#xff0c;并附带一些示例说明&#xff1a; ### 1. 变量和数据类型 Java 中的变量用于存储数据&#xff0c;必须先声明后使用。Java 的数据类型分为基本数据类…

C++ 仿QT信号槽二

// 实现原理 // 每个signal映射到bitset位&#xff0c;全集 // 每个slot做为signal的bitset子集 // signal全集触发&#xff0c;标志位有效 // flip将触发事件队列前置 // slot检测智能指针全集触发的标志位&#xff0c;主动运行子集绑定的函数 // 下一帧对bitset全集进行触发清…

【C++】 解决 C++ 语言报错:Segmentation Fault

文章目录 引言 段错误&#xff08;Segmentation Fault&#xff09;是 C 编程中常见且令人头疼的错误之一。段错误通常发生在程序试图访问未被允许的内存区域时&#xff0c;导致程序崩溃。本文将深入探讨段错误的产生原因、检测方法及其预防和解决方案&#xff0c;帮助开发者在…

Lex Fridman Podcast with Andrej Karpathy

我不太喜欢Lex Fridman的声音&#xff0c;总觉得那让人昏昏欲睡&#xff0c; 但无奈他采访的人都太大牌了&#xff0c;只能去听。但是听着听着&#xff0c;就会觉得有深度的采访这些人&#xff0c;似乎也只有他这种由研究员背景的人能干&#xff0c; 另&#xff0c;他提的问题确…

4.2 投影

一、投影和投影矩阵 我们以下面两个问题开始&#xff0c;问题一是为了展示投影是很容易视觉化的&#xff0c;问题二是关于 “投影矩阵”&#xff08;projection matrices&#xff09;—— 对称矩阵且 P 2 P P^2P P2P。 b \boldsymbol b b 的投影是 P b P\boldsymbol b Pb。…

android的dump_processe中anon和swap字段的含义是什么?计算进程占用内存大小是否可以用这两个字段相加?

在Android系统中&#xff0c;dump_processes 命令或类似机制&#xff08;如通过 adb shell dumpsys&#xff09;的输出中&#xff0c;可能会包含与进程内存使用相关的信息&#xff0c;但通常不直接以 anon 和 swap 作为字段名。不过&#xff0c;基于您的提问&#xff0c;我可以…

嵌入式学习——硬件(Linux内核驱动编程LED、蜂鸣器、按键)——day59

1. 编写LED驱动&#xff08;初始化所有子设备号&#xff09; #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <asm/uaccess.h> #include <asm/io.h>#define GPBCON (0x5…

2024年7月5日 (周五) 叶子游戏新闻

老板键工具来唤去: 它可以为常用程序自定义快捷键&#xff0c;实现一键唤起、一键隐藏的 Windows 工具&#xff0c;并且支持窗口动态绑定快捷键&#xff08;无需设置自动实现&#xff09;。 卸载工具 HiBitUninstaller: Windows上的软件卸载工具 《乐高地平线大冒险》为何不登陆…

江汉大学刘春萌同学整理的wifi模块 上传mqtt实验步骤

一.固件烧录 1.打开安信可官网 2.点击wifi模组系列的ESP8266 3.点击各类固件后选择固件号1471下载 4.打开烧录工具将下载的二进制文件导入并将后面的起始地址写为0x00000,下面勾选40mhz QIO 8Mbit点击start下载即可 二.本地部署mqtt服务器(windows) 1.下载mosquitto后有一个m…

Java并发编程知识整理笔记

目录 ​1. 什么是线程和进程&#xff1f; 线程与进程有什么区别&#xff1f; 那什么是上下文切换&#xff1f; 进程间怎么通信&#xff1f; 什么是用户线程和守护线程&#xff1f; 2. 并行和并发的区别&#xff1f; 3. 创建线程的几种方式&#xff1f; Runnable接口和C…

微博视频下载

video_urls 获取xpath://video/src|//video/autoplay # !/usr/bin/python3 # -*- coding:utf-8 -*- """ author: JHC000abcgmail.com file: demo1.py time: 2024/6/3 18:00 desc:""" import os import re import requests from urllib.parse im…

Qt实现流动的管道效果代码示例

在现代图形用户界面&#xff08;GUI&#xff09;应用程序中&#xff0c;动态效果可以显著增强用户体验。本文将介绍如何使用Qt框架实现一个流动的管道效果。我们将通过自定义QWidget来绘制管道&#xff0c;并使用定时器来实现流动效果。 1. 准备工作 首先&#xff0c;确保你已…

LeetCode.68文本左右对齐

问题描述 给定一个单词数组 words 和一个长度 maxWidth &#xff0c;重新排版单词&#xff0c;使其成为每行恰好有 maxWidth 个字符&#xff0c;且左右两端对齐的文本。 你应该使用 “贪心算法” 来放置给定的单词&#xff1b;也就是说&#xff0c;尽可能多地往每行中放置单词…

HMI 的 UI 风格创造奇迹

HMI 的 UI 风格创造奇迹

Table-driven Declarative Rewrite Rule (DRR)

Table-driven Declarative Rewrite Rule (DRR 好处规则定义原模式基于位置的匹配操作的匹配有向无环图&#xff08;DAG&#xff09;(AOp (BOp), $attr): 绑定操作的结果 好处 模式创建者只需要声明性地指定重写模式&#xff0c;而不必担心调用具体的C方法。 消除样板代码&…