來點(diǎn)兒干貨蒋荚,今天白天主要時(shí)間都在車上,于是繼續(xù)完善這篇文章贷祈。
原本以為在寫上一條引用的時(shí)候可以把這篇完成狈醉,結(jié)果中途又遇到了一些問題,自己對(duì)JSON的語法規(guī)則并沒有很理解牲芋,這是停留在應(yīng)用層面撩笆。于是捺球,在業(yè)余時(shí)間,擠了擠時(shí)間夕冲,看了一些JSON的語法知識(shí)氮兵。
前言
- 寫技術(shù)文章確實(shí)是一件很難的事情,寫出來容易歹鱼,要自己理解泣栈,同時(shí)還要讓讀者看懂,真的是一件很不容易的事情弥姻。與君共勉南片。
1 概述
- 物聯(lián)網(wǎng)產(chǎn)品免不了和服務(wù)器做交互,目前使用的比較多的是以太網(wǎng)接網(wǎng)線或者WiFi設(shè)備或者GPRS庭敦。
- 無論是用的透?jìng)魈劢€是非透?jìng)鞯姆绞剑夹枰獙⒂布a(chǎn)生的原始數(shù)據(jù)轉(zhuǎn)換為服務(wù)器端的物聯(lián)網(wǎng)數(shù)據(jù)秧廉,硬件處理服務(wù)端的物聯(lián)網(wǎng)數(shù)據(jù)時(shí)颠悬,也需要轉(zhuǎn)化為十六進(jìn)制的數(shù)據(jù),方便處理定血。
- 這里涉及到了兩個(gè)問題赔癌,JSON數(shù)據(jù)包的解析和組裝。
- 硬件設(shè)備使用的基本都是C語言澜沟,同時(shí)考慮成本等因素灾票,單片機(jī)的RAM也是KB級(jí)的比較多。
- 此文章重點(diǎn)講解一下一個(gè)非常好用的CJSON庫茫虽,在MDK中編譯的代碼量只有十幾KB刊苍,占用的RAM只有幾KB
- 該JSON庫具有占用空間小(ROM占用10K以內(nèi)濒析,易移植(只有一個(gè)c文件和一個(gè)h文件)正什,使用簡(jiǎn)單(只需要掌握幾個(gè)常用的函數(shù),和一個(gè)CJSON結(jié)構(gòu)體就可以輕松地使用)的特點(diǎn)号杏。包含到項(xiàng)目源碼中非常方便婴氮,而且其實(shí)現(xiàn)效率也是非常高的。
2 JSON
- 先貼一段JSON數(shù)據(jù)盾致,閱讀下文時(shí)可以參考一下對(duì)應(yīng)的數(shù)據(jù)格式
{
"msg": [
{
"ctime": "20170916091927",
"gateLine": "ON",
"locksId": 65,
"isLocked": true,
"locksNo": "1001001105",
"pwd": {
"1": "654321",
"2": "147258"
}
},
{
"ctime": "20170916091927",
"gateLine": "ON",
"locksId": 66,
"isLocked": false,
"locksNo": "1001001106",
"pwd": {
"1": "123456",
"2": “147258"
}
}
],
"code": 0
}
- 下文對(duì)JSON的介紹來自筆者看了大量教程以后的總結(jié)主经。
2.1JSON 語法規(guī)則
JSON(JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式。
- 結(jié)構(gòu)特點(diǎn)
- 數(shù)據(jù)在名稱/值對(duì)中
- 數(shù)據(jù)由逗號(hào)分隔
- 大括號(hào)保存對(duì)象
- 中括號(hào)保存數(shù)組
- 鍵庭惜、值可層層嵌套
- 說明一下:鍵罩驻、值可層層嵌套
- 理解該特點(diǎn)是運(yùn)用JSON的關(guān)鍵。
- JSON的值可以為以下類型:
數(shù)字(整數(shù)或浮點(diǎn)數(shù))
字符串(在雙引號(hào)中)
邏輯值(true 或 false)
數(shù)組(在方括號(hào)中)
對(duì)象(在花括號(hào)中)
null(在不同的語言表示的意義不一樣护赊,開發(fā)者只需要知道在自己的語言里的意義就可以了) - JSON的值為數(shù)組時(shí)惠遏,數(shù)組可以是數(shù)字?jǐn)?shù)組砾跃,字符串?dāng)?shù)組,對(duì)象數(shù)組等节吮,所以該值里面又會(huì)包含很多鍵值對(duì)
- 解析JSON的核心也是一層一層地往外撥蜓席,反復(fù)地調(diào)用一個(gè)或者兩個(gè)方法(下文會(huì)詳細(xì)介紹)
2.2 JSON值
2.2.3 JSON數(shù)字
"locksId": 65,
2.2.4 JSON字符串
"ctime": "20170916091927",
2.2.5 JSON邏輯值
"isLocked": false,
2.2.6 JSON數(shù)組
- "msg"對(duì)應(yīng)的值為一個(gè)數(shù)組,數(shù)組里面有兩個(gè)對(duì)象(花括號(hào))元素课锌,
"msg": [
{
"ctime": "20170916091927",
"gateLine": "ON",
"locksId": 65,
"isLocked": true,
"locksNo": "1001001105",
"pwd": {
"1": "654321",
"2": "147258"
}
},
{
"ctime": "20170916091927",
"gateLine": "ON",
"locksId": 66,
"isLocked": false,
"locksNo": "1001001106",
"pwd": {
"1": "123456",
"2": “147258"
}
}
],
2.2.7 JSON對(duì)象
- 一個(gè)對(duì)象里面一般會(huì)包含多種類型的值,里面的“pwd”對(duì)應(yīng)的值也是一個(gè)對(duì)象
{
"ctime": "20170916091927",
"gateLine": "ON",
"locksId": 66,
"isLocked": false,
"locksNo": "1001001106",
"pwd": {
"1": "123456",
"2": “147258"
}
}
看到祈秕,應(yīng)該可以深入感受一下上文提到的"鍵渺贤、值可層層嵌套"
2.2.8 介紹一下JSON數(shù)據(jù)格式
- Object,Item,Array
筆者需要補(bǔ)充一下json的數(shù)據(jù)格式,學(xué)習(xí)中请毛。志鞍。。方仿。固棚。。
- 該小節(jié)作為一章的內(nèi)容放在了第2章中仙蚜。
3 介紹CJOSN的結(jié)構(gòu)
- 核心結(jié)構(gòu)體
/* The cJSON structure: */
typedef struct cJSON {
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int type; /* The type of the item, as above. */
char *valuestring; /* The item's string, if type==cJSON_String */
int valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
這個(gè)結(jié)構(gòu)體包含了所有的返回?cái)?shù)據(jù)類型此洲。
4 介紹CJSON的解析
4.1 解析使用的核心函數(shù)如下
cJSON *cJSON_Parse(const char *value);
void cJSON_Delete(cJSON *c);
int cJSON_GetArraySize(cJSON *array);
cJSON *cJSON_GetArrayItem(cJSON *array,int item);
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
- 一共五個(gè)函數(shù), 前三個(gè)函數(shù)使用的位置和方法都很固定委粉,后兩個(gè)就是在獲取數(shù)據(jù)的時(shí)候反復(fù)調(diào)用呜师,目的就是走到JSON數(shù)據(jù)的最底部--獲取健值。
- 總結(jié)一下就是:三個(gè)函數(shù)固定使用贾节,目的是獲取待處理的數(shù)據(jù)或者做收尾工作汁汗;兩個(gè)函數(shù)反復(fù)使用,目的是一層一層往下栗涂,獲取到基本數(shù)據(jù)知牌。
cJSON *cJSON_Parse(const char *value);
- 該函數(shù)是接收到j(luò)son字符串時(shí),將字符串轉(zhuǎn)為json格式的字符串斤程,一般都是在解析的第一行主要代碼的位置角寸。
void cJSON_Delete(cJSON *c);
- 該函數(shù)是在解析完成以后,用于釋放內(nèi)存忿墅。
int cJSON_GetArraySize(cJSON *array);
- 該函數(shù)是在有數(shù)組的時(shí)候袭厂,且不知道數(shù)組長(zhǎng)度的情況下,獲取數(shù)組的長(zhǎng)度球匕,然后再用循環(huán)挨個(gè)解析數(shù)組纹磺。如果需要解析的數(shù)據(jù)里面沒有數(shù)組的話,或者可以知道數(shù)組的具體長(zhǎng)度的話亮曹,就不需要使用該函數(shù)橄杨。
- 下面是兩個(gè)最重要的函數(shù)秘症,熟練掌握了這兩個(gè)函數(shù),大多數(shù)的場(chǎng)景都可以應(yīng)對(duì)了式矫。
cJSON *cJSON_GetArrayItem(cJSON *array,int item);
- 該函數(shù)的作用是獲取數(shù)組里面的元素乡摹,元素可以是對(duì)象,字符串采转,數(shù)值等各種類型聪廉。
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
- 該函數(shù)的作用是獲取對(duì)象里面,鍵對(duì)應(yīng)的值故慈。
4.2 解析舉例說明
4.2.1數(shù)據(jù)分析
- 還是用上面的的例子板熊,貼下源數(shù)據(jù)
{
"msg": [
{
"ctime": "20170916091927",
"gateLine": "ON",
"locksId": 65,
"isLocked": true,
"locksNo": "1001001105",
"pwd": {
"1": "654321",
"2": "147258"
}
},
{
"ctime": "20170916091927",
"gateLine": "ON",
"locksId": 66,
"isLocked": false,
"locksNo": "1001001106",
"pwd": {
"1": "123456",
"2": “147258"
}
}
],
"code": 0
}
- 簡(jiǎn)單分析一下
分析務(wù)必搞清楚幾點(diǎn):
1.第二章里面介紹的結(jié)構(gòu)
2.上文提到的五個(gè)方法,有不明白的可往上翻
- 最外圍結(jié)構(gòu)為一個(gè)對(duì)象(花括號(hào))察绷。使用cJSON_Parse就可以獲取到JSON對(duì)象內(nèi)容
- 對(duì)象當(dāng)中包含了兩個(gè)Item干签,分別是"msg"和"code"。
- "code"對(duì)應(yīng)的是一個(gè)數(shù)字拆撼,一次解析可以獲得數(shù)據(jù)容劳。使用cJSON_GetObjectItem,獲取返回的int類型數(shù)據(jù)
- "msg"里面包含了一個(gè)JSON數(shù)組闸度,每個(gè)數(shù)組的元素為一個(gè)對(duì)象竭贩。使用cJSON_GetObjectItem,返回值是一個(gè)array
- 先獲取到array的數(shù)量莺禁。使用cJSON_GetArraySize
- 用for循環(huán)對(duì)每個(gè)數(shù)組里面的對(duì)象元素做解析cJSON_GetArrayItem娶视,返回一個(gè)對(duì)象
- 反復(fù)對(duì)對(duì)象做解析,就可以獲取所有的數(shù)據(jù)睁宰。反復(fù)使用cJSON_GetObjectItem
4.2.2 貼一小段代碼示例
- 筆者不喜歡貼代碼肪获,雖然很多讀者都喜歡直接看代碼
- 還是那句話,看代碼引用起來快柒傻,但是后期維護(hù)更多的時(shí)間來搞清楚算法
- 下面提到的步驟1孝赫,2,3红符,4....對(duì)應(yīng)上文簡(jiǎn)單分析的7個(gè)步驟青柄,一一對(duì)應(yīng)看即可。
步驟1
Mother_obj=cJSON_Parse(json_string);
//json_string為源數(shù)據(jù)的字符數(shù)組
//Mother_obj為整個(gè)花括號(hào)對(duì)應(yīng)的對(duì)象
步驟2预侯,3
arry_obj_item = cJSON_GetObjectItem(Mother_obj,"code");
json_int_buf=arry_obj_item->valueint;
//獲取code的值
步驟4
array = cJSON_GetObjectItem(Mother_obj,"msg");
//獲取“msg”的數(shù)組值
步驟5
lock_array_len = cJSON_GetArraySize(array);
//獲取數(shù)組里面的元素個(gè)數(shù)
步驟6致开,7
for(i=0;i<lock_array_len;i++){
array_obj = cJSON_GetArrayItem(array,i);
//獲取數(shù)組里面的元素對(duì)象
//后面就對(duì)對(duì)象做處理,反復(fù)調(diào)用cJSON_GetObjectItem即可
if(array_obj==NULL)continue;
//獲取“time”對(duì)應(yīng)的值
arry_obj_item = cJSON_GetObjectItem(array_obj,"ctime");
if(arry_obj_item==NULL)continue;
json_buf = arry_obj_item->valuestring;
//獲取“l(fā)ockId”對(duì)應(yīng)的值
arry_obj_item = cJSON_GetObjectItem(array_obj,"locksId");
if(arry_obj_item==NULL)continue;
json_int_buf = arry_obj_item->valueint;
}
按照層層嵌套的邏輯萎馅,就可以解析出整個(gè)字符串
5 介紹CJSON的數(shù)據(jù)組合
- 下一篇繼續(xù)介紹
CrekerLi双戳,與君共勉于技術(shù)之路上