前言
之前我曾經寫過幾個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