参考: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数据结构

  1. /* cJSON Types: */
  2. #define cJSON_Invalid (0)
  3. #define cJSON_False (1 << 0)
  4. #define cJSON_True (1 << 1)
  5. #define cJSON_NULL (1 << 2)
  6. #define cJSON_Number (1 << 3)
  7. #define cJSON_String (1 << 4)
  8. #define cJSON_Array (1 << 5)
  9. #define cJSON_Object (1 << 6)
  10. #define cJSON_Raw (1 << 7) /* raw json */
  11. #define cJSON_IsReference 256
  12. #define cJSON_StringIsConst 512
  13. /* The cJSON structure: */
  14. typedef struct cJSON
  15. {
  16. /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
  17. struct cJSON *next;
  18. struct cJSON *prev;
  19. /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
  20. struct cJSON *child;
  21. /* The type of the item, as above. */
  22. int type;
  23. /* The item's string, if type==cJSON_String and type == cJSON_Raw */
  24. char *valuestring;
  25. /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
  26. int valueint;
  27. /* The item's number, if type==cJSON_Number */
  28. double valuedouble;
  29. /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
  30. char *string;
  31. } 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;
}