在做物聯網應用中,需要和服務器做通信,經常使用json格式。
cjson是常用的解析庫,功能強大。
https://github.com/DaveGamble/cJSON
jsmn利用了零拷貝,減少了內存的使用,適合小資源嵌入式系統。
https://github.com/zserge/jsmn
下面直接從使用角度進行對比:
解析
cjson:開箱即用
cJSON* json = cJSON_Parse(json_str);
jsmn:需要提前定義好足夠的token數量
jsmntok_t tokens[256];
jsmn_parser parser;
jsmn_init(&parser);
int num = jsmn_parse(&parser, json_str, strlen(json_str), tokens, 256);
獲取對象
cjson:
cJSON* sn = cJSON_GetObjectItemCaseSensitive(json, "sn");
jsmn:
jsmntok_t* sn;
for(int i = 0; i < num; i++) { //並不能排除子對象中重名的值
jsmntok_t* t = &tokens[i];
jsmn_get_item(json_str, t, "sn", &sn);
}
獲取數值
cjson:使用指針
jsmn:原字符串需要一直傳遞下來
字符串
cjson:
if(cJSON_IsString(sn) && (sn->valuestring != NULL))
{
PRINTLN("sn:%s", sn->valuestring);
}
jsmn:無法得到0結尾的完整字符串
if(jsmn_is_string(json_str, sn))
{
uint8_t* sn_ptr;
uint8_t sn_len;
jsmn_get_string(json_str, sn__, &sn_ptr, &sn_len);
PRINTLN("sn:%.*s", sn_len, sn_ptr);
}
數字
cjson:
if(cJSON_IsNumber(spo2))
{
PRINTLN("spo2:%d", spo2->valueint);
}
jsmn:
if(jsmn_is_number(json_str, spo2))
{
PRINTLN("spo2:%d", jsmn_get_number(json_str, spo2));
}
浮點
cjson:
if(cJSON_IsNumber(volt))
{
PRINTLN("volt:%f", volt->valuedouble);
}
jsmn:
if(jsmn_is_float(json_str, volt))
{
PRINTLN("volt:%f", jsmn_get_float(json_str, volt));
}
數組
cjson:
cJSON* gyro;
if(cJSON_IsArray(gyros))
{
PRINT("gyro(%d):", cJSON_GetArraySize(gyros));
cJSON_ArrayForEach(gyro gyros)
{
if(cJSON_IsNumber(gyro))
{
PRINT("%d,", gyro->valueint);
}
}
PRINT("\n");
}
jsmn:
if(jsmn_is_array(json_str, gyros))
{
PRINT("gyro(%d):", jsmn_get_array_len(json_str, gyros));
for(uint8_t i = 0; i < jsmn_get_array_len(json_str, gyros); i++) {
jsmntok_t* gyro;
jsmn_get_array_item(json_str, gyros, i, &gyro);
if(jsmn_get_number(json_str, gyro))
{
PRINT("%d,", jsmn_get_number(json_str, gyro));
}
}
PRINT("\n");
}
子對象獲取
cjson:
cJSON* irs = cJSON_GetObjectItemCaseSensitive(ppg, "ir");
cJSON* reds = cJSON_GetObjectItemCaseSensitive(ppg, "red");
jsmn:
jsmntok_t* irs;
jsmntok_t* reds;
for(int i = 0; i < jsmn_get_object_token_num(json_str, ppg); i++) {
jsmntok_t* t = &ppg[i];
jsmn_get_item(json_str, t, "ir" , &irs);
jsmn_get_item(json_str, t, "red", &reds);
}
小結
jsmn雖然看起來高效和資源使用少,但是太原始。解析無嵌套無數組的json很方便,如果json嵌套比較複雜,解析代碼看起來就很麻煩。
cjson代碼寫得稍微深奧,封裝過多,不太適合小資源的嵌入式用。內存使用稍大,因為把原數據全都做了值拷貝。但優點是各對象使用了鏈表,對於嵌套的json處理方便。