最近在stm32f103上做一個智能家居的項目,其中選擇的實時操作系統(tǒng)是 rt_thread OS v1.2.2穩(wěn)定版本凹联,其中涉及到C和java(android)端數(shù)據(jù)的交換問題沐兰,經(jīng)過討論和研究,選擇了json格式的數(shù)據(jù)進(jìn)行交互蔽挠。當(dāng)然住闯,如果自己去寫一個json解析器,有點重造輪子的嫌疑澳淑。于是使用了開源的json解析器比原。考慮到是嵌入式平臺杠巡,在一位朋友的推薦下春寿,選擇了輕量級別的cJSON。
cJSON 開源項目位置: http://sourceforge.net/projects/cjson/
cJSON忽孽,目前來說绑改,就只有兩個文件谢床,一個cJSON.c 一個cJSON.h文件。使用的時候厘线,自己創(chuàng)建好一個main.c文件后识腿,如果是在linux pc上,請使用以下命令進(jìn)行編譯:
gcc -g -Wall *.c -l m
就會默認(rèn)生成一個 a.out文件造壮,執(zhí)行即可渡讼。在linux下編譯的時候,注意鏈接 libm 庫耳璧。
整個項目都是以極標(biāo)準(zhǔn)的C來寫的成箫,意思說,可以跨各種平臺使用了旨枯。不過蹬昌,還是有兩三處需要微調(diào)一下<針對stm32f103 + rt_thread >。其中修改一下malloc & free & size_t 這三個東西:
46 static void *(*cJSON_malloc)(size_t sz) = malloc;
47 static void (*cJSON_free)(void *ptr) = free;
----------------------------------------
46 static void *(*cJSON_malloc)(size_t sz) = rt_malloc;
47 static void (*cJSON_free)(void *ptr) = rt_free;
46 static void *(*cJSON_malloc)(size_t sz) = malloc;
47 static void (*cJSON_free)(void *ptr) = free;
----------------------------------------
46 static void *(*cJSON_malloc)(size_t sz) = rt_malloc;
47 static void (*cJSON_free)(void *ptr) = rt_free;
free & malloc就這么兩個地方要修改一下吧攀隔,其中size_t 這個應(yīng)該是在 .h 文件修改皂贩,主要是rtt的 rt_malloc 和這里的malloc使用的不同,所以修改了下---不一定非要修改昆汹。
所以明刷,這東西說實話,也不存在什么移植不移植的問題了满粗。很輕松的就可以在各個平臺使用了辈末。
不對json的格式進(jìn)行說明了,下面直接記下使用方法了映皆。
第一挤聘,創(chuàng)建json數(shù)據(jù)串。這數(shù)據(jù)串劫扒,可能是對象檬洞,也可能是數(shù)組狸膏,也可能是它們的各種組合沟饥,其中再加上一些鍵值對。有一點要先說明:它們的組合湾戳,符合父子繼承格式--這也是json數(shù)據(jù)串的特點贤旷。
<1> 創(chuàng)建一個對象,并在這個對象里面添加一個字符串鍵值和一個數(shù)字鍵值:
int create_js(void)
{
cJSON *root;
/*create json string root*/
root = cJSON_CreateObject();
if(!root) {
DEBUG("get root faild !\n");
goto EXIT;
}else DEBUG("get root success!\n");
{
cJSON * js_body ;
const char *const body = "body";
cJSON_AddItemToObject(root, body, js_body=cJSON_CreateObject());
cJSON_AddStringToObject(js_body,"name","xiaohui");
cJSON_AddNumberToObject(js_body,"value",600);
{
char *s = cJSON_PrintUnformatted(root);
if(s){
DEBUG("create js string is %s\n",s);
free(s);
}
}
cJSON_Delete(root);
}
return 0;
EXIT:
return -1;
}
int main(int argc, char **argv)
{
create_js();
return 0;
}
運行結(jié)果:
create js string is {"body":{"name":"xiaohui","value":600}}
說明: 創(chuàng)建根對象砾脑,使用 cJSON_CreateObject(); 這個API幼驶,返回的是一個 cJSON的指針,注意韧衣,在這個指針用完了以后盅藻,需要手工調(diào)用 cJSON_Delete(root); 進(jìn)行內(nèi)存回收购桑。
創(chuàng)建body對象的時候,是在根對象的基礎(chǔ)上進(jìn)行創(chuàng)建氏淑,而插入name 和value的時候勃蜘,是以body為父節(jié)點。需要注意的是 json 格式的數(shù)據(jù)假残,雖然也是一個字符串的樣子缭贡,但這個時候還是無法當(dāng)成普通的字符串進(jìn)行使用,需要調(diào)用 cJSON_PrintUnformatted(root) 或者 cJSON_Print(root);來將json對象轉(zhuǎn)換成普通的字符串辉懒,并且都是以該json對象的根為基點阳惹。兩個API的區(qū)別即是:一個是沒有格式的:也就是轉(zhuǎn)換出的字符串中間不會有"\n" "\t"之類的東西存在,而cJSON_Print(root);打印出來是人看起來很舒服的格式眶俩。僅此而已莹汤。
<2> 創(chuàng)建一個數(shù)組,并向數(shù)組添加一個字符串和一個數(shù)字:
int create_js(void)
{
cJSON *root, *js_body;
root = cJSON_CreateArray();
cJSON_AddItemToArray(root, cJSON_CreateString("Hello world"));
cJSON_AddItemToArray(root, cJSON_CreateNumber(10));
{
// char *s = cJSON_Print(root);
char *s = cJSON_PrintUnformatted(root);
if(s){
DEBUG(" %s \n",s);
free(s);
}
}
if(root)
cJSON_Delete(root);
return 0;
EXIT:
return -1;
}
int main(int argc, char **argv)
{
create_js();
return 0;
}
運行結(jié)果:
1 ["Hello world",10]
<3> 對象里面包括一個數(shù)組仿便,數(shù)組里面包括對象体啰,對象里面再添加一個字符串和一個數(shù)字:
int create_js(void)
{
cJSON *root, *js_body, *js_list;
root = cJSON_CreateObject();
cJSON_AddItemToObject(root,"body", js_body = cJSON_CreateArray());
cJSON_AddItemToArray(js_body, js_list = cJSON_CreateObject());
cJSON_AddStringToObject(js_list,"name","xiaohui");
cJSON_AddNumberToObject(js_list,"status",100);
{
// char *s = cJSON_Print(root);
char *s = cJSON_PrintUnformatted(root);
if(s){
DEBUG(" %s \n",s);
free(s);
}
}
if(root)
cJSON_Delete(root);
return 0;
EXIT:
return -1;
}
int main(int argc, char **argv)
{
create_js();
return 0;
}
運行結(jié)果:
1 {"body":[{"name":"xiaohui","status":100}]}
<4>其他組合就依次類推,只要搞清楚父子關(guān)系即可嗽仪。隨便嵌套隨便玩荒勇。不再貼了。
<第二闻坚, 解析json數(shù)據(jù)串>
步驟: 1 先將普通的json 字符串 處理成 json對象格式沽翔。 2 根據(jù)關(guān)鍵字進(jìn)行解析,解析的時候窿凤,需要根據(jù)關(guān)鍵字值的類型進(jìn)行判斷仅偎,而這些類型,已經(jīng)在cJSON.h里面寫明白了雳殊,包括:對象橘沥、數(shù)組、普通字符串夯秃、普通變量等等座咆。
<偷個懶吧,將自己學(xué)習(xí)的時候用的資料現(xiàn)貼過來仓洼,后面休息一下再詳細(xì)補(bǔ)充自己在工程中的解析方法>
http://blog.csdn.net/xukai871105/article/details/17094113
http://blog.sina.com.cn/s/blog_a6fb6cc90101ffme.html
<當(dāng)然介陶,他寫的比較簡潔,還有些可以補(bǔ)充的---其實我已經(jīng)在上面使用文字進(jìn)行補(bǔ)充過了色建。當(dāng)然哺呜,不同的工程,可能解析的方法和側(cè)重點并不相同>
或許箕戳,是時候把解析的部分補(bǔ)充上來了:
處理流程:
1某残, 先將普通的json串處理成json對象国撵,也就是所謂的創(chuàng)建json root的過程,只有一行代碼即可:
cJSON *root;
root = cJSON_Parse(js_string);
ps:需要注意的是玻墅,這個root在解析完成后卸留,需要釋放掉,代碼如下:
if (root)
cJSON_Delete(root);
2椭豫,開始拿關(guān)鍵字耻瑟,但如果關(guān)鍵字還有父層或者祖層,那就需要先從父層開拿赏酥,所謂剝洋蔥是也喳整!
先說沒有父層的:
{"name":"xiaohong","age":10}
這個字符串這樣拿即可:
char *s = "{\"name\":\"xiao hong\",\"age\":10}";
cJSON *root = cJSON_Parse(s);
if(!root) {
printf("get root faild !\n");
return -1;
}
cJSON *name = cJSON_GetObjectItem(root, "name");
if(!name) {
printf("No name !\n");
return -1;
}
printf("name type is %d\n",name->type);
printf("name is %s\n",name->valuestring);
cJSON *age = cJSON_GetObjectItem(root, "age");
if(!age) {
printf("no age!\n");
return -1;
}
printf("age type is %d\n", age->type);
printf("age is %d\n",age->valueint);
顯示結(jié)果:
1 name type is 4
2 name is xiao hong
3 age type is 3
4 age is 10
需要注意的是: 上面的type 已經(jīng)在cJSON.h里面定義好了,有自己的意義裸扶。如果是在嚴(yán)格的場所框都,應(yīng)該先判定該 item的type,然后再考慮去拿值呵晨。
而如果有父層的話魏保,無非就是接著向下拿就是了,稍微修改下前面的demo吧:
處理這串?dāng)?shù)據(jù)吧:
{\"list\":{\"name\":\"xiao hong\",\"age\":10},\"other\":{\"name\":\"hua hua\"}}
char *s = "{\"list\":{\"name\":\"xiao hong\",\"age\":10},\"other\":{\"name\":\"hua hua\"}}";
cJSON *root = cJSON_Parse(s);
if(!root) {
printf("get root faild !\n");
return -1;
}
cJSON *js_list = cJSON_GetObjectItem(root, "list");
if(!js_list) {
printf("no list!\n");
return -1;
}
printf("list type is %d\n",js_list->type);
cJSON *name = cJSON_GetObjectItem(js_list, "name");
if(!name) {
printf("No name !\n");
return -1;
}
printf("name type is %d\n",name->type);
printf("name is %s\n",name->valuestring);
cJSON *age = cJSON_GetObjectItem(js_list, "age");
if(!age) {
printf("no age!\n");
return -1;
}
printf("age type is %d\n", age->type);
printf("age is %d\n",age->valueint);
cJSON *js_other = cJSON_GetObjectItem(root, "other");
if(!js_other) {
printf("no list!\n");
return -1;
}
printf("list type is %d\n",js_other->type);
cJSON *js_name = cJSON_GetObjectItem(js_other, "name");
if(!js_name) {
printf("No name !\n");
return -1;
}
printf("name type is %d\n",js_name->type);
printf("name is %s\n",js_name->valuestring);
if(root)
cJSON_Delete(root);
return 0;
打印結(jié)果:
1 list type is 6
2 name type is 4
3 name is xiao hong
4 age type is 3
5 age is 10
6 list type is 6
7 name type is 4
8 name is hua hua
所謂子子孫孫無窮盡也摸屠,按照上面那個方法推下去即可谓罗。
3,json 里數(shù)組怎么燃径檩咱?
1 {\"list\":[\"name1\",\"name2\"]}
int main(int argc, char **argv)
{
char *s = "{\"list\":[\"name1\",\"name2\"]}";
cJSON *root = cJSON_Parse(s);
if(!root) {
printf("get root faild !\n");
return -1;
}
cJSON *js_list = cJSON_GetObjectItem(root, "list");
if(!js_list){
printf("no list!\n");
return -1;
}
int array_size = cJSON_GetArraySize(js_list);
printf("array size is %d\n",array_size);
int i = 0;
cJSON *item;
for(i=0; i< array_size; i++) {
item = cJSON_GetArrayItem(js_list, i);
printf("item type is %d\n",item->type);
printf("%s\n",item->valuestring);
}
if(root)
cJSON_Delete(root);
return 0;
}
對頭,好簡單的樣子<在別人的庫上使用>
4 如果json數(shù)組里面又搞了對象怎么辦胯舷?
不怕搞對象刻蚯,就怕這樣搞對象? 無他桑嘶,就是稍微復(fù)雜了一點炊汹,全是體力活兒:
<1> 既然是數(shù)組里面,那肯定要先測量數(shù)組的大小逃顶,然后根據(jù)大小循環(huán)拿讨便;
<2> 拿到一個數(shù)組項,然后把這個項先轉(zhuǎn)化成普通的json字符串口蝠,也就是 char *s 能接受的器钟。
<3>再次將這個json字符串津坑,轉(zhuǎn)化成一個json對象
<4> 按照拿普通對象中的東西那樣開干就行了妙蔗。
ps:曾經(jīng)試過直接在數(shù)組項中拿內(nèi)容,失敗了疆瑰,不知為何眉反,于是就按照這個4步開干了昙啄。
比如:
1 {\"list\":[{\"name\":\"xiao hong\",\"age\":10},{\"name\":\"hua hua\",\"age\":11}]}
是的.list 是一個數(shù)組,數(shù)組里面有兩個對象寸五,那么代碼如下:
int main(int argc, char **argv)
{
char *s = "{\"list\":[{\"name\":\"xiao hong\",\"age\":10},{\"name\":\"hua hua\",\"age\":11}]}";
cJSON *root = cJSON_Parse(s);
if(!root) {
printf("get root faild !\n");
return -1;
}
cJSON *js_list = cJSON_GetObjectItem(root, "list");
if(!js_list){
printf("no list!\n");
return -1;
}
int array_size = cJSON_GetArraySize(js_list);
printf("array size is %d\n",array_size);
int i = 0;
cJSON *item,*it, *js_name, *js_age;
char *p = NULL;
for(i=0; i< array_size; i++) {
item = cJSON_GetArrayItem(js_list, i);
if(!item) {
//TODO...
}
p = cJSON_PrintUnformatted(item);
it = cJSON_Parse(p);
if(!it)
continue ;
js_name = cJSON_GetObjectItem(it, "name");
printf("name is %s\n",js_name->valuestring);
js_age = cJSON_GetObjectItem(it, "age");
printf("age is %d\n",js_age->valueint);
}
if(root)
cJSON_Delete(root);
return 0;
}
按理說梳凛,應(yīng)該釋放下 it 變量才對,但似乎事實不是這樣梳杏,僅僅可以釋放根root韧拒。
好了,json 解析十性,無非就是上面的組合了叛溢,還能有什么呢?
解析和封裝都有了劲适,此文結(jié)束了