1.2 解析JSON字符串
1.2 解析JSON字符串
在cJSON中解析JSON字符串是第一步最重要的步骤,而cJSON提供了4个解析JSON字符串的函数,包括对完整的JSON串的解析,解析固定长度的JSON串的解析,以及解析可能含义非JSON语法的错误信息的JSON串的解析函数,而这些函数还能在适当的时候解析出错的时候返回整个JSON中有效的JSON,以及解析出错的位置。下面我们通过一个示例来介绍一下,我这里使用了Visual Studio进行了代码的编写。
1 #include <iostream> 2 #include "cJSON.h" 3 using namespace std; 4 5 int main() 6 { 7 ///////////////////////////////////// cJSON初始化JSON串的几种方式 ///////////////////////////////////// 8 // 1.直接通过内存中的JSON来进行初始化 9 /// 1.1 先手动构建一个JSON字符串串 10 const char jsonStr1[] = "{\"Name\":\"XiaoXin\",\"Age\":23,\"Information\":{\"Year\":2023,\"Month\":12}}"; 11 /// 1.2 然后使用cJSON_Parse函数来根据刚刚的JSON字符串来创建cJSON对象 12 cJSON*json1 = cJSON_Parse(jsonStr1); 13 cout << cJSON_Print(json1) << endl;//可以使用cJSON_Print来输出JSON,但是这个输出的话,会带有很多空格(方便调试看到),如果不需要的话可以使用unFormat 14 cout << cJSON_PrintUnformatted(json1) << endl; 15 /// 1.3 我们一旦使用完cJSON对象之后就需要释放掉,防止内存泄露 16 cJSON_Delete(json1); 17 json1 = NULL; 18 19 20 // 2.按照固定的长度来解析JSON串(这种场景,假设我们收到的JSON串是不完整的(这可能会用在网络通信中收到的JSON),但是我们如果知道前n个长度确确实实是有效的JSON上下文,那么我们就可以用这个函数) 21 /// 2.1 构造一个不完整的JSON串 22 const char jsonStr2[] = "{\"Key1\":12,\"Key2\":13},Name:";//前21个字符都是有效的串 23 /// 2.2 通过前21个有效的字符来构造一个cJSON对象 24 cJSON*json2 = cJSON_ParseWithLength(jsonStr2, 21); 25 cout << cJSON_PrintUnformatted(json2) << endl; 26 /// 2.3 记得释放 27 cJSON_Delete(json2); 28 json2 = NULL; 29 30 // 3.通过自定义行为来解析JSON串(我们可以通过cJSON_ParseWithOpts来传入适当的参数来规定如何解析JSON串[尤其是一些不完整的JSON串],以及还可以当解析到无效位置时,可以做什么) 31 /* 32 cJSON_ParseWithOpts( 33 const char* value,//要解析的JSON串 34 const char** return_parse_end,//这个二级指针会自动定位到解析失败的那个字符串的首字符地址上,我们可以通过这个地址计算出是字符串哪个下标出出错了(若传入NULL,则视为不使用这个参数) 35 cJSON_bool require_null_terminated//作用:控制是否强制要求输入字符串在JSON数据结束后立即跟随null终止符(\0)。 36 设置为 1 (true):解析器会检查 JSON 结束后是否紧跟 \0。如果后面还有非空白字符(如垃圾数据),则视为解析错误。这有助于防止解析被截断的数据或包含尾部垃圾的数据。 37 设置为 0 (false):解析器在解析完合法的 JSON 结构后即停止,忽略后面的内容(只要前面的 JSON 语法正确)。 38 ); 39 */ 40 /// 3.1 定义一个带有错误的不完整的JSON串 41 const char jsonStr3[] = "{\"Key1\":12,\"Key2\":13},Name:"; 42 const char* return_parse_end = NULL; 43 //如果说我们定义了需要在解析出错时得到在哪个位置出错了的地址,以及我们强制要求解析失败了就返回空的JSON对象并停止一切动作 44 cJSON*json3 = cJSON_ParseWithOpts(jsonStr3, &return_parse_end, 1); 45 if (!json3) 46 { 47 cout << "使用cJSON_ParseWithOpts解析不完整的JSON串失败,且返回了空的JSON对象,因为用户定义了当解析失败时强行返回空JSON对象" << endl; 48 cout << "JSON解析失败!失败的字符串是" << return_parse_end << ",解析出错的位置是:" << (return_parse_end - jsonStr3) << endl; 49 } 50 cJSON_Delete(json3); 51 json3 = NULL; 52 //如果说我们定义了需要在解析出错时得到哪个字符串位置出错了,以及即使是出错,我们也需要解析出出错位置前面有效的JSON对象,那么就可以将第三个参数改为0 53 cJSON* json4 = cJSON_ParseWithOpts(jsonStr3, &return_parse_end, 0); 54 if (!json4) 55 { 56 cout << "JSON解析失败!虽然指定了出错时仍然返回有效的JSON对象,但JSON根本无有效的JSON子串" << endl; 57 } 58 else 59 { 60 cout << "JSON虽然解析失败,但目标JSON字符串中仍然有有效的JSON对象,但解析出错的字符串是:" << return_parse_end << ",解析出错的位置在:" << (return_parse_end-jsonStr3) << endl; 61 cout << cJSON_PrintUnformatted(json4) << endl; 62 } 63 cJSON_Delete(json4); 64 json4 = NULL; 65 66 // 4.对于cJSON_ParseWithLengthOpts函数,相比于cJSON_ParseWithOpts就是多了一个长度控制,基本上是用在网络传输中读取固定长度的JSON时,若解析失败则需要做出相关操作的场景。这个函数读者可以自己去试验。 67 return 0; 68 }
| 函数名称 | 支持指定JSON长度? | 支持返回解析错误或错误的位置? | 强制要求JSON输入必须以\0结尾? | 使用场景 |
| cJSON_Parse | 不支持 | 不支持 | 是 | 适用于在内存中构建或解析100%完整且不会出错的JSON字符串 |
| cJSON_ParseWithLength | 支持 | 不支持 | 否,因为我们可以解析JSON串中的某一段长度的子JSON片段 | 适用于解析固定长度的JSON字符串。尤其是时候解析网络数据中指定长度的JSON子片段。 |
| cJSON_ParseWithOpts | 不支持 | 支持,若参数3为1,则当解析失败时视为返回的cJSON对象无效,且可以通过配置参数来获得解析出错的位置(通过指针相减计算得出)。若参数3为0,则看被解析的JSON串中除了无效的JSON内容之外若还有有效的子JSON串,那么就返回有效的cJSON串上下文,且可以通过配置第二参数得到解析出错的位置。 | 是 | 适用于解析在内存中构建的可能含有无效JSON内容但又含有有效JSON的字符串上下文。 |
| cJSON_ParseWithLengthOpts | 支持 | 支持,若参数3为1,则当解析失败时视为返回的cJSON对象无效,且可以通过配置参数来获得解析出错的位置(通过指针相减计算得出)。若参数3为0,则看被解析的JSON串中除了无效的JSON内容之外若还有有效的子JSON串,那么就返回有效的cJSON串上下文,且可以通过配置第二参数得到解析出错的位置。 | 否,我们可以通过传入的Length参数解析指定的长度的JSON上下文,且这个函数还能在指定长度的上下文中进一步视JSON的情况知道有效的JSON位置和解析出错的位置 | 功能最完整的组合版,同时支持长度控制、解析结束位置返回、终止符校验,是嵌入式/网络场景下最安全的解析选择 |
本节小结:
本节我们学习了cJSON的4个解析JSON字符串的函数,分别是cJSON_Parse;cJSON_ParseWithLength;cJSON_ParseWithOpts以及cJSON_ParseWithLengthOpts。以及我们初步还认识了如何使用cJSON_PrintUnformat和cJSON_Print来讲将cJSON对象输出到标准输出上。以及最重要的当我们使用完cJSON对象后,需要使用cJSON_Delete来释放cJSON对象以防止内存泄露。希望读者能从本节有所收获。有所总结。

浙公网安备 33010602011771号