Basic use of Json library for embedded devices

Hello everyone, today I will introduce a lightweight Json library based on C language - cJson. Can be used in resource-constrained embedded devices.

 

cJSON is an ultra-lightweight, portable, single-file, simple ANSI-C standard JSON parser.

cJSON is an open source project, github download address:

https://github.com/DaveGamble/cJSON

cJSON, currently, there are two main files, one  cJSON.c for each  cJSON.h. When using it, just include the header file.

If it is used in the Linux operating system, the math library needs to be added when compiling  libm.so, as follows:

gcc  *.c  cJSON.c  -lm

1. cJSON structure

cJSON.h A very important structure cJSON is defined in . If you want to be familiar with using cJSON library functions, you can start with the cJSON structure. The cJSON structure is as follows

typedef struct cJSON {  
     struct cJSON *next,*prev;   
     struct cJSON *child;   
     int type;   
     char *valuestring;        // value值是字符串类型
     int valueint;  
     double valuedouble;   
     char *string;             // 对象中的key
} cJSON; 

Here are some explanations about this structure:

  1. The cJOSN structure is a doubly linked list, and the next layer can be accessed through the child pointer.

  2. The type variable of the structure member is used to describe the type of the data element (if it is a key-value pair representing the type of the value value), the data element can be a string, an integer, or a floating-point type.

  • If it is an integer value, the value can be taken out by valueint

  • If it is a floating point type, the value can be taken out by valuedouble

  • If it is a string type, the value can be taken out through valuestring

  1. The structure member string represents the name of the key in the key-value pair.

As a parsing library of Json format, cJSON’s main function is to construct and parse Json format. For example, to send data: the purpose is to encapsulate the data to be sent by the sender in the form of json, and then send it. After receiving the data, the receiver still presses JSON format analysis, you get the desired data.

2. cJson API

The data in Json format is nothing more than two kinds of Json objects and Json arrays. The Json data string created may be one of the two, or a combination of the two, no matter which one is available by calling the relevant API function Do it easily.

2.1 Encapsulation of data

You can see some function declarations in  cJSON.h the header file. By calling these creation functions, the data types supported by Json can be encapsulated into cJSON structure types:

// 空值类型
extern cJSON *cJSON_CreateNull(void);
// 布尔类型
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int b);
// 数值类型
extern cJSON *cJSON_CreateNumber(double num);
// 字符串类型
extern cJSON *cJSON_CreateString(const char *string);
// json数组(创建空数组)
extern cJSON *cJSON_CreateArray(void);
// json对象(创建空对象)
extern cJSON *cJSON_CreateObject(void);

In addition, the cJson library also provides us with some more convenient operation functions, which can also be initialized while creating an array

// 创建一个Json数组, 元素为整形
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
// 创建一个Json数组, 元素为浮点
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
// 创建一个Json数组, 元素为字符串类型
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);

2.2 Json object operation

After getting a Json object, you can add key-value pairs to the object, you can use cJSON_AddItemToObject()

extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);

The affiliation of nodes in the cJSON library is maintained through a tree, and each layer of nodes is maintained through a linked list, so that the meaning of the function parameters can be analyzed:

  • object: The key-value pair to be added belongs to that node

  • string: the key-value of the added key-value pair

  • item: the value of the added key-value pair (it needs to be encapsulated into a cJSON type structure first)

In order to make my operation more convenient, the cJson library also provides us with some macro functions, so that we can quickly add key-value pairs to Json objects

#define cJSON_AddNullToObject(object,name)      cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name)      cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name)     cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddBoolToObject(object,name,b)    cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
#define cJSON_AddNumberToObject(object,name,n)  cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s)  cJSON_AddItemToObject(object, name, cJSON_CreateString(s))

We can also extract the corresponding value according to the key value in the Json object. The API function prototype is as follows:

extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);

2.3 Json array operation

Add data to the Json array (original data needs to be converted to cJSON structure type first)

extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);

Get the number of elements in the Json array:

extern int cJSON_GetArraySize(cJSON *array);

Get the element at the specified position in the Json array. If it returns NULL, it means that the value acquisition failed.

extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);

2.4 Serialization

Serialization is the process of converting data in Json format into strings. The cJson library provides us with 3 conversion functions, as follows:

The first parameter item represents the root node of the Json data block.

extern char  *cJSON_Print(cJSON *item);
extern char  *cJSON_PrintUnformatted(cJSON *item);
extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
  • Calling  cJSON_Print() the function we can get a formatted Json string (with newlines, it looks more intuitive)

  • Calling  cJSON_PrintUnformatted() the function will get an unformatted Json string (no line breaks, all data on the same line).

  • The calling  cJSON_PrintBuffered() function uses the buffer strategy to convert the Json entity into a string. The parameter prebuffer is the size of the specified buffer, and the parameter  fmt==0 means unformatted and fmt==1 formatted.

During the encoding process, we can call the relevant operation functions according to our actual needs to obtain the Json string in the corresponding format.

2.5 Parsing of Json strings

If we get a string in Json format and want to read the data in it, we need to parse the string. The processing method is to convert the string into a cJSON structure, and then read the original data inside based on this structure. Data, the function prototype of the conversion function is as follows:

extern cJSON *cJSON_Parse(const char *value);

2.6 Memory release

When we encapsulate the data into a node of cJSON structure type, we will get a piece of heap memory. When we release a node, we can call the delete function provided by the cJson library. The function prototype is as follows  cJSON_Delete():

extern void   cJSON_Delete(cJSON *c);

The parameter of this function is the address of the node to be released. Here we emphasize one point: when the memory address is released, the current node and its child nodes will be deleted.

3. Encapsulation of Json data

3.1 Example of Json object operation

Create an object and add string and integer keys to this object:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"cJSON.h"
 
int main()
{
    cJSON * root;
    cJSON *arry;

    root=cJSON_CreateObject();                     // 创建根数据对象
    cJSON_AddStringToObject(root,"name","luffy");  // 添加键值对
    cJSON_AddStringToObject(root,"sex","man");     // 添加键值对
    cJSON_AddNumberToObject(root,"age",19);        // 添加键值对

    char *out = cJSON_Print(root);   // 将json形式转换成字符串
    printf("%s\n",out);

    // 释放内存  
    cJSON_Delete(root);  
    free(out);        
}

operation result

{
 "name": "luffy",
 "sex": "man",
 "age": 19
}

Some clarifications:

  • cJSON_CreateObject The function can create a root object and return a cJSON pointer. After the pointer is used up, it needs to be called manually  cJSON_Delete(root) for memory recovery.

  • The malloc function is encapsulated inside the function  cJSON_Print() , so the free() function needs to be used to release the memory space occupied by out.

3.2 Example of Json array operation

Create an array and add a string and a number to the array

int main(int argc, char **argv)
{
    cJSON *root;
    root = cJSON_CreateArray();
    cJSON_AddItemToArray(root, cJSON_CreateString("Hello world"));
    cJSON_AddItemToArray(root, cJSON_CreateNumber(10)); 
    // char *s = cJSON_Print(root);
    char *s = cJSON_PrintUnformatted(root);
    if(s)
    {
        printf(" %s \n",s);
        free(s);
    }
    cJSON_Delete(root);
    return 0;
}

operation result:

["Hello world",10]

3.3 Nested use of Json objects and arrays

The object contains an array, the array contains objects, and a string and a number are added to the object

{
    "person":[{
        "name":"luffy",
        "age":19
    }]
}

Sample code:

int main(int argc, char **argv)
{
    cJSON *root, *body, *list;
    // josn 对象 root
    root = cJSON_CreateObject();
    // root 添加键值对 person:json数组A
    cJSON_AddItemToObject(root,"person", body = cJSON_CreateArray());
    // json数组A 添加Json对象B
    cJSON_AddItemToArray(body, list = cJSON_CreateObject());
    // 在json对象B中添加键值对: "name":"luffy"
    cJSON_AddStringToObject(list,"name","luffy");
    // 在json对象B中添加键值对: "age":19
    cJSON_AddNumberToObject(list,"age",19);
 
    // char *s = cJSON_Print(root);
    char *s = cJSON_PrintUnformatted(root);
    if(s)
    {
        printf(" %s \n",s);
        free(s);
    }
    if(root)
    {
        cJSON_Delete(root); 
    }
    return 0;
}

operation result:

{"person":[{"name":"luffy","age":19}]}

4. Parse the Json string

4.1 Parsing Json objects

The parsing process of the Json string is opposite to the encapsulation process of the data. Suppose we have such a Json string (the double quotes in the string need to be translated into ordinary characters by escape characters):

{\"name\":\"luffy\",\"sex\":\"man\",\"age\":19}

The sample code is as follows:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
 
int main()
{
    cJSON *json, *name, *sex, *age;
    char* out="{\"name\":\"luffy\",\"sex\":\"man\",\"age\":19}";
 
    json = cJSON_Parse(out); //解析成json形式
    name = cJSON_GetObjectItem(json, "name");  //获取键值内容
    sex = cJSON_GetObjectItem(json, "sex");
    age = cJSON_GetObjectItem(json, "age");
 
    printf("name:%s,sex:%s,age:%d\n", name->valuestring, sex->valuestring, age->valueint);
 
    cJSON_Delete(json);  //释放内存 
}

Output result:

name:luffy,sex:man,age:19

If it is in a strict place, the type of each item should be determined first, and then the value should be considered .

4.2 Parsing nested Json objects

To make it a little more difficult, let's parse a nested Json object, the data is as follows:

{\"list\":{\"name\":\"luffy\",\"age\":19},\"other\":{\"name\":\"ace\"}}
int main()
{
    char *s = "{\"list\":{\"name\":\"luffy\",\"age\":19},\"other\":{\"name\":\"ace\"}}";
    cJSON *root = cJSON_Parse(s);
    if(!root) 
    {
        printf("get root faild !\n");
        return -1;
    }

    cJSON *js_list = cJSON_GetObjectItem(root, "list");
    if(!js_list) 
    {
        printf("no list!\n");
        return -1;
    }
    printf("list type is %d\n",js_list->type);

    cJSON *name = cJSON_GetObjectItem(js_list, "name");
    if(!name) 
    {
        printf("No name !\n");
        return -1;
    }
    printf("name type is %d\n",name->type);
    printf("name is %s\n",name->valuestring);

    cJSON *age = cJSON_GetObjectItem(js_list, "age");
    if(!age) 
    {
        printf("no age!\n");
        return -1;
    }
    printf("age type is %d\n", age->type);
    printf("age is %d\n",age->valueint);

    cJSON *js_other = cJSON_GetObjectItem(root, "other");
    if(!js_other) 
    {
        printf("no list!\n");
        return -1;
    }
    printf("list type is %d\n",js_other->type);

    cJSON *js_name = cJSON_GetObjectItem(js_other, "name");
    if(!js_name) 
    {
        printf("No name !\n");
        return -1;
    }
    printf("name type is %d\n",js_name->type);
    printf("name is %s\n",js_name->valuestring);

    if(root)
    {
        cJSON_Delete(root);
    }
    return 0;
}

print result:

list type is 6
name type is 4
name is luffy
age type is 3
age is 19
list type is 6
name type is 4
name is ace

4.3 Parsing Json array

If the Json string we encounter is in a Json array format, the processing method is similar to that of a Json object. For example, we want to parse the following string:

{\"names\":[\"luffy\",\"robin\"]}
int main(int argc, char **argv)
{
    char *s = "{\"names\":[\"luffy\",\"robin\"]}";
    cJSON *root = cJSON_Parse(s);
    if(!root) 
    {
        printf("get root faild !\n");
        return -1;
    }
    cJSON *js_list = cJSON_GetObjectItem(root, "names");
    if(!js_list)
    {
        printf("no list!\n");
        return -1;
    }
    int array_size = cJSON_GetArraySize(js_list);
    printf("array size is %d\n",array_size);
    for(int i=0; i< array_size; i++) 
    {
        cJSON *item = cJSON_GetArrayItem(js_list, i);
        printf("item type is %d\n",item->type);
        printf("%s\n",item->valuestring);
    }

    if(root)
    {
        cJSON_Delete(root);
    }
    return 0;
}

4.4 Parsing nested Json objects and arrays

The most complex number of Json strings is the nested form of Json objects and Json arrays. Here is an example to demonstrate how to parse them. The string format is as follows:

{\"list\":[{\"name\":\"luffy\",\"age\":19},{\"name\":\"sabo\",\"age\":21}]}

When parsing, we only need to parse layer by layer according to the affiliation relationship:

  • The root node is a Json object, based on the key value in the root node, the corresponding value is taken out, and a Json array is obtained

  • Read the size of the Json array, and traverse each element inside, each element is a Json object

  • Extract the corresponding value value from the key-value pair in the Json object according to the key value

  • The sample code for reading the value corresponding to the actual type from the retrieved Value is as follows:

#include "cJSON.h"
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    char *s = "{\"list\":[{\"name\":\"luffy\",\"age\":19},{\"name\":\"sabo\",\"age\":21}]}";
    cJSON *root = cJSON_Parse(s);
    if(!root) 
    {
        printf("get root faild !\n");
        return -1;
    }
    cJSON *list = cJSON_GetObjectItem(root, "list");
    if(!list)
    {
        printf("no list!\n");
        return -1;
    }
    int array_size = cJSON_GetArraySize(list);
    printf("array size is %d\n",array_size);
    
    for(int i=0; i< array_size; i++) 
    {
        cJSON* item = cJSON_GetArrayItem(list, i);
        cJSON* name = cJSON_GetObjectItem(item, "name");
        printf("name is %s\n",name->valuestring);
        cJSON* age = cJSON_GetObjectItem(item, "age");
        printf("age is %d\n",age->valueint);
    }

    if(root)
    {
        cJSON_Delete(root);
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_41114301/article/details/132397101