1、前言
项目中常用Json格式的数据进行数据mqtt传输或者配置文件读取等操作,本文将常用接口做简单测试给大家参考。
2、Json格式
2.1 Json结构体格式
typedef struct cJSON
{
/* 通过next/prev 可以找到同级节点或者使用 GetArraySize/GetArrayItem/GetObjectItem等接口来查找同级节点*/
struct cJSON *next;
struct cJSON *prev;
/* 子节点指针 */
struct cJSON *child;
/* key的类型 */
int type;
/* value类型为字符串时存放字符串首地址 */
char *valuestring;
// 测试了一下valueint和valuedouble
// 当置入整数值的时候,比如12 valueint为12,valuedouble为12.0
// 当置入小数值的时候,比如12.333 valueint为12,valuedouble为12.333
/* value类型为数值时存放该数值 */
int valueint;
/* value类型为数值时存放该数值 */
double valuedouble;
/* key的名称 */
char *string;
} cJSON;
2.2 常用接口
部分常用的接口整理如下:
/**********************创建节点常用接口**********************/
// 创建节点对象
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
// 创建数组节点对象
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
// 创建count个key的相应数据类型的节点对象
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);
/**********************填充节点常用接口**********************/
// 向object节点对象中添加键值对 其中key为name value为number
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
// 向object节点对象中添加键值对 其中key为name value为string
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
// 向object节点对象中添加名称为name的对象节点
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
// 向object节点对象中添加名称为name的数组对象节点
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
// 向array数组中添加item节点对象
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
/**********************解析节点常用接口**********************/
// 从object节点对象中查找key为string的节点作为返回值返回
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
// 获取数组中元素个数
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
// 根据index索引返回数组中节点对象
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/***********************转换常用接口*************************/
// 将item整个序列打印出来 格式清晰有换行
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
// 将item整个序列打印出来 只有一整行 无回车等
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
// 将json格式的字符串转为节点对象
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
/***********************内存释放接口*************************/
// 释放object节点内存 包含其子节点
CJSON_PUBLIC(void) cJSON_free(void *object);
3、测试用例
3.1 简单数据组织
创建两个节点对象,分别向两个节点对象中添加数字和字符串键值对,然后进行格式化输出,代码如下:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main()
{
cJSON *root = NULL;
cJSON *bodymsg = NULL;
char *pString = NULL;
// 创建根节点
root = cJSON_CreateObject();
// 创建body节点
bodymsg = cJSON_CreateObject();
// 向bodymsg中添加键值对
cJSON_AddNumberToObject(bodymsg, "BdTestNum", (double)12);
cJSON_AddItemToObject(bodymsg, "BdTestStr", cJSON_CreateString("bodystring"));
// 向root中添加键值对
cJSON_AddNumberToObject(root, "NumTest", (double)1.23);
cJSON_AddItemToObject(root, "StringTest", cJSON_CreateString("hello"));
cJSON_AddItemToObject(root, "body", bodymsg);
// 将root节点进行格式化输出并打印出来
pString = cJSON_Print(root);
printf("%s\n",pString);
// 内存释放
cJSON_Delete(root);
free(pString);
return 0;
}
测试输出结果:
3.2 数组数据组织
数组的组织相对复杂一点,测试代码如下:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main()
{
cJSON *root = NULL;
cJSON *arrymsg = NULL;
cJSON *arry1 = NULL;
cJSON *arry2 = NULL;
char *pString = NULL;
cJSON *arrystr = NULL;
char *pstr[4] = {"rng","we","edg","ig"};
// 创建根节点
root = cJSON_CreateObject();
// 创建arrymsg数组节点
arrymsg = cJSON_CreateArray();
// 创建数组内容节点
arry1 = cJSON_CreateObject();
arry2 = cJSON_CreateObject();
// 创建元素全为字符串的数组
arrystr = cJSON_CreateStringArray(pstr, 4);
// 添加键值对
cJSON_AddNumberToObject(arry1, "arr1", (double)12);
cJSON_AddItemToObject(arry2, "arr2", cJSON_CreateString("bodystring"));
// 向数组添加元素
cJSON_AddItemToArray(arrymsg, arry1);
cJSON_AddItemToArray(arrymsg, arry2);
// 向root中添加键值对
cJSON_AddNumberToObject(root, "NumTest", (double)1.23);
cJSON_AddItemToObject(root, "StringTest", cJSON_CreateString("hello"));
cJSON_AddItemToObject(root, "body", arrymsg);
cJSON_AddItemToObject(root, "strbody", arrystr);
// 将root节点进行格式化输出并打印出来
pString = cJSON_Print(root);
printf("%s\n",pString);
// 内存释放
cJSON_Delete(root);
free(pString);
return 0;
}
测试输出结果:
3.3 获取数据解析
读取json格式数据,进行数据解析和获取,读取文件内容如下:
测试代码:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main()
{
char configfile[1024] = {0};
FILE *pFile = fopen("test.json", "r");
int ret, iRet;
if (pFile == NULL)
{
return -1;
}
else
{
ret = fread(configfile, 1, sizeof(configfile), pFile);
fclose(pFile);
if (ret > 0)
{
cJSON * root = NULL;
// 将字符串json格式化
root = cJSON_Parse(configfile);
if (root == NULL)
{
return -1;
}
else
{
// 解析数据
char string[10] = {0};
int num = 0;
cJSON * temp;
cJSON * tempIn;
cJSON * tempInIn;
cJSON * arrData;
// 获取root下面的数值 先获取该对象节点
temp = cJSON_GetObjectItem(root, "rootnum");
printf("Get rootnum = %lf\n", temp->valuedouble);
// 获取第一个body中字符串的值进行打印 获取嵌套body中数字的值进行打印
temp = cJSON_GetObjectItem(root, "body");
// 第一个body是一个数组 并且只有一个元素
for(int i = 0; i < cJSON_GetArraySize(temp); ++i)
{
// 根据索引获取节点对象
tempIn = cJSON_GetArrayItem(temp, i);
// 获取body中第一个元素的bodystring对象并打印
tempInIn = cJSON_GetObjectItem(tempIn, "bodystring");
printf("Get bodystring = %s\n", tempInIn->valuestring);
// 获取嵌套body 并打印其中元素的值
tempInIn = cJSON_GetObjectItem(tempIn, "body");
// 嵌套的body也是一个数组 有三个元素
for(int j = 0; j < cJSON_GetArraySize(tempInIn); ++j)
{
arrData = cJSON_GetArrayItem(tempInIn, j);
printf("Get bodyIn No.[%d] = %d\n", j, arrData->valueint);
}
}
cJSON_Delete(root);
}
}
else
{
return -1;
}
}
return 0;
}
测试结果: