作者:王超
首发:电子电路开发学习
前言
之前我曾经写过几个JSON解析库的使用方法:
对于嵌入式开发,比较常用的就是cJSON解析库了,但是使用这个库对内存开销比较大,需要大量使用malloc和free进行动态内存分配和释放。对于单片机这种资源短缺的芯片来说,简直是太吃力了。使用STM32等单片机,不能解析多层JSON时,还需要调大堆栈。
今天来了解一下一个和cJSON非常类似的解析库——Jansson的使用,支持解析和构建JSON字符串,不需要动态分配内存,使用方法和cJSON几乎一样。
本文以Keil环境下的Jansson为例,介绍多种不同格式的JSON字符串解析。
示例工程下载:whik1194-JanssonDemo.rar
Jansson的安装
Jansson的安装非常简单,到Keil官网下载一个Jansson的Pack包即可: Keil.Jansson.1.0.0.pack,点击直接下载。
安装完成之后,如果要在当前项目中添加Jansson解析库,在Keil中勾选上Jansson即可,选择完成之后,在当前工程下会出现两个文件:jansson_CM3LE.lib
和jansson_config.c
。
在要使用的文件中包含头文件:#include <jansson.h>
为了方便调试,自定义实现了一个串口格式化输出函数:LOG1。
void LOG1(char *fmt,...)
{
unsigned char UsartPrintfBuf[296];
va_list ap;
unsigned char *pStr = UsartPrintfBuf;
va_start(ap, fmt);
vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap); //格式化
va_end(ap);
while(*pStr != 0)
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
USART_SendData(USART1, *pStr++);
}
}
示例1:纯键值对
JSON字符串,包括字符串、整形和布尔类型三种类型的键值对:
{
"status": true,
"age": 20,
"name": "whik1194",
"blog": "https://blog.csdn.net/whik1194",
"wechat": "mcu149"
}
解析函数:
uint8_t Jansson1_Demo(void)
{
const char *text = "{\"status\":true,\"age\":20,\"score\":78.4,\"name\":\"whik1194\",\"blog\":\"https://blog.csdn.net/whik1194\",\"wechat\":\"mcu149\"}";
json_error_t error;
json_t *root;
json_t *status;
char *name, *blog, *wechat;
int age;
double score;
root = json_loads((const char*)text, 0, &error);
if(json_is_object(root))
{
LOG1("root format correct\r\n");
/* string 类型的解析 */
name = (char *)json_string_value(json_object_get(root, "name"));
blog = (char *)json_string_value(json_object_get(root, "blog"));
wechat = (char *)json_string_value(json_object_get(root, "wechat"));
LOG1("name: %s\r\n", name);
LOG1("blog: %s\r\n", blog);
LOG1("wechat: %s\r\n", wechat);
/* int 类型的解析 */
age = json_integer_value(json_object_get(root, "age"));
LOG1("age: %d\r\n", age);
/* double 类型的解析 */
score = json_real_value(json_object_get(root, "score"));
LOG1("score: %.1f\r\n", score);
/* bool 类型的解析 */
status = json_object_get(root, "status");
if(json_is_true(status))
LOG1("status: true\r\n");
else if(json_is_false(status))
LOG1("status: false\r\n");
}
else
{
printf("root format error:%d-%s\r\n", error.line, error.text);
return 1;
}
return 0;
}
运行结果:
示例2:键的值是一个对象
JSON字符串,其中result键的值是一个JSON对象,包括几组键值对:
{
"success": "1",
"result": {
"timestamp": "1592640249",
"datetime_1": "2020-06-20 16:04:09",
"week_1": "6",
"week_2": "Saturday"
}
}
解析函数:
uint8_t Jansson2_Demo(void)
{
const char *text = "{\"success\":\"1\",\"result\":{\"timestamp\":\"1592640249\",\"datetime_1\":\"2020-06-20 16:04:09\",\"week_1\":\"6\",\"week_2\":\"Saturday\"}}";
json_error_t error;
json_t *root;
json_t *result;
char *success;
char *timestamp;
char *datetime_1;
char *week_1;
root = json_loads((const char*)text, 0, &error);
if(json_is_object(root))
{
LOG1("root format correct\r\n");
success = (char *)json_string_value(json_object_get(root, "success"));
LOG1("success:%s\r\n", success);
result = json_object_get(root, "result");
if(json_is_object(result))
{
timestamp = (char *)json_string_value(json_object_get(result, "timestamp"));
datetime_1 = (char *)json_string_value(json_object_get(result, "datetime_1"));
week_1 = (char *)json_string_value(json_object_get(result, "week_1"));
LOG1("timestamp:%s\r\n", timestamp);
LOG1("datetime_1:%s\r\n", datetime_1);
LOG1("week_1:%s\r\n", week_1);
}
else
{
LOG1("reuslt format error\r\n");
return 1;
}
}
else
{
LOG1("root format error:%d-%s\r\n", error.line, error.text);
return 1;
}
return 0;
}
运行结果:
示例3:键的值是一个数组
JSON字符串,键的值是一个JSON数组,包含两个JSON对象:
{
"location": [{
"name": "Faye",
"address": "Beijing"
}, {
"name": "Andy",
"address": "ShangHai"
}, {
"name": "Lisa",
"address": "ShenZhen"
}],
"time": "2018-11-17"
}
解析函数:
uint8_t Jansson3_Demo(void)
{
const char *text = "{\"location\":[{\"name\":\"Faye\",\"address\":\"Beijing\"},{\"name\":\"Andy\",\"address\":\"ShangHai\"},{\"name\":\"Lisa\",\"address\":\"ShenZhen\"}],\"time\":\"2018-11-17\"}";
json_error_t error;
json_t *root;
json_t *location_arr;
json_t *location;
char *name, *address;
char *time;
int idx;
root = json_loads((const char*)text, 0, &error);
if(json_is_object(root))
{
LOG1("root format correct\r\n");
time = (char *)json_string_value(json_object_get(root, "time"));
location_arr = json_object_get(root, "location");
if(json_is_array(location_arr))
{
for(idx = 0; idx < json_array_size(location_arr); idx++)
{
location = json_array_get(location_arr, idx);
name = (char *)json_string_value(json_object_get(location, "name"));
address = (char *)json_string_value(json_object_get(location, "address"));
LOG1("%d: %s-%s\r\n", idx, name, address);
}
}
}
else
{
LOG1("root format error:%d-%s\r\n", error.line, error.text);
return 1;
}
return 0;
}
运行结果:
注意
如果出现解析失败,或者解析错误,可以尝试增加Heap\_Size大小:
不知道是不是编码的问题,Jansson并不支持含有中文的JSON字符串解析,会报格式错误。
示例工程下载:whik1194-JanssonDemo.rar
推荐阅读
- Keil开发环境如何生成BIN文件
- 我用STM32MP1做了个疫情监控平台1—交叉编译环境搭建
- 我用STM32MP1做了个疫情监控平台2—Qt环境搭建
- 我用STM32MP1做了个疫情监控平台3—疫情监控平台实现
- 我用STM32MP1做了个疫情监控平台4—功能完善界面重新设计
欢迎关注公众号:电子电路开发学习,id:mcu149。
更多电子电路、单片机、嵌入式、物联网等技术文章欢迎关注电子电路开发学习专栏。