前言
最近拿到了一个编码方式为GB2312的.json文件,那么我们应该如何使用cJSON去解析呢?
一、编码格式统一?
首先我们要知道到.json文件是什么编码格式,那么我们只需要将文件用nodepad++工具打开就可以在右下角看到了。
然后我们要查看的就是我们使用的虚拟机的编码方式是什么,在这里我使用的是locale命令,结果如下图所示,我发现他的编码方式是UTF-8格式,但是我的.json编码格式是GB2312,如果直接将文件放进编译器进行编译打印就会出现很多的乱码,将文件转为UTF-8的方式应该有很多,在这里我就分享一种方式。首先将文件用nodepad++打开,然后复制文件内容,之后黏贴到记事本,选择使用另存方式,在底下编码方式中选择UTF-8格式,然后将.txt重命名为.json,这样我们的.json文件就变成了UTF-8的格式了。
二、构建文件并解析
1.引入cJSON库
cJSON库文件,只需要两个文件,一个是cJSON.c,一个是cJSON.h,我们需要做的就是写一个.c文件将这两个文件也加入编译就行了。下载cJSON源码文件。
2.解析json报文或文件
头文件
#ifndef __JSON_H
#define __JSON_H
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include "cJSON.h"
#endif
.c文件
#include "json.h"
//创建多个JSON对象
int create_objects(cJSON **root)
{
cJSON *fmt;
cJSON *arr;
cJSON *number,*img,*thm,*fld,*intput,*idds;
int i,arr_size;
const char *strings[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
int numbers[3][3]={{0,-1,0},{1,0,0},{0,0,1}};
int ids[4]={116,943,234,38793};
//创建子节点
*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);
cJSON_AddItemToObject(*root, "format", arr=cJSON_CreateStringArray(strings,7));
cJSON_AddItemToObject(*root,"nums",number = cJSON_CreateArray());
for (i=0;i<3;i++) cJSON_AddItemToArray(number,cJSON_CreateIntArray(numbers[i],3));
//改变数组成员参数
//cJSON_ReplaceItemInArray(number,0,cJSON_CreateString("Replacement"));
//增加数组成员
cJSON_AddItemToObject(*root, "Image", img=cJSON_CreateObject());
cJSON_AddNumberToObject(img,"Width",800);
cJSON_AddNumberToObject(img,"Height",600);
cJSON_AddStringToObject(img,"Title","View from 15th Floor");
cJSON_AddItemToObject(img, "Thumbnail", thm=cJSON_CreateObject());
cJSON_AddStringToObject(thm, "Url", "http:/*www.example.com/image/481989943");
cJSON_AddNumberToObject(thm,"Height",125);
cJSON_AddStringToObject(thm,"Width","100");
cJSON_AddItemToObject(img,"IDs", idds = cJSON_CreateIntArray(ids,4));
//删除对应星期
// cJSON_DeleteItemFromArray(arr, 2);
// cJSON_DetachItemFromObject(*root, "Image");
//查询
intput = cJSON_GetObjectItem(fmt, "width");
// printf("width = %d\n",intput->valueint);
//统计数组个数
arr_size = cJSON_GetArraySize(idds);
//查询数组具体内容
#if 0
for(i = 0; i < arr_size;i++)
{
intput = cJSON_GetArrayItem(idds, i);
printf("width = %d\n",intput->valueint);
}
printf("--------------------------------------------\n");
#endif
return 0;
}
//解析
cJSON *parse_objects(cJSON *root)
{
int arr_size,i;
cJSON *imn,*imu;
//获取对应节点的地址
imn = cJSON_GetObjectItem(root,"image");
imu = cJSON_GetObjectItem(imn,"IDs");
arr_size = cJSON_GetArraySize(imu);
for(i = 0; i < arr_size; i++)
{
printf("IDs[%d] = %d\n",i,cJSON_GetArrayItem(imu,i)->valueint);
}
return imu;
}
int doit(char *text)
{
cJSON *json,*value,*maxf;
char *out;
int i,arr_size;
json = cJSON_Parse(text);
if (!json)
{
printf("Error before: [%s]\n",cJSON_GetErrorPtr());
}
// printf("%s\n",cJSON_GetObjectItem(json,"CapturemodeName")->valuestring);
value = cJSON_GetObjectItem(json,"capturemodes");
arr_size = cJSON_GetArraySize(value);
for(i = 0; i < arr_size; i++)
{
maxf = cJSON_GetArrayItem(value,i);
printf("maxFrame[%d] = %d\n",i,cJSON_GetObjectItem(maxf,"maxFrame")->valueint);
}
// out = cJSON_Print(json);
// printf("%s\n",out);
printf("####################################################\n");
cJSON_Delete(json);
return 0;
}
int main(int argc,const char* argv[])
{
cJSON* root,*arr;
char *out;
int fd;
int numread;
char list[10240];
fd = open("json.json",O_RDONLY);
if(-1 == fd)
{
printf("fail to open");
return 0;
}
while((numread = read(fd,list,10240)) > 0)
{
doit(list);
}
//创建JSON格式内容
create_objects(&root);
arr = parse_objects(root);
//将内容按JSON规格标准打印
out = cJSON_Print(arr);
printf("%s\n",out);
cJSON_Delete(root);
// cJSON_Delete(arr);
}
三、函数接口概况
1.核心结构体:
typedef struct cJSON
{
struct cJSON *next,*prev;
struct cJSON *child;
int type;
char *valuestring;
int valueint;
double valuedouble;
char *string;
}cJSON
struct cJSON *next,*prev; 表示同级数据之间用双向链表连接,struct cJSON *child;表示不同级之间用树连接。int type;表示数据类型。char *valuestring;表示当类型为字符串类型是,字符串类型的值,int valueint; double valuedouble;表示类型为数字是的数字值,有int和double两种类型。char *string;表示节点名称。
各个接口说明:
整个代码各个函数接口的功能,总的来讲分为6个部分。
-
创建节点基本类型函数接口。例如:cJSON_CreateString(const char *string);这里面有6种基本类型,所以对应的创建基本类型的函数接口也有六种。
- 创建对象或数组类型节点。例如:cJSON_CreateObject(void); 这种一般是建立在有多个基本类型节点需要放在一个对象或者一个数组中是来进行创建的。
- 将基本类型节点加入对象或者数组中。例如:cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);在这个函数中只需要知道需要加入的对象节点,要加入的名称,以及添加的节点即可。当然添加数组也是这样。后面的节点可以是对象,也可以是数组。
- 对添加进来的节点信息进行删除,修改,和查询。这里面依次用到的是cJSON_Delete*,cJSON_Replace*,cJSON_Get*,基本都是知词答意,而且用起来也不困难。
- 最后就是解析使用的,cJSON_Prase(const char *string);这个函数其实也可以用上面讲述的带有Add的函数接口依次实现,但是如果我们所要解析的问价数量有点大是,我还是建议去使用这个函数。他的返回值,就是将所有数据打包成JSON格式之后的根节点地址。
最后就是cJSON_Print(cJSON *root);这个函数是将整个数据遍历,然后以字符串的格式,将返回值返回,方便使用者随时查看使用的。其次就是一些小函数了,比如转进制的函数,或者转编码方式的函数接口都是有的。
总结
这里代码部分其实就是对这cJSON函数库的调用,解析方式包含了很多种的方式,但是只要理解了我们是如何将json报文或文件添加到cJSON标准格式的过程后,解析对于我们来说就是反向过程,而我们所需要做的就是调用不同的接口罢了,希望这一篇文章对大家有用。