Third party library cJson for C/C + + json parsing and synthesis

Posted by neh on Thu, 03 Feb 2022 19:48:49 +0100

We often use JSON format data for communication in our projects. In particular, we need to implement it on the ARM development board. It is troublesome to process JSON and tear the data by ourselves, but now we have a third-party library! That's cJson!

Environmental preparation

cJson official library:

https://github.com/DaveGamble/cJSONhttps://github.com/DaveGamble/cJSON Or:

git clone https://github.com/DaveGamble/cJSON

Just keep cjson C and cjson H two core documents.

Popular explanation

First, cJSON provides a variable type called cJSON. Let's look at cJSON H file shows that it is a structure:

/* 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;

It can be seen from this structure that the content of this JSON structure supports JSON objects, integers, strings, double precision floating-point numbers.

To obtain the data under the node from a json data node, you can use the following function:

/* 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);
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
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);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);

/* Check item type and return its value */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);

Among them, the more commonly used ones are

/* Get the json data under the node */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
/* Get the character data under the node */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
/* Get the digital data under the node */
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);

cJson provides many methods to create or add objects:

/* 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);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);

/* Create a string where valuestring references a string so
 * it will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
/* Create an object/array that only references it's elements so
 * they will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);

/* These utilities create an Array of count items.
 * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
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 *const *strings, int count);

/* Append item to the specified array/object. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
 * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
 * writing to `item->string` */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);

Not only add or create, but also delete.

/* Remove/Detach 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);

However, the deletion function is not commonly used, and there are even replacement objects. Students can use this function by looking at the source code of the library. I won't explain it too much here.

Basic usage process of Library

Using this library is simple. You only need to add those two core files to the project path.

#include"cJSON.h"

You can start using any function in this library.

Basic example -- get data from string in json data format

For a classic case, the json data to be parsed is as follows:

{
    "semantic": {
        "slots":    {
            "name": "Zhang San"
        }
    },
    "rc":   0,
    "operation":    "CALL",
    "service":  "telephone",
    "text": "Call Zhang San"
}

The parsing code is as follows:

#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
 
void printJson(cJSON * root)//Print the innermost key value pair of json recursively
{
    for(int i=0; i<cJSON_GetArraySize(root); i++)   //Traverse the outer key pair json
    {
        cJSON * item = cJSON_GetArrayItem(root, i);        
        if(cJSON_Object == item->type)      //If the value of the corresponding key is still cJSON_Object recursively calls printjason
            printJson(item);
        else                                //If the value is not a json object, the key and value are printed directly
        {
            printf("%s->", item->string);
            printf("%s\n", cJSON_Print(item));
        }
    }
}
 
int main()
{
    char * jsonStr = "{\"semantic\":{\"slots\":{\"name\":\"Zhang San\"}}, \"rc\":0, \"operation\":\"CALL\", \"service\":\"telephone\", \"text\":\"Call Zhang San\"}";
    cJSON * root = NULL;
    cJSON * item = NULL;//cjson object
 
    root = cJSON_Parse(jsonStr);     
    if (!root) 
    {
        printf("Error before: [%s]\n",cJSON_GetErrorPtr());
    }
    else
    {
        printf("%s\n", "Print in a formatted manner Json:");           
        printf("%s\n\n", cJSON_Print(root));
        printf("%s\n", "Print without format json: ");
        printf("%s\n\n", cJSON_PrintUnformatted(root));
 
        printf("%s\n", "Step by step acquisition name Key value pair:");
        printf("%s\n", "obtain semantic Lower cjson object:");
        item = cJSON_GetObjectItem(root, "semantic");//
        printf("%s\n", cJSON_Print(item));
        printf("%s\n", "obtain slots Lower cjson object");
        item = cJSON_GetObjectItem(item, "slots");
        printf("%s\n", cJSON_Print(item));
        printf("%s\n", "obtain name Lower cjson object");
        item = cJSON_GetObjectItem(item, "name");
        printf("%s\n", cJSON_Print(item));
 
        printf("%s:", item->string);   //Take a look at the meaning of these two members in the structure of cjson object
        printf("%s\n", item->valuestring);
                        
 
        printf("\n%s\n", "Print json All innermost key value pairs:");
        printJson(root);
    }
    return 0;    
}

Basic instance -- generate string data in json format

For a classic case, the json data to be generated is as follows:

{
    "semantic": {
        "slots":    {
            "name": "Zhang San"
        }
    },
    "rc":   0,
    "operation":    "CALL",
    "service":  "telephone",
    "text": "Call Zhang San"
}

The generation code is as follows:

#include <stdio.h>
#include "cJSON.h"
 
int main()
{
    cJSON * root =  cJSON_CreateObject();
    cJSON * item =  cJSON_CreateObject();
    cJSON * next =  cJSON_CreateObject();
 
    cJSON_AddItemToObject(root, "rc", cJSON_CreateNumber(0));//Add under root node
    cJSON_AddItemToObject(root, "operation", cJSON_CreateString("CALL"));
    cJSON_AddItemToObject(root, "service", cJSON_CreateString("telephone"));
    cJSON_AddItemToObject(root, "text", cJSON_CreateString("Call Zhang San"));
    cJSON_AddItemToObject(root, "semantic", item);//Add a semantic node under the root node
    cJSON_AddItemToObject(item, "slots", next);//Add an item node under the semantic node
    cJSON_AddItemToObject(next, "name", cJSON_CreateString("Zhang San"));//Add name node
 
    printf("%s\n", cJSON_Print(root));
 
    return 0;
}

To use json objects, you have to create json objects! Then add key value pairs.

make a concise evaluation

cJson is a simple third-party library. The files downloaded from the official website also contain sufficient sample programs, which is very good!

The author has personally tested that this library can be run on stm32F103 and stm32F411 to send and receive json packets through serial port.

Topics: C C++ JSON Ubuntu UART