cJSON用法闹击,轉(zhuǎn)載

最近在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é)束了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末楷掉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子霞势,更是在濱河造成了極大的恐慌烹植,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件愕贡,死亡現(xiàn)場離奇詭異草雕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)固以,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進(jìn)店門促绵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嘴纺,你說我怎么就攤上這事败晴。” “怎么了栽渴?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵尖坤,是天一觀的道長。 經(jīng)常有香客問我闲擦,道長慢味,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任墅冷,我火速辦了婚禮纯路,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘寞忿。我一直安慰自己驰唬,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著叫编,像睡著了一般辖佣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上搓逾,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天卷谈,我揣著相機(jī)與錄音,去河邊找鬼霞篡。 笑死世蔗,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的朗兵。 我是一名探鬼主播凸郑,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼矛市!你這毒婦竟也來了芙沥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤浊吏,失蹤者是張志新(化名)和其女友劉穎而昨,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體找田,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡歌憨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了墩衙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片务嫡。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖漆改,靈堂內(nèi)的尸體忽然破棺而出心铃,到底是詐尸還是另有隱情,我是刑警寧澤挫剑,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布去扣,位于F島的核電站,受9級特大地震影響樊破,放射性物質(zhì)發(fā)生泄漏愉棱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一哲戚、第九天 我趴在偏房一處隱蔽的房頂上張望奔滑。 院中可真熱鬧,春花似錦顺少、人聲如沸朋其。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽令宿。三九已至,卻和暖如春腕窥,著一層夾襖步出監(jiān)牢的瞬間粒没,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工簇爆, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留癞松,地道東北人。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓入蛆,卻偏偏與公主長得像响蓉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子哨毁,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,728評論 2 351

推薦閱讀更多精彩內(nèi)容