JSON格式学习和cJSON解析的基本操作

一、JSON是什么?

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。简单来说就是一种文件格式,官方介绍

JSON文件中只有两种结构:

  • 对象(object),也就是键值对,形式如{ “key1”: value1, “key2”: value2}
  • 数组(array),形式如[value1, value2, value3]

其中value可以是字符串string,整型number,布尔型true,false,null,或者是对象object,数组array。但是JSON对象中的key值必须是字符串,而且不能重复。

JSON 对象

{
    "name": "Jack (\"Bee\") Nimble", 
    "format": {
        "type":       "rect", 
        "width":      1920, 
        "height":     1080, 
        "interlace":  false, 
        "frame rate": 24
    }
}

JSON数组

["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
[
    [0, -1, 0],
    [1, 0, 0],
    [0, 0, 1]
]

二、cJSON开源库的安装

cJSON是一个开源的JSON解析器,该项目包含了cJSON.ccJSON.h两个文件。

cJSON官方下载网站:https://github.com/DaveGamble/cJSON

下载完成后无安装,只需要将cJSON.ccJSON.h两个文件拷贝到项目的文件夹下即可。

使用下面命令编译一个使用cJSON的小例子:(解压的目录下有相关文件)

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

cJSON结构体的具体代码:

typedef struct cJSON {
	struct cJSON *next,*prev;
	struct cJSON *child;

	int type;

	char *valuestring;
	int valueint;
	double valuedouble;

	char *string;
} cJSON;

cJSON默认所有值都为0,除非额外为其赋有意义的值。

next/prev是一个双向链表中的兄弟。next指向链表中下一个兄弟节点,prev指向本节点前一个节点。 只有对象和数组有child节点,并且child节点是双向链表的头节点。child的prev一般为NULL,不指向任何节点,而next一般是有指向的。 双向链表的最后一个兄弟节点的next是无指向的。

type取值如下:Null/True/False/Number/String/Array/Object。这些值类型都在cJSON.h中通过宏定义了。

Number类型节点有valueint和valuedouble。如果你想要整形值,读取valueint,否则读取valuedouble。

string表示节点的名称。所有的节点都是一个链表,都具有string值。

三、cJSON的基本操作

根据官网的demo,test.c文件,编写两个程序create_json.cread_json.ccreate_json.c主要生成vedio.json文件,然后read_json.c再从vedio.json中解析,并打印显示。

video.json文件内容:

{
	"name":	"Jack (\"Bee\") Nimble",
	"format":	{
		"type":	"rect",
		"width":	1920,
		"height":	1080,
		"interlace":	false,
		"frame rate":	24
	},
	"JSON arr1":["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
	"JSON arr2":[[0, -1, 0], [1, 0, 0], [0, 0, 1]]
}

cJSON相关的函数解释可以参考这个cJSON的中文文档,链接在这里
create_json.c文件内容:

/******************************************************************************
 * File:             create_json.c
 *
 * Author:           Seaworth  
 * Created:          03/07/20 
 * Description:      采用cJSON生成一个JSON格式的文件
 *****************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include "cJSON.h"

int main(int argc, char *argv[])
{
	/* Our "Video" datatype: */
	cJSON *root,*fmt;
	root = cJSON_CreateObject();
	cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
	cJSON_AddItemToObject(root, "format", fmt = cJSON_CreateObject());
	cJSON_AddStringToObject(fmt, "type", "rect");
	cJSON_AddNumberToObject(fmt, "width", 1920);
	cJSON_AddNumberToObject(fmt, "height", 1080);
	cJSON_AddFalseToObject (fmt, "interlace");
	cJSON_AddNumberToObject(fmt, "frame rate", 24);

	// 添加一个JSON arrays到root
	cJSON *arr1;
	cJSON_AddItemToObject(root, "JSON arr1", arr1 = cJSON_CreateArray());
	cJSON_AddItemToArray(arr1, cJSON_CreateString("Sunday"));
	cJSON_AddItemToArray(arr1, cJSON_CreateString("Monday"));
	cJSON_AddItemToArray(arr1, cJSON_CreateString("Tuesday"));
	cJSON_AddItemToArray(arr1, cJSON_CreateString("Wednesday"));
	cJSON_AddItemToArray(arr1, cJSON_CreateString("Thursday"));
	cJSON_AddItemToArray(arr1, cJSON_CreateString("Friday"));
	cJSON_AddItemToArray(arr1, cJSON_CreateString("Saturday"));

	cJSON *arr2;
	cJSON *arr2_1, *arr2_2, *arr2_3;
	cJSON_AddItemToObject(root, "JSON arr2", arr2 = cJSON_CreateArray());
	cJSON_AddItemToArray(arr2, arr2_1 = cJSON_CreateArray());
	cJSON_AddItemToArray(arr2_1, cJSON_CreateNumber(0));
	cJSON_AddItemToArray(arr2_1, cJSON_CreateNumber(-1));
	cJSON_AddItemToArray(arr2_1, cJSON_CreateNumber(0));

	cJSON_AddItemToArray(arr2, arr2_2 = cJSON_CreateArray());
	cJSON_AddItemToArray(arr2_2, cJSON_CreateNumber(1));
	cJSON_AddItemToArray(arr2_2, cJSON_CreateNumber(0));
	cJSON_AddItemToArray(arr2_2, cJSON_CreateNumber(0));

	cJSON_AddItemToArray(arr2, arr2_3 = cJSON_CreateArray());
	cJSON_AddItemToArray(arr2_3, cJSON_CreateNumber(0));
	cJSON_AddItemToArray(arr2_3, cJSON_CreateNumber(0));
	cJSON_AddItemToArray(arr2_3, cJSON_CreateNumber(1));

	// 将JSON数据转换为字符串,写入文件中
	char* data = cJSON_Print(root);
	printf("json:\n%s\n", data);

	FILE* fp = fopen("video.json", "w");
	fwrite(data, sizeof(char), strlen(data)+1, fp);

	fclose(fp);
	cJSON_Delete(root);
	free(data);

	return 0;
}

read_json.c文件内容:

/******************************************************************************
 * File:             read_json.c
 *
 * Author:           Seaworth  
 * Created:          03/07/20 
 * Description:      读取JSON格式的文件,对其进行解析
 *****************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>

#include "cJSON.h"

// 定义结构体,方便后面解析数据,保存
typedef struct{
	char type[32];
	int width;
	int height;
	int interlace;
	int frame_rate;
}format;

/* Parse text to JSON, then render back to text, and print! */
void doit(char *text)
{
	char *out;cJSON *json;

	json=cJSON_Parse(text);
	if (!json) {printf("Error before: [%s]\n",cJSON_GetErrorPtr());}
	else
	{
		out=cJSON_Print(json);
		printf("print json:\n");
		printf("%s\n",out);
	}
	printf("================================\n");
	printf("parse json:\n");
	cJSON *name=cJSON_GetObjectItem(json,"name"); 
	if(name != NULL){
		printf("name: %s\n", cJSON_Print(name));
	}

	cJSON *fmt=cJSON_GetObjectItem(json,"format"); 
	if(fmt != NULL){
		cJSON *item;
		format f1;
		item=cJSON_GetObjectItem(fmt,"type");
		memcpy(f1.type,item->valuestring,strlen(item->valuestring));
		item=cJSON_GetObjectItem(fmt,"width");
		f1.width = item->valueint;
		item=cJSON_GetObjectItem(fmt,"height");
		f1.height = item->valueint;
		item=cJSON_GetObjectItem(fmt,"interlace");
		f1.interlace = item->valueint;
		item=cJSON_GetObjectItem(fmt,"frame rate");
		f1.frame_rate = item->valueint;

		// 打印format的信息
		printf("format: type=%s, width=%d, height=%d, interlace=%d, frame rate=%d\n", 
				f1.type, f1.width, f1.height, f1.interlace, f1.frame_rate);
	}

	cJSON *arr1=cJSON_GetObjectItem(json,"JSON arr1"); 
	if(arr1 != NULL){
		printf("JSON arr1:\n");
		for (int i = 0; i < cJSON_GetArraySize(arr1); ++i) {
			cJSON *node = cJSON_GetArrayItem(arr1, i);
			printf("%s", node->valuestring);
			if(i < cJSON_GetArraySize(arr1)-1){
				printf(", ");
			}
		}	
	}
	cJSON *arr2=cJSON_GetObjectItem(json,"JSON arr2"); 
	if(arr2 != NULL){
		printf("\nJSON arr2:\n");
		for (int i = 0; i < cJSON_GetArraySize(arr2); ++i) {
			cJSON *node1 = cJSON_GetArrayItem(arr2, i);
			for (int j = 0; j < cJSON_GetArraySize(node1); ++j) {
				cJSON *node2 = cJSON_GetArrayItem(node1, j);
				printf("%d", node2->valueint);
				if(j < cJSON_GetArraySize(node1)-1){
					printf(", ");
				}
			}
			printf("\n");
		}
	}

	cJSON_Delete(json);
	free(out);
}

/* Read a file, parse, render back, etc. */
void dofile(char *filename)
{
	FILE *f;long len;char *data;

	f=fopen(filename,"rb");fseek(f,0,SEEK_END);len=ftell(f);fseek(f,0,SEEK_SET);
	data=(char*)malloc(len+1);fread(data,1,len,f);fclose(f);
	doit(data);
	free(data);
}
int main(int argc, char *argv[])
{
	dofile("video.json");
	return 0;
}

编译指令:

gcc cJSON.c create_json.c -o create_json -lm
gcc cJSON.c read_json.c -o read_json -lm
./create_json
./read_json

./read_json的运行结果如下:

在这里插入图片描述

四、参考

  1. cJSON项目
  2. cJSON官方文档翻译
  3. JSON简介
  4. 使用cJSON解析JSON字符串
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章