最近接触到的一个项目,需要使用json数据格式上传几类数据,于是近期把json格式学习了一下,体会到了json作为一类通用的数据传输格式,能够为不同介质间的数据传输带来多大的便利。
虽然json本身并不复杂,但实际项目中难免遇到许多嵌套层次非常复杂的数据,像本咸鱼这次虽然只封装了5条数据,却写了300行代码。好在借助简洁的cJSON工具,让整个写代码的过程虽然枯燥,但逻辑却不复杂。

json介绍

以下内容摘自百度百科:
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

一款轻量级的json数据解析工具——cJSON

cJSON是一个使用C语言编写的JSON数据解析器,具有超轻便,可移植,单文件的特点,使用MIT开源协议。

cJSON项目托管在Github上,仓库地址如下:

https://github.com/DaveGamble/cJSON

使用Git命令将其拉取到本地:

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

进入cJSON文件夹,输入指令生成相关文件并链接系统库:

make
sudo make install

注:在之后写代码的过程中需要将生成的cJSON.c文件复制到你工程所在的文件夹。

封装多层嵌套的json数据

在学习json时我们会看到很多例子,里面会教你封装一些简单的json数据。但是如果你所需要封装的数据嵌套格式非常多,像下面这样:

{
    “msgCnt”: 20,
    “timestamp”: 1576800000,
    “nodes”:
    [
        {
            “name”: “node1”,
            “nodeId”: 
            {
                “region”: 25,
                “id”: 1001 
            },
            “refPos”: 
            {
                “lat”: 32.1234567, 
                “lon”: 112.1234567, 
                “elevation”: 20.2 
            },
            “inLinks”: 
            [
                {
                    “name”: “link1”, 
                    “upstreamNodeId”:
                    {
                        “region”:25, 
                        “id”: 1002 
                    },
                    “speedLimits”:
                    [
                        {
                            “type”: 5, 
                            “speed”: 1667 
                        }
                    ],
                    “laneWidth”: 300, 
                    “lanes”: 
                    [
                        {
                            “laneId”: 1
                        },
                        {
                            “laneId”: 2 
                        }
                    ],
                    “movements”:
                    [
                        {
                            “remoteIntersection”:
                            {
                                “region”: 25,
                                “id”: 1003,
                            },
                            “phaseId”: 1 
                        },
                        {
                            “remoteIntersection”: 
                            {
                                “region”: 25, 
                                “id”: 1004
                            },
                            “phaseId”: 2 
                        }
                    ]
                }
            ]
        }
    ]
}

该如何去编写代码呢?
我们的cJSON包里有如下几类函数可以调用:

cJSON_AddNullToObject(cJSON * const object, const char * const name);

cJSON_AddTrueToObject(cJSON * const object, const char * const name);

cJSON_AddFalseToObject(cJSON * const object, const char * const name);

cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);

cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);

cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);

cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);

cJSON_AddObjectToObject(cJSON * const object, const char * const name);

cJSON_AddArrayToObject(cJSON * const object, const char * const name);

封装JSON数据的过程,其实就是创建链表和向链表中添加节点的过程。
我先放一下我的代码:

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

int main()
{
	char* str;
	
	cJSON* cjson_test = NULL;
    cJSON* cjson_address = NULL;
    cJSON* cjson_address0 = NULL;
    cJSON* cjson_address1 = NULL;
    cJSON* cjson_address2 = NULL;
    cJSON* cjson_address3 = NULL;
    cJSON* cjson_address4 = NULL;
    cJSON* cjson_address5 = NULL;
    cJSON* cjson_address6 = NULL;
    cJSON* cjson_address7 = NULL;
    cJSON* cjson_skill = NULL;
    cJSON* cjson_skill0 = NULL;
    cJSON* cjson_skill1 = NULL;
    cJSON* cjson_skill2 = NULL;
    cJSON* cjson_skill3 = NULL;
    
    cjson_test = cJSON_CreateObject();
    cJSON_AddNumberToObject(cjson_test, "msgCnt", 20);
    cJSON_AddNumberToObject(cjson_test, "timeStamp", 1576800000);
    cjson_skill = cJSON_CreateArray();
    cJSON_AddItemToObject(cjson_test, "nodes", cjson_skill);
    cjson_address = cJSON_CreateObject();
    cJSON_AddItemToObject(cjson_skill, "nodes", cjson_address);
    cJSON_AddStringToObject(cjson_address, "name", "node1");
    
    cjson_address0 = cJSON_CreateObject();
    cJSON_AddItemToObject(cjson_address, "nodeId", cjson_address0);
    cJSON_AddNumberToObject(cjson_address0, "region", 25);
    cJSON_AddNumberToObject(cjson_address0, "id", 1001);
    
    cJSON_AddItemToObject(cjson_address, "refPos", cjson_address7);
    cJSON_AddNumberToObject(cjson_address7, "lat", 32.1234567);
    cJSON_AddNumberToObject(cjson_address7, "lon", 112.1234567);
    cJSON_AddNumberToObject(cjson_address7, "elevation", 20.2);
    
    cjson_skill0 = cJSON_CreateArray();
    cJSON_AddItemToObject(cjson_address, "inLinks", cjson_skill0);
    cjson_address1 = cJSON_CreateObject();
    cJSON_AddItemToObject(cjson_skill0, "inLinks", cjson_address1);
    cJSON_AddStringToObject(cjson_address1, "name", "link1");
    
    cjson_address2 = cJSON_CreateObject();
    cJSON_AddItemToObject(cjson_address1, "upstreamNodeLd", cjson_address2);
    cJSON_AddNumberToObject(cjson_address2, "region", 25);
    cJSON_AddNumberToObject(cjson_address2, "id", 1002);
    
    cjson_skill1 = cJSON_CreateArray();
    cJSON_AddItemToObject(cjson_address1, "speedLimits", cjson_skill1);
    cjson_address3 = cJSON_CreateObject();
    cJSON_AddItemToObject(cjson_skill1, "nodes", cjson_address3);
    cJSON_AddNumberToObject(cjson_address3, "type", 5);
    cJSON_AddNumberToObject(cjson_address3, "speed", 1667);
    cJSON_AddNumberToObject(cjson_address3, "laneWidth", 300);

    cJSON_AddItemToObject(cjson_address1, "lanes", cjson_skill2);
    cJSON_AddItemToObject(cjson_skill2, "lanes", cjson_address3);
    cJSON_AddNumberToObject(cjson_address3, "laneId", 1);
    cjson_address4 = cJSON_CreateObject();
    cJSON_AddItemToObject(cjson_skill2, "lanes", cjson_address4);
    cJSON_AddNumberToObject(cjson_address4, "laneId", 2);
    
    cJSON_AddItemToObject(cjson_address1, "movements", cjson_skill3);
    cJSON_AddItemToObject(cjson_skill3, "movements", cjson_address3);
    cjson_address5 = cJSON_CreateObject();
    cJSON_AddItemToObject(cjson_address3, "remoteIntersection", cjson_address5);
    cJSON_AddNumberToObject(cjson_address5, "region", 25);
    cJSON_AddNumberToObject(cjson_address5, "id", 1003);
    cJSON_AddNumberToObject(cjson_address3, "phaseId", 1);
    
    cjson_address6 = cJSON_CreateObject();
    cJSON_AddItemToObject(cjson_address3, "remoteIntersection", cjson_address6);
    cJSON_AddNumberToObject(cjson_address6, "region", 25);
    cJSON_AddNumberToObject(cjson_address6, "id", 1004);
    cJSON_AddNumberToObject(cjson_address3, "phaseId", 2);
    
    str = cJSON_Print(cjson_test);
    printf("%s\n", str);
    
    return 0;
}

输入编译指令并运行:

gcc test.c cJSON.c -o test
./test

输出结果:

java 多层 嵌套 json 解析为对象 多层嵌套json格式_结点


总的来说就是几个关键点:

1)cJSON_AddNumberToObject()和cJSON_AddStringToObject()函数用于添加一个新的结点并赋值(赋数字和字符串);

2)cJSON_AddItemToObject()函数用于添加一个新的结点分支,第一个参数必须为上一个结点的表达式,第三个参数为下一个结点的表达式;

3)新的结点如果是对象(大括号括起来的是对象),结点用cJSON_CreateObject()函数添加;

4)新的结点如果是数组(中括号括起来的是数组),结点用cJSON_CreateArray()函数添加;