JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,可以把 JSON 的结构理解成无序的、可嵌套的 key-value 键值对集合,这些 key-value 键值对以结构体或数组的形式来组织的。同一级的 key-value 键值对之间用一个,(逗号) 隔开,每个 key-value 键值对是由一个 key 后面紧接一个:(冒号),冒号后面是这个 key 对应的 value。key 是一个 word,由大小写字母、下划线及数字组成,可以由双引号封闭,也可以不用双引号。而 value 的取值集为: number、boolean(true、false)、null、string、object 和 array。而cJSON则是一个用C 语言写JSON 解析库,特点就是一个简洁。
void create_json(const char *filename)//参数为输出文件名
{
printf("----------------create json start-----------------------------\n");
//组JSON
cJSON *root_json = cJSON_CreateObject();
cJSON *data_json = cJSON_CreateObject();
cJSON_AddItemToObject(root_json, "data", data_json);//基本的条目添加方法
// 原子条目创建&添加
// cJSON_AddItemToObject(data_json, "Null", cJSON_CreateNull());
// cJSON_AddItemToObject(data_json, "True", cJSON_CreateTrue());
// cJSON_AddItemToObject(data_json, "False", cJSON_CreateFalse());
// cJSON_AddItemToObject(data_json, "bool", cJSON_CreateBool(-1));//不等于0,true
// cJSON_AddItemToObject(data_json, "double", cJSON_CreateNumber(1.1));
// cJSON_AddItemToObject(data_json, "string", cJSON_CreateString("strings"));
// 一些直接的添加条目的方法,其实是通过宏添加对cJSON_AddItemToObject的参数实现
cJSON_AddNullToObject(data_json, "Null");
cJSON_AddTrueToObject(data_json, "True");
cJSON_AddFalseToObject(data_json, "False");
cJSON_AddBoolToObject(data_json, "bool", 0); //等于0,false
cJSON_AddNumberToObject(data_json, "double", 2.2);
cJSON_AddStringToObject(data_json, "string", "strings");
// 数组条目创建&添加
cJSON *total_array = cJSON_CreateArray();
cJSON_AddItemToObject(root_json, "array", total_array);//基本的条目添加方法
int i[] = {1, 2, 3};
float f[] = {1.2, 2.2, 3.3};
double d[] = {1.2, 2.2, 3.3};
char str1[] = "123";
char str2[] = "234";
char str3[] = "345";
const char *str[] = {str1, str2, str3};
cJSON_AddItemToArray(total_array, cJSON_CreateIntArray(i, 3));
cJSON_AddItemToArray(total_array, cJSON_CreateFloatArray(f, 3));
cJSON_ReplaceItemInArray(total_array, 2, cJSON_CreateDoubleArray(d, 3)); //替换2(第三个)
cJSON_InsertItemInArray(total_array, 0, cJSON_CreateStringArray(str, 3)); //插到第一
cJSON_AddItemToObject(root_json, "Replace", cJSON_CreateObject());
// 替换条目内容
cJSON_ReplaceItemInObject(root_json, "Replace", cJSON_CreateNull());
//分离和删除,略
//cJSON *DetachItem_object=cJSON_DetachItemFromObject(cJSON *object,const char *string);
//cJSON_DeleteItemFromObject(cJSON *object,const char *string);
//cJSON *DetachItem_arraycJSON_DetachItemFromArray(cJSON *array,int which);
//cJSON_DeleteItemFromArray(cJSON *array,int which);
//引用性添加节点,略
// cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
// cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
//复制条目,略
//cJSON *cJSON_Duplicate(cJSON *item,int recurse);
//打印JSON
char *out = cJSON_Print(root_json);
printf("%s\n", out);
FILE *fp = fopen(filename, "wb"); //写入文件
fprintf(fp, out);
fclose(fp);
free(out);
cJSON_Delete(root_json);
printf("----------------create json end-------------------------------\n");
}
void parse_json(const char *filename)//参数为输入文件名
{
printf("----------------parse json start-------------------------------\n");
//从文件中读取要解析的JSON数据
FILE *fp = fopen(filename, "rb");
fseek(fp, 0, SEEK_END);
long len = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *data = (char *)malloc(len + 1);
fread(data, 1, len, fp);
fclose(fp);
data[len] = '\0'; //修改最后的EOF为\0
printf("%s", data);
printf("\n");
//解析JSON数据
cJSON *root_json = cJSON_Parse(data); //将字符串解析成json结构体
if (NULL == root_json)
{
printf("error:%s\n", cJSON_GetErrorPtr());
cJSON_Delete(root_json);
return;
}
//解析一个条目
cJSON *one_item = cJSON_GetObjectItem(root_json, "data");
if (one_item != NULL)
{
char *str = cJSON_Print(one_item ); //将JSON结构体打印到字符串中需要自己释放
printf("%s: %s\n", one_item ->string, str);
free(str);
}
//解析数组相关,略
// cJSON *cJSON_GetArrayItem(cJSON *array,int item);
// cJSON_GetArraySize(cJSON *array);
//一层遍历解析,输出显示
cJSON *item = cJSON_GetObjectItem(root_json, "name");
cJSON_ArrayForEach(item, root_json)
{
printf("%s: %s\n", item->string, cJSON_Print(item));
}
free(item);
free(data);
cJSON_Delete(root_json);
printf("----------------parse json end--------------------------------\n");
}
只是通过简单的宏定义实现。
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
理解了这个数据结构就基本可以了解实现原理了。
/*
typedef struct cJSON {
struct cJSON *next,*prev;
struct cJSON *child;
int type;
char *valuestring;
int valueint;
double valuedouble;
char *string;
} cJSON;
1.cJOSN 结构体为一个双向列表,并可通过 child 指针访问下一层。
2.type 变量决定数据项类型(键的类型),
数据项可以是字符串可以是整形,也可以是浮点型。
如果是整形值的话可从 valueint,如果是浮点型的话可从 valuedouble 取出,以此类推。
3.string 可理解为节点的名称,综合此处的第2点可理解为child “键”的名称。
*/
首先提一下,内存操作可以替换为其他自定义的 malloc 和 free 函数
static void *(*cJSON_malloc)(size_t sz) = malloc;
static void (*cJSON_free)(void *ptr) = free;
所有对JSON中条目的操作实际都是在对一条双向链表各个节点(还有子节点)的操作,
static cJSON *cJSON_New_Item(void)
{
cJSON *node = (cJSON *)cJSON_malloc(sizeof(cJSON));
if (node) memset(node, 0, sizeof(cJSON));
return node;
}
void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
{
if (!item) return;
if (!(item->type & cJSON_StringIsConst) && item->string) cJSON_free(item->string);
item->string = (char *)string;
item->type |= cJSON_StringIsConst;
cJSON_AddItemToArray(object, item);
}
static cJSON *create_reference(cJSON *item)
{
cJSON *ref = cJSON_New_Item();
if (!ref) return 0;
memcpy(ref, item, sizeof(cJSON));
ref->string = 0;
ref->type |= cJSON_IsReference;
ref->next = ref->prev = 0;
return ref;
}
void cJSON_Delete(cJSON *c)
{
cJSON *next;
while (c)
{
next = c->next;
if (!(c->type & cJSON_IsReference) && c->child) cJSON_Delete(c->child);
if (!(c->type & cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
if (!(c->type & cJSON_StringIsConst) && c->string) cJSON_free(c->string);
cJSON_free(c);
c = next;
}
}
限于篇幅,还有删除子节点,复制节点,修改节点内容,替换节点内容,获取对应节点内容等等,都容易看明白。
接下来一大块就是解析字符串生成JSON数据的实现,还有相对的格式化输出。这部分有很多可以学习的东西。
确实对于JSON有了更深的了解,也对链表操作多一点熟悉感,
不过主要还是对一个开源项目有了最基本的印象,看到了各种为了方便他人使用的而进行的设置,易于理解的函数名,实用的宏设置等等。
小而美的实用项目,希望今后自己也可以写出一个像这样简洁实用的作品。