轉自:https://blog.csdn.net/qimi123456/article/details/80426474
json-c 庫中是在嵌入式開發中常用的庫。因爲很多地方都以json數據數據交互協議, 尤其嵌入式web數據交互時通常會用到json格式, 因此如果需要在產品端進行json數據解析 , json-c 是一個比較不錯的選擇。本次我主要是對json數據的解析 , 主要是整型 , 字符串 和數據 , 進行解析。一.將json格式的數據轉化爲一個json對象 :jsonobj那麼首先需要的就是有一個可以被解析的json對象。因爲從web來的的數據一般是字符串也可以純文本,而json-c對這兩種都支持。先說json格式的字符串轉成json對象:
json_object* json_tokener_parse(const char *str);
或者以具有json格式文本內容的文本文件轉化爲json對象:
json_object* json_object_from_file(const char *filename);
這兩種方式都可以輕鬆將json格式的數據轉化爲json對象。並進一步進行解析。
二.對json對象進行解析
這個解析主要分兩步走
第一步:根據鍵名,從json對象中獲取對應數據的json對象
第二步: 根據數據類型,將數據對應的json對象轉化爲對應類型的數據
主要接口:
json_bool json_object_object_get_ex(struct json_object* obj, const char *key, struct json_object **value);
這個是一個增強的接口, 參數說明: obj:源json對象 , 即需要從obj這個json對象取數據 key: 需要取數據的鍵名 value: 用於存放獲取的對應數據的json對象,注意這裏一定傳入的是二級指針。不用傳入實體將對應的整型數據json數據轉成對應的整型數據
int32_t json_object_get_int(struct json_object *obj);
將對應的json字符串轉換爲字符串數據
extern const char* json_object_get_string(struct json_object *obj);
提取json數組中元素,當然這個元素也是一個json對象
json_object* json_object_array_get_idx(struct json_object *obj , int idx);
參數說明:
obj:json數據對象
idx:數據元素的腳標索引
當然還有其他的接口就不說了, 目前就對數據進行解析, 沒有對數據封裝成json數據
但是這個json數據解析需要注意釋放內存
以上接口產生的json對象 , 都需分別用
json_object_put(struct json_object *obj);
對內存進行釋放
最後貼一個測試代碼
#include <stdio.h>
#include <Alooper/Errors.h>
#include <linux/types.h>
#include <jsonc/json.h>
typedef long long off64_t;
#include <ghttp/ghttp.h>
/**是否強制退出http處理**/
static int mCancelHttp = 0;
char buffer[4096];
/***專輯列表數據***/
typedef struct speciallist_s{
// int keyId;
char id[10];
char name[128];
int type;
int count;
}speciallist_t;
char *jsonstr = "{\"data\":[{\"id\":\"100101\",\"name\":\"小學語文一年級上(人教版)\",\"type\":0,\"count\":20},{\"id\":\"100102\",\"name\":\"小學語文一年級下(人教版)\",\"type\":1,\"count\":37},{\"id\":\"100103\",\"name\":\"小學語文二年級上(人教版)\",\"type\":1,\"count\":40},{\"id\":\"100104\",\"name\":\"小學語文二年級下(人教版)\",\"type\":1,\"count\":41},{\"id\":\"100105\",\"name\":\"小學語文三年級上(人教版)\",\"type\":1,\"count\":35},{\"id\":\"100106\",\"name\":\"小學語文三年級下(人教版)\",\"type\":1,\"count\":32},{\"id\":\"100107\",\"name\":\"小學語文四年級上(人教版)\",\"type\":1,\"count\":32},{\"id\":\"100108\",\"name\":\"小學語文四年級下(人教版)\",\"type\":1,\"count\":32},{\"id\":\"100109\",\"name\":\"小學語文五年級上(人教版)\",\"type\":1,\"count\":36},{\"id\":\"100110\",\"name\":\"小學語文五年級下(人教版)\",\"type\":1,\"count\":30},{\"id\":\"100111\",\"name\":\"小學語文六年級上(人教版)\",\"type\":1,\"count\":33},{\"id\":\"100112\",\"name\":\"小學語文六年級下(人教版)\",\"type\":1,\"count\":32},{\"id\":\"100201\",\"name\":\"小學英語一年級上(人教版)\",\"type\":1,\"count\":38},{\"id\":\"100202\",\"name\":\"小學英語一年級下(人教版)\",\"type\":1,\"count\":38},{\"id\":\"100203\",\"name\":\"小學英語二年級上(人教版)\",\"type\":1,\"count\":38},{\"id\":\"100204\",\"name\":\"小學英語二年級下(人教版)\",\"type\":1,\"count\":38},{\"id\":\"100205\",\"name\":\"小學英語三年級上(人教版)\",\"type\":1,\"count\":60},{\"id\":\"100206\",\"name\":\"小學英語三年級下(人教版)\",\"type\":1,\"count\":60}],\"total\":18,\"flag\":99,\"result\":0}";
/*********
數據解析
***********/
int dedata(char *databuf)
{
int i = 0;
int total = 0;
int flag = 0;
int result = 0;
int ret = -1;
speciallist_t listdata[20];
if(NULL == databuf)
{
printf("the databuf is NULL ...\n");
}
json_object *jsonobj = NULL;
json_object *tmpjson = NULL;
json_object *datajson = NULL;
json_object *listjson = NULL;
printf("databuf :[%s], size:[%d]\n",databuf , strlen(databuf));
//jsonobj = json_object_new_string_len(databuf , strlen(databuf));
// jsonobj = json_object_new_string(jsonstr);
jsonobj = json_tokener_parse(databuf);
if(NULL == jsonobj)
{
printf("the jsonobj is error \n");
}
// printf("json:%s",json_object_to_json_string(jsonobj));
ret =json_object_object_get_ex(jsonobj , "total" , &tmpjson);
if(!ret)
{
printf("get jsondata error ...\n");
}
if(NULL == tmpjson)
{
printf("the tmpjson : [%s]\n",json_object_to_json_string(tmpjson));
}
/**獲取total***/
total = json_object_get_int(tmpjson);
json_object_put(tmpjson);
// tmpjson = NULL;
/***獲取flag***/
json_object_object_get_ex(jsonobj , "flag" , &tmpjson);
flag = json_object_get_int(tmpjson);
json_object_put(tmpjson);
/***獲取result***/
json_object_object_get_ex(jsonobj , "result" , &tmpjson);
result = json_object_get_int(tmpjson);
json_object_put(tmpjson);
/***獲取data***/
json_object_object_get_ex(jsonobj , "data" , &tmpjson);
for(i = 0 ; i < total ; i++)
{
datajson = json_object_array_get_idx(tmpjson , i);
json_object_object_get_ex(datajson , "id" , &listjson);
strcpy(listdata[i].id , json_object_get_string(listjson));
json_object_object_get_ex(datajson , "name" , &listjson);
strcpy(listdata[i].name , json_object_get_string(listjson));
json_object_object_get_ex(datajson , "type" , &listjson);
listdata[i].type = json_object_get_int(listjson);
json_object_object_get_ex(datajson , "count" , &listjson);
listdata[i].count = json_object_get_int(listjson);
json_object_put(listjson);
}
json_object_put(tmpjson);
/***釋放json對象***/
json_object_put(jsonobj);
printf("------------the data -----------------\n");
printf("{\n\t\"data\":\n\t\t[\n");
for(i = 0 ; i < total ; i++)
{
printf("\t\t\t\{\"id\":\"%s\",\"name\":\"%s\",\"type\":%d,\"count\":%d\n",listdata[i].id , listdata[i].name,listdata[i].type,listdata[i].count);
}
printf("\t\t],\n\t\"total\":%d,\n\t\"flag\":%d,\n\t\"result\":%d\n}",total,flag , result);
return 0;
}
/***從外部線程中斷http請求 , 避免網絡差時卡在http請求中***/
void http_abort(void)
{
mCancelHttp = 1;
}
int http_interrupt(void *arg)
{
static i = 0;
printf("http is been interrupt :%d \n",i++);
return *(int *)arg;
}
/*******
獲取重定向url
*******/
static char *_get_redirect_url(char *url , ghttp_request *req)
{
const char *newUri = ghttp_get_resp_header(req , http_hdr_Location);
if(NULL == newUri)
{
return NULL;
}
if(newUri[0] == '/')
{
char *p1 , *p2;
int len;
p1 = strstr(url , "://")+3;
p2 = strstr(p1 , "/");
if(NULL == p2)
{
p2 = url + strlen(url);
}
len = p2 - url;
p1 = malloc(len + strlen(newUri)+1);
if(NULL == p1)
{
printf("malloc error\n");
return NULL;
}
memcpy(p1 , url , len);
strcpy(p1+len , newUri);
return p1;
}
else
{
return strdup(newUri);
}
}
int http_process(char *file_url)
{
ghttp_request *req = NULL;
ghttp_status status;
int statusCode;
int ret;
int filesize;
int redirect_cnt = 0;
char *url = file_url;
char *p;
bzero(buffer , sizeof(buffer));
/***初始化a-res庫****/
//ares_library_init(ARES_LIB_INIT_ALL);
AGAIN:
req = ghttp_request_new(http_interrupt , &mCancelHttp);
if(NULL == req)
{
printf("request new err !!\n");
goto EXIT;
}
/***設置請求的url**/
if(ghttp_set_uri(req , url) != 0)
{
printf("set uri err !!\n");
goto EXIT;
}
/***設置自定義http協議頭 ,非必須***/
// ghttp_set_header(req , "User-Agent","VLC/2.2.4LibVLC/2.2.4\n");
/**設置get方法下載數據**/
ghttp_set_type(req , ghttp_type_get);
ghttp_prepare(req);
/***連接服務器***/
status = ghttp_connect(req , 011 , 011);
// status = ghttp_connect(req , 0 , 4095);
if((status != ghttp_done)&&(status != ghttp_error_no_support_range))
{
printf("http fail ...\n");
goto EXIT;
}
/****獲取http 服務器的響應碼***/
statusCode = ghttp_status_code(req);
/***處理重定向****/
if(statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 307)
{
if(redirect_cnt >= 3)
{
printf("redirect too much times \n");
goto EXIT;
}
char *p = _get_redirect_url(url , req);
if(NULL == p)
{
goto EXIT;
}
if(redirect_cnt > 0)
{
free(url);
}
url = p;
redirect_cnt++;
ghttp_request_destroy(req);
goto AGAIN;
}
/***開始獲取數據***/
filesize = ghttp_get_size(req);
ret = ghttp_read(req , buffer , 4095);
if(ret < 0)
{
printf("http get data fail , ret = %d\n",ret);
}
else if(ret == 0)
{
printf("http get data success filesize :%d\n",filesize);
}
else
{
printf("http get data ret : %d\n",ret);
}
/****釋放http請求資源****/
ghttp_request_destroy(req);
if((redirect_cnt > 0)&& (NULL != url))
{
free(url);
}
printf("the data:[%s]\n",buffer);
/***json 解析****/
printf("-------------------++++josn++++-------------------\n");
dedata(buffer);
return 0;
EXIT:
if(NULL != req)
{
ghttp_request_destroy(req);
}
if((redirect_cnt > 0)&& (NULL != url))
{
free(url);
}
return -1;
}
/****main*****/
int main(int argc , char *argv[])
{
int ret = -1;
char *url="http://xzxtest.com/test/abc/listSubAlbum?sn=10086&flag=0";
ret = http_process(url);
return 0;
}