JSON組件使用方法是什么

本篇內(nèi)容主要講解“JSON組件使用方法是什么”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“JSON組件使用方法是什么”吧!

專(zhuān)業(yè)成都網(wǎng)站建設(shè)公司,做排名好的好網(wǎng)站,排在同行前面,為您帶來(lái)客戶和效益!成都創(chuàng)新互聯(lián)為您提供成都網(wǎng)站建設(shè),五站合一網(wǎng)站設(shè)計(jì)制作,服務(wù)好的網(wǎng)站設(shè)計(jì)公司,成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)負(fù)責(zé)任的成都網(wǎng)站制作公司!

1. JSON與cJSON

JSON —— 輕量級(jí)的數(shù)據(jù)格式

JSON 全稱 JavaScript Object Notation,即 JS對(duì)象簡(jiǎn)譜,是一種輕量級(jí)的數(shù)據(jù)格式。

它采用完全獨(dú)立于編程語(yǔ)言的文本格式來(lái)存儲(chǔ)和表示數(shù)據(jù),語(yǔ)法簡(jiǎn)潔、層次結(jié)構(gòu)清晰,易于人閱讀和編寫(xiě),同時(shí)也易于機(jī)器解析和生成,有效的提升了網(wǎng)絡(luò)傳輸效率。

JSON語(yǔ)法規(guī)則

JSON對(duì)象是一個(gè)無(wú)序的"名稱/值"鍵值對(duì)的集合:

  • 以"{"開(kāi)始,以"}"結(jié)束,允許嵌套使用;

  • 每個(gè)名稱和值成對(duì)出現(xiàn),名稱和值之間使用":"分隔;

  • 鍵值對(duì)之間用","分隔

  • 在這些字符前后允許存在無(wú)意義的空白符;

對(duì)于鍵值,可以有如下值:

  • 一個(gè)新的json對(duì)象

  • 數(shù)組:使用"["和"]"表示

  • 數(shù)字:直接表示,可以是整數(shù),也可以是浮點(diǎn)數(shù)

  • 字符串:使用引號(hào)"表示

  • 字面值:false、null、true中的一個(gè)(必須是小寫(xiě))

示例如下:

{
    "name": "mculover666",
    "age": 22,
    "weight": 55.5
    "address":
    {
        "country": "China",
        "zip-code": 111111
    },
    "skill": ["c", "Java", "Python"],
    "student": false
}

LiteOS中的cJSON組件

cJSON是一個(gè)使用C語(yǔ)言編寫(xiě)的JSON數(shù)據(jù)解析器,具有超輕便,可移植,單文件的特點(diǎn),使用MIT開(kāi)源協(xié)議。

LiteOS中已經(jīng)移植了cJSON,作為一個(gè)組件使用,源碼在sdk\IoT_LINK_1.0.0\iot_link\cJSON中,其源碼文件只有兩個(gè):

  • cJSON.h

  • cJSON.c

使用的時(shí)候,只需要將這兩個(gè)文件復(fù)制到工程目錄,然后包含頭文件cJSON.h即可,如下:

#include "cJSON.h"

2. cJSON數(shù)據(jù)結(jié)構(gòu)和設(shè)計(jì)思想

cJSON的設(shè)計(jì)思想從其數(shù)據(jù)結(jié)構(gòu)上就能反映出來(lái)。

cJSON使用cJSON結(jié)構(gòu)體來(lái)表示一個(gè)JSON數(shù)據(jù),定義在cJSON.h中,源碼如下:

/* The cJSON structure: */
typedef struct cJSON
{
    /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
    struct cJSON *next;
    struct cJSON *prev;
    /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
    struct cJSON *child;

    /* The type of the item, as above. */
    int type;

    /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
    char *valuestring;
    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    int valueint;
    /* The item's number, if type==cJSON_Number */
    double valuedouble;

    /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
    char *string;
} cJSON;

cJSON的設(shè)計(jì)很巧妙。

首先,它不是將一整段JSON數(shù)據(jù)抽象出來(lái),而是將其中的一條JSON數(shù)據(jù)抽象出來(lái),也就是一個(gè)鍵值對(duì),用上面的結(jié)構(gòu)體 strcut cJSON 來(lái)表示,其中用來(lái)存放值的成員列表如下:

  • String:用于表示該鍵值對(duì)的名稱;

  • type:用于表示該鍵值對(duì)中值的類(lèi)型;

  • valuestring:如果鍵值類(lèi)型(type)是字符串,則將該指針指向鍵值;

  • valueint:如果鍵值類(lèi)型(type)是整數(shù),則將該指針指向鍵值;

  • valuedouble:如果鍵值類(lèi)型(type)是浮點(diǎn)數(shù),則將該指針指向鍵值;

其次,一段完整的JSON數(shù)據(jù)中由很多鍵值對(duì)組成,并且涉及到鍵值對(duì)的查找、刪除、添加,所以使用鏈表來(lái)存儲(chǔ)整段JSON數(shù)據(jù),如上面的代碼所示:

  • next指針:指向下一個(gè)鍵值對(duì)

  • prev指針指向上一個(gè)鍵值對(duì)

最后,因?yàn)镴SON數(shù)據(jù)支持嵌套,所以一個(gè)鍵值對(duì)的值會(huì)是一個(gè)新的JSON數(shù)據(jù)對(duì)象(一條新的鏈表),也有可能是一個(gè)數(shù)組,方便起見(jiàn),在cJSON中,數(shù)組也表示為一個(gè)數(shù)組對(duì)象,用鏈表存儲(chǔ),所以:

在鍵值對(duì)結(jié)構(gòu)體中,當(dāng)該鍵值對(duì)的值是一個(gè)嵌套的JSON數(shù)據(jù)或者一個(gè)數(shù)組時(shí),由child指針指向該條新鏈表。

3. 開(kāi)啟cJSON組件

在LiteOS中,cJSON組件默認(rèn)是未開(kāi)啟的,使用宏定義CONFIG_JSON_ENABLE開(kāi)啟。

開(kāi)啟之后,LiteOS會(huì)自動(dòng)進(jìn)行初始化,并且使用cJSON的內(nèi)存鉤子將cJSON申請(qǐng)內(nèi)存的方式變?yōu)槭褂胦sal_malloc申請(qǐng),自動(dòng)初始化代碼在link_main.c文件中:

JSON組件使用方法是什么

4. JSON數(shù)據(jù)封裝

封裝方法

封裝JSON數(shù)據(jù)的過(guò)程,其實(shí)就是創(chuàng)建鏈表和向鏈表中添加節(jié)點(diǎn)的過(guò)程。

首先來(lái)講述一下鏈表中的一些術(shù)語(yǔ):

  • 頭指針:指向鏈表頭結(jié)點(diǎn)的指針;

  • 頭結(jié)點(diǎn):不存放有效數(shù)據(jù),方便鏈表操作;

  • 首節(jié)點(diǎn):第一個(gè)存放有效數(shù)據(jù)的節(jié)點(diǎn);

  • 尾節(jié)點(diǎn):最后一個(gè)存放有效數(shù)據(jù)的節(jié)點(diǎn);

明白了這幾個(gè)概念之后,我們開(kāi)始講述創(chuàng)建一段完整的JSON數(shù)據(jù),即如何創(chuàng)建一條完整的鏈表。

  • ① 創(chuàng)建頭指針:

 cJSON* cjson_test = NULL;
  • ② 創(chuàng)建頭結(jié)點(diǎn),并將頭指針指向頭結(jié)點(diǎn):

cjson_test = cJSON_CreateObject();
  • ③ 盡情的向鏈表中添加節(jié)點(diǎn):

cJSON_AddNullToObject(cJSON * const object, const char * const name);

cJSON_AddTrueToObject(cJSON * const object, const char * const name);

cJSON_AddFalseToObject(cJSON * const object, const char * const name);

cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);

cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);

cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);

cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);

cJSON_AddObjectToObject(cJSON * const object, const char * const name);

cJSON_AddArrayToObject(cJSON * const object, const char * const name);

輸出JSON數(shù)據(jù)

上面講述,一段完整的JSON數(shù)據(jù)就是一條長(zhǎng)長(zhǎng)的鏈表,那么,如何打印出這段JSON數(shù)據(jù)呢?

cJSON提供了一個(gè)API,可以將整條鏈表中存放的JSON信息輸出到一個(gè)字符串中:

(char *) cJSON_Print(const cJSON *item);

使用的時(shí)候,只需要接收該函數(shù)返回的指針地址即可。

封裝數(shù)據(jù)和打印數(shù)據(jù)示例

單純的講述方法還不夠,下面用一個(gè)例子來(lái)說(shuō)明,封裝出開(kāi)頭給出的那段JSON數(shù)據(jù)。

首先基于HelloWorld工程,創(chuàng)建一個(gè)存放示例文件的文件夾cloud_test_demo,并新建一個(gè)實(shí)驗(yàn)文件cjson_print_demo.c,編寫(xiě)如下代碼:

#include <osal.h>
#include <stdio.h>
#include <cJSON.h>

static int cjson_print_demo_entry()
{
    cJSON* cjson_test = NULL;
    cJSON* cjson_address = NULL;
    cJSON* cjson_skill = NULL;
    char* str = NULL;

    /* 創(chuàng)建一個(gè)JSON數(shù)據(jù)對(duì)象(鏈表頭結(jié)點(diǎn)) */
    cjson_test = cJSON_CreateObject();

    /* 添加一條字符串類(lèi)型的JSON數(shù)據(jù)(添加一個(gè)鏈表節(jié)點(diǎn)) */
    cJSON_AddStringToObject(cjson_test, "name", "mculover666");

    /* 添加一條整數(shù)類(lèi)型的JSON數(shù)據(jù)(添加一個(gè)鏈表節(jié)點(diǎn)) */
    cJSON_AddNumberToObject(cjson_test, "age", 22);

    /* 添加一條浮點(diǎn)類(lèi)型的JSON數(shù)據(jù)(添加一個(gè)鏈表節(jié)點(diǎn)) */
    cJSON_AddNumberToObject(cjson_test, "weight", 55.5);

    /* 添加一個(gè)嵌套的JSON數(shù)據(jù)(添加一個(gè)鏈表節(jié)點(diǎn)) */
    cjson_address = cJSON_CreateObject();
    cJSON_AddStringToObject(cjson_address, "country", "China");
    cJSON_AddNumberToObject(cjson_address, "zip-code", 111111);
    cJSON_AddItemToObject(cjson_test, "address", cjson_address);

    /* 添加一個(gè)數(shù)組類(lèi)型的JSON數(shù)據(jù)(添加一個(gè)鏈表節(jié)點(diǎn)) */
    cjson_skill = cJSON_CreateArray();
    cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "C" ));
    cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Java" ));
    cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Python" ));
    cJSON_AddItemToObject(cjson_test, "skill", cjson_skill);

    /* 添加一個(gè)值為 False 的布爾類(lèi)型的JSON數(shù)據(jù)(添加一個(gè)鏈表節(jié)點(diǎn)) */
    cJSON_AddFalseToObject(cjson_test, "student");

    /* 打印JSON對(duì)象(整條鏈表)的所有數(shù)據(jù) */
    str = cJSON_Print(cjson_test);
    printf("%s\n", str);

    /* 釋放整條鏈表內(nèi)存 */
    cJSON_Delete(cjson_test);

    return 0;
}

int standard_app_demo_main()
{
    osal_task_create("cjson_print_demo",cjson_print_demo_entry,NULL,0x800,NULL,2);
    return 0;
}

在user_demo.mk中配置文件路徑:

	#example for cjson_print_demo
	ifeq ($(CONFIG_USER_DEMO), "cjson_print_demo")	
		user_demo_src  = ${wildcard $(TOP_DIR)/targets/STM32L431_BearPi/Demos/cloud_test_demo/cjson_print_demo.c}
	endif

位置如下:

JSON組件使用方法是什么

然后在.sdkconfig中開(kāi)啟cJSON組件,并且選中該demo:

JSON組件使用方法是什么

實(shí)驗(yàn)結(jié)果如圖:

JSON組件使用方法是什么

5. cJSON數(shù)據(jù)解析

解析方法

解析JSON數(shù)據(jù)的過(guò)程,其實(shí)就是剝離一個(gè)一個(gè)鏈表節(jié)點(diǎn)(鍵值對(duì))的過(guò)程。

解析方法如下:

  • ① 創(chuàng)建鏈表頭指針:

cJSON* cjson_test = NULL;
  • ② 解析整段JSON數(shù)據(jù),并將鏈表頭結(jié)點(diǎn)地址返回,賦值給頭指針:

解析整段數(shù)據(jù)使用的API只有一個(gè):

(cJSON *) cJSON_Parse(const char *value);
  • ③ 根據(jù)鍵值對(duì)的名稱從鏈表中取出對(duì)應(yīng)的值,返回該鍵值對(duì)(鏈表節(jié)點(diǎn))的地址

(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
  • ④ 如果JSON數(shù)據(jù)的值是數(shù)組,使用下面的兩個(gè)API提取數(shù)據(jù):

(int) cJSON_GetArraySize(const cJSON *array);
(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);

解析示例

下面用一個(gè)例子來(lái)說(shuō)明如何解析出開(kāi)頭給出的那段JSON數(shù)據(jù)。

在存放示例文件的文件夾cloud_test_demo中,再新建一個(gè)實(shí)驗(yàn)文件cjson_parse_demo.c,編寫(xiě)如下代碼:

#include <osal.h>
#include <stdio.h>
#include <cJSON.h>

char *message = 
"{                              \
    \"name\":\"mculover666\",   \
    \"age\": 22,                \
    \"weight\": 55.5,           \
    \"address\":                \
        {                       \
            \"country\": \"China\",\
            \"zip-code\": 111111\
        },  \
    \"skill\": [\"c\", \"Java\", \"Python\"],\
    \"student\": false\
}";

static int cjson_test1_demo_entry()
{
   cJSON* cjson_test = NULL;
    cJSON* cjson_name = NULL;
    cJSON* cjson_age = NULL;
    cJSON* cjson_weight = NULL;
    cJSON* cjson_address = NULL;
    cJSON* cjson_address_country = NULL;
    cJSON* cjson_address_zipcode = NULL;
    cJSON* cjson_skill = NULL;
    cJSON* cjson_student = NULL;
    int    skill_array_size = 0, i = 0;
    cJSON* cjson_skill_item = NULL;

    /* 解析整段JSO數(shù)據(jù) */
    cjson_test = cJSON_Parse(message);
    if(cjson_test == NULL)
    {
        printf("parse fail.\n");
        return -1;
    }

    /* 依次根據(jù)名稱提取JSON數(shù)據(jù)(鍵值對(duì)) */
    cjson_name = cJSON_GetObjectItem(cjson_test, "name");
    cjson_age = cJSON_GetObjectItem(cjson_test, "age");
    cjson_weight = cJSON_GetObjectItem(cjson_test, "weight");

    printf("name: %s\n", cjson_name->valuestring);
    printf("age:%d\n", cjson_age->valueint);
    printf("weight:%.1f\n", cjson_weight->valuedouble);

    /* 解析嵌套json數(shù)據(jù) */
    cjson_address = cJSON_GetObjectItem(cjson_test, "address");
    cjson_address_country = cJSON_GetObjectItem(cjson_address, "country");
    cjson_address_zipcode = cJSON_GetObjectItem(cjson_address, "zip-code");
    printf("address-country:%s\naddress-zipcode:%d\n", cjson_address_country->valuestring, cjson_address_zipcode->valueint);

    /* 解析數(shù)組 */
    cjson_skill = cJSON_GetObjectItem(cjson_test, "skill");
    skill_array_size = cJSON_GetArraySize(cjson_skill);
    printf("skill:[");
    for(i = 0; i < skill_array_size; i++)
    {
        cjson_skill_item = cJSON_GetArrayItem(cjson_skill, i);
        printf("%s,", cjson_skill_item->valuestring);
    }
    printf("\b]\n");

    /* 解析布爾型數(shù)據(jù) */
    cjson_student = cJSON_GetObjectItem(cjson_test, "student");
    if(cjson_student->valueint == 0)
    {
        printf("student: false\n");
    }
    else
    {
        printf("student:error\n");
    }

    /* 釋放整條鏈表內(nèi)存 */
    cJSON_Delete(cjson_test);
    
    return 0;
}

int standard_app_demo_main()
{
    osal_task_create("cjson_test1_demo",cjson_test1_demo_entry,NULL,0x800,NULL,2);
    return 0;
}

在user_demo.mk中配置文件路徑:

	#example for cjson_parse_demo
	ifeq ($(CONFIG_USER_DEMO), "cjson_parse_demo")	
		user_demo_src  = ${wildcard $(TOP_DIR)/targets/STM32L431_BearPi/Demos/cloud_test_demo/cjson_parse_demo.c}
	endif

位置如下:

JSON組件使用方法是什么

然后在.sdkconfig中開(kāi)啟cJSON組件,并且選中該demo:

JSON組件使用方法是什么

實(shí)驗(yàn)結(jié)果如圖:

JSON組件使用方法是什么

注意事項(xiàng)

在本示例中,因?yàn)槲姨崆爸罃?shù)據(jù)的類(lèi)型,比如字符型或者浮點(diǎn)型,所以我直接使用指針指向?qū)?yīng)的數(shù)據(jù)域提取,在實(shí)際使用時(shí),如果提前不確定數(shù)據(jù)類(lèi)型,應(yīng)該先判斷type的值,確定數(shù)據(jù)類(lèi)型,再?gòu)膶?duì)應(yīng)的數(shù)據(jù)域中提取數(shù)據(jù)

6. cJSON使用過(guò)程中的內(nèi)存問(wèn)題

內(nèi)存及時(shí)釋放

cJSON的所有操作都是基于鏈表的,所以cJSON在使用過(guò)程中大量的使用malloc從堆中分配動(dòng)態(tài)內(nèi)存的,所以在使用完之后,應(yīng)當(dāng)及時(shí)調(diào)用下面的函數(shù),清空cJSON指針?biāo)赶虻膬?nèi)存,該函數(shù)也可用于刪除某一條數(shù)據(jù):

(void) cJSON_Delete(cJSON *item);

注意:該函數(shù)刪除一條JSON數(shù)據(jù)時(shí),如果有嵌套,會(huì)連帶刪除。

內(nèi)存鉤子

cJSON在支持自定義malloc函數(shù)和free函數(shù),方法如下:

  • ① 使用cJSON_Hooks來(lái)連接自定義malloc函數(shù)和free函數(shù):

typedef struct cJSON_Hooks
{
      /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
      void *(CJSON_CDECL *malloc_fn)(size_t sz);
      void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;
  • ② 初始化鉤子cJSON_Hooks

(void) cJSON_InitHooks(cJSON_Hooks* hooks);

到此,相信大家對(duì)“JSON組件使用方法是什么”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

網(wǎng)站欄目:JSON組件使用方法是什么
網(wǎng)頁(yè)地址:http://muchs.cn/article4/gedoie.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導(dǎo)航、品牌網(wǎng)站建設(shè)、用戶體驗(yàn)靜態(tài)網(wǎng)站、軟件開(kāi)發(fā)、外貿(mào)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營(yíng)