参考:https://www.jianshu.com/p/4fcb49b55ff6
一、cJson介绍
项目地址:https://github.com/DaveGamble/cJSON
Welcome to cJSON.
cJSON aims to be the dumbest possible parser that you can get your job done with. It’s a single file of C, and a single header file. JSON is described best here: http://www.json.org/ It’s like XML, but fat-free. You use it to move data around, store things, or just generally represent your program’s state. As a library, cJSON exists to take away as much legwork as it can, but not get in your way. As a point of pragmatism (i.e. ignoring the truth), I’m going to say that you can use it in one of two modes: Auto and Manual. Let’s have a quick run-through. I lifted some JSON from this page: http://www.json.org/fatfree.html That page inspired me to write cJSON, which is a parser that tries to share the same philosophy as JSON itself. Simple, dumb, out of the way.
二、在当前项目中添加cJson
将项目中的cJson.c和cJson.h拷贝到当前项目即可.
三、cJson API
3.1 cJson数据结构
/* cJSON Types: */
#define cJSON_Invalid (0)
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_Raw (1 << 7) /* raw json */
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
/* 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;
3.2 cJSON_Parse
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
作用:将一个JSON字符串,按照cJSON结构体的结构序列化整个数据包,并在堆中开辟一块内存存储cJSON结构体。
返回值:成功返回一个指向内存块中的cJSON的指针,失败返回NULL。
3.3 cJSON_Delete
/* Delete a cJSON entity and all subentities. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
作用:释放位于堆中cJSON结构体内存。
返回值:无
注意:在使用cJSON_Parse()获取cJSON指针后,若不再使用了,则需要调用cJSON_Delete()对其释放,否则会导致内存泄漏。
3.4 cJSON_Print
/* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. */
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
作用:将cJSON数据解析成JSON字符串,并在堆中开辟一块char的内存空间存储JSON字符串。cJSON_PrintUnformatted()与cJSON_Print()类似,只是打印输出不带格式,而只是一个字符串数据。
返回值:成功返回一个char指针该指针指向位于堆中JSON字符串,失败返回NULL。
注意:通过cJSON_Print()可以将cJSON链表中所有的cJSON对象打印出来,但是需要手动去释放对应的资源:free(char *)。
3.5 cJSON_Version
/* returns the version of cJSON as a string */
CJSON_PUBLIC(const char*) cJSON_Version(void);
作用:获取当前使用的cJSON库的版本号。
返回值:返回一个字符串数据。
3.6 cJSON_GetArrayItem
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
作用:从object的cJSON链中寻找key为string的cJSON对象。
返回值:成功返回一个指向cJSON类型的结构体指针,失败返回NULL。
与cJSON_GetObjectItem()类似的接口还有(相信不用解释就能看明白):
/* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
/* Check if the item is a string and return its valuestring */
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
3.7 类型判断接口
下面的接口用于判断具体cJSON指针指向的item类型:
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
3.8 创建cJSON对象接口
下面的接口用于创建指定类型的cJSON数据结构对象:
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
/* These calls create a cJSON item of the appropriate type. */
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* These utilities create an Array of count items. */
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
3.9 添加cJSON对象到链表
下面的接口用于将创建的cJSON对象添加到链表中:
/* Append item to the specified array/object. */
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
3.10 从cJSON对象中删除一个cJSON对象
下面的接口用于从现有的cJSON链表中删除一个对象:
/* Remove/Detatch items from Arrays/Objects. */
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
3.11 创建并添加到链表
下面的接口用于创建并添加cJSON对象到指定的链表(简化操作):
/* Helper functions for creating and adding items to an object at the same time.
* They return the added item or NULL on failure. */
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
四、cJson使用示例
int signin(const char *url, const char *identifier, const char *credential)
{
struct http_response *p_resp;
cJSON *root = NULL, *data = NULL, *tmp = NULL;
char *json = NULL;
char signinbody[1024];
//0.构造参数和返回对应的数据类型
struct
{
int client;
int type;
struct
{
const char *identifier;
const char *credential;
} data;
} param = {1, 3, {identifier, credential}};
struct
{
int code;
char *msg;
cJSON_bool success;
struct
{
char *token;
} data;
} response;
//1.构造请求参数
root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "client", param.client);
cJSON_AddNumberToObject(root, "type", param.type);
cJSON_AddItemToObject(root, "data", data = cJSON_CreateObject());
cJSON_AddStringToObject(data, "identifier", param.data.identifier);
cJSON_AddStringToObject(data, "credential", param.data.credential);
json = cJSON_PrintUnformatted(root);
strncpy(signinbody, json, sizeof(signinbody));
printf("params: %s\n", signinbody);
free(json);
cJSON_Delete(root);
//2.发送请求
if ((p_resp = http_request_post(url, signinbody)) == NULL)
{
ERR("Not enough memory for malloc");
return -1;
}
if (p_resp->errcode)
{
ERR(p_resp->errtext);
return -1;
}
//3.处理响应
printf("%lu bytes data recieved: %s\n", (unsigned long)p_resp->datasize, p_resp->data);
//printf("%lu bytes header recieved: %s\n", (unsigned long)p_resp->headersize, p_resp->header);
root = cJSON_Parse(p_resp->data);
if ((root) && (tmp = cJSON_GetObjectItemCaseSensitive(root, "success")))
{
if ((response.success = tmp->valueint))
{
if ((tmp = cJSON_GetObjectItemCaseSensitive(root, "data")))
{
if ((tmp = cJSON_GetObjectItemCaseSensitive(tmp, "token")))
{
response.data.token = tmp->valuestring;
strncpy(g_config.token, response.data.token, sizeof(g_config.token));
}
}
}
}
cJSON_Delete(root);
http_response_free(p_resp);
return *g_config.token ? 0 : -1;
}