使用cJSON庫對JSON格式進行解析

晖_IL發表於2024-06-13

JSON format


基本概念

JSON是JavaScript Object Notation的簡稱,中文含義為“JavaScript 物件表示法”,它是一種資料交換的文字格式,而不是一種程式語言

它易於閱讀和編寫,並且易於機械解析和生成,常在Web開發中用於資料的格式和傳輸


資料格式

物件

JSON 由兩種資料結構組成:物件和陣列。物件(object)是由鍵值對組成的無序集合,鍵是字串,值可以是任何型別,包括物件和陣列。物件由一對花括號{ }包圍,鍵和值之間用冒號:分隔。鍵值對之間用逗號,分隔。

//是一個JSON格式的物件,物件中有3個鍵值對 ,鍵的名稱:“name”  “age”   “score”
{
//鍵值對
“name” 	:  “lmx”,     //值的型別:字串
“age” 	:  29,		 //值的型別:整型

“score”	:[			 //值的型別:陣列 ,陣列中有1個元素,元素型別是物件
            {
                //物件中包含2個鍵值對
“xxx”: 85.5,  //值的型別是浮點型
“xxx”: 92
}
]
}


陣列

JSON 由兩種資料結構組成:物件和陣列。陣列(array)是值(value)的有序集合,每個值可以是任何型別,包括物件和陣列。陣列由一對方括號[ ]包圍,值之間用逗號,分隔。

[ "apple",  "banana",  "orange"] 

在上面的例子中,可以看到陣列包含三個字串元素,分別是:"apple"、"banana"和"orange"。


解析方法

一般嵌入式開發中可以使用cJSON庫對JSON格式進行解析,cJSON庫是基於C語言的一個開源專案,github下載地址:https://github.com/DaveGamble/cJSON

Untitled

cJSON庫主要的檔案有兩個:一個是cJSON.c 一個是cJSON.h。使用時在工程中包含標頭檔案即可,在cJSON.h標頭檔案中有一個用於解析JSON格式的結構體,如下:

Untitled

解析JSON流程

  1. 想要解析JSON格式,前提是得到儲存了JSON資料的字串,一般就是HTTP的請求或者響應的時候,絕大多數的情況都是伺服器響應的資料為JSON格式。

    Untitled

  2. 需要把儲存了JSON資料的字串進行轉換,轉換JSON格式,此時可以透過cJSON庫中README.md來分析,可以知道呼叫 cJSON_Parse() 進行解析,該函式的返回值就是cJSON格式的資料

    Untitled

  3. 如果得到了轉換成功的JSON格式的字串,可以對該字串進行除錯輸出,可以選擇呼叫cJSON_Print(),該函式的返回值就是儲存了JSON格式的字串,如下:

    Untitled

  4. 如果輸出結果沒有問題,則可以開始對JSON資料進行解析,其中可以先從JSON物件中獲得某個鍵的值,相當於對某個鍵值對進行解析,注意:如果鍵值對的值的型別不是字串、整型、浮點型,則需要繼續對鍵值對進行解析。否則,可以直接輸出鍵值對的內容,利用JSON物件的結構體指標cJSON *的成員valuestring、valueint、valuedouble。

    Untitled

  5. 如果鍵值對的型別不是基本型別,而是物件或者陣列,則需要繼續解析,此時分為兩種情況,第一種是情況:鍵值對的值的型別是陣列,此時可以選擇呼叫cJSON_GetArraySize()函式,該函式的作用是獲取陣列中的元素的數量。另外,可以選擇呼叫cJSON_GetArrayItem()函式,可以獲取陣列中的元素,如果陣列的元素型別是物件,則可以選擇呼叫cJSON_GetObjectItem()函式對物件進行解析

    Untitled


構造JSON流程

  1. 如果打算構造JSON格式,則需要首先建立一個JSON頂層物件,需要呼叫cJSON_CreateObject(),也就是該函式可以建立物件,其實就是構造一對{ }。

    Untitled

案例

可以選擇繼續呼叫cJSON_CreateObject()來建立新的小物件,此時可以選擇向小物件中新增鍵值對,新增鍵值對的前提是構造鍵值對,需要先把鍵值對的值新增到建立的物件中,再把小物件新增到其他物件中,具有巢狀關係。根據鍵值對的值的型別,可以選擇呼叫。


Untitled

//示例:
{
   "action":"mode_set",
   "mode":1,
   "datalist":
            {
                "username":"admin",
                "password":"admin" 
            }
   "register":
             ["{
                "status":"0",
                "msg":"Success." 
             }"]
}
 
//組資料:
cJSON *JsRegisterArr = cJSON_CreateArray();
cJSON *JsRegisterObj = cJSON_CreateObject();
cJSON_AddItemToObject(JsData, "register", JsRegisterArr);
cJSON_AddItemToArray(JsRegisterArr, JsRegisterObj);
cJSON_AddStringToObject(JsRegisterObj, "status", "0");
cJSON_AddStringToObject(JsRegisterObj, "msg", "Success");
 
//解析資料:
cJSON *JsRegisterArr = NULL;
cJSON *JsRegisterObj = NULL;
cJSON *pValue = NULL;
UINT4  u4DataSize = 0; 
JsRegisterArr = cJSON_GetObjectItem(JsData, "register");
u4DataSize = cJSON_GetArraySize(JsRegisterArr);
for (UINT4 u4Index = 0; u4Index < u4DataSize; u4Index ++)
{
   JsRegisterObj = cJSON_GetArrayItem(JsRegisterArr, u4Index)
   pValue = cJSON_GetObjectItem(JsRegisterObj, "status");
   printf("status : %s \r\n", pValue->valuestring);
   pValue = cJSON_GetObjectItem(JsRegisterObj, "msg");
   printf("msg : %s \r\n", pValue->valuestring);
}

//以下函式呼叫時都會申請記憶體,如果不釋放記憶體會造成記憶體洩露:
cJSON_Parse();
cJSON_CreateObject();
cJSON_CreateArray();
cJSON_Print();
cJSON_PrintUnformatted();
 
//釋放記憶體:
cJSON_Delete();
cJSON_free();
 
//用法解釋:
//1.呼叫cJSON_Parse,cJSON_CreateObject,cJSON_CreateArray時,使用cJSON_Delete釋放記憶體,
//比如JsData = cJSON_CreateObject(), DataListArr = cJSON_CreateArray();cJSON_AddItemToArray(DataListArr, JsData);
//這種情況只要cJSON_Delete(JsData), 這樣也會同時釋放DataListArr的記憶體。
//2.如果是呼叫cJSON_Print,cJSON_PrintUnformatted時,則使用cJSON_free();
 
//建議:
//因為涉及申請記憶體及釋放記憶體,所以在每次creat一個cJSON後,使用前都要判空。
cJSON *JsData = NULL;
JsData = cJSON_CreateObject();
if (JsData == NULL)
   return FAILURE;
   

相關文章