2025年一文搞懂JSON

一文搞懂JSON目录 什么是 JSON JSON 的基本数据类型 JSON 的特点和优势 了解 JSON 格式规范 重点 JSON 的基本操作 关键接口的梳理 序列化 反序列化 答案和解析 序列化答案 反序列化答案 第一种思路 第二种思路 什么是 JSON

大家好,我是讯享网,很高兴认识大家。

目录

什么是JSON?

JSON的基本数据类型

JSON的特点和优势(了解)

JSON格式规范(重点)

JSON的基本操作

关键接口的梳理

序列化

反序列化

答案和解析

序列化答案

反序列化答案

第一种思路

第二种思路


什么是JSON?

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于将数据结构化地传输和存储。它由键值对组成,采用类似于JavaScript对象的格式来表示数据。JSON易于阅读和编写,并且易于解析和生成,成为广泛应用于Web应用程序和数据交换的标准格式之一。

JSON的基本数据类型

类型

解释

案例

字符

(String)

由双引号包围的Unicode字符序列

"Hello, World!"

数字(Number)

包括整数和浮点数

42,3.14

布尔值(Boolean)

表示真或假,C相关的实现库可能会用0和1表示

值为true或false


讯享网

空值

(Null)

表示空值

值为null

对象

(Object)

由一组无序的键值对组成,键是字符串,值可以是任意的JSON数据类型。键值对之间使用逗号分隔,整个对象使用花括号{}包围

{"name": "John",

"age": 30,

"city": "New York"}

数组

(Array)

由一组有序的值组成,值可以是任意的JSON数据类型。值之间使用逗号分隔,整个数组使用方括号[]包围

[1, 2, 3, 4, 5]

JSON的特点和优势(了解)

  1. 简洁和易读:JSON使用简洁的文本格式表示数据,易于阅读和编写。
  2. 平台无关性:JSON是一种独立于编程语言和平台的数据格式,可被多种编程语言解析和生成。
  3. 易于解析和生成:JSON的解析和生成相对简单,各种编程语言都提供了相应的JSON解析器和生成器。
  4. 支持复杂数据结构:JSON支持嵌套、复杂的数据结构,可以表示对象、数组和各种组合类型的数据。
  5. 与Web应用程序兼容性良好:JSON广泛用于Web应用程序中,可以轻松地与JavaScript进行交互。

JSON格式规范(重点)

1. 数据使用键值对表示,键和值之间使用冒号(:)分隔。 例如:{"name": "John", "age": 30} 2. 键使用双引号(")包围,值可以是字符串、数字、布尔值、对象、数组或null。 例如:{"name": "John", "age": 30, "isStudent": true, "address": null} 3. 键值对之间使用逗号(,)分隔,最后一个键值对后不应有逗号。 例如:{"name": "John", "age": 30} 4. 字符串值使用双引号(")包围,可以包含任意Unicode字符序列,特殊字符可以使用转义字符表示。 例如:"Hello, World!", "I "love" JSON" 5. 数字可以是整数或浮点数,不使用引号包围。 例如:42, 3.14 6. 布尔值只有两个取值:true和false,不使用引号包围。 例如:true, false 7. 数组使用方括号([])包围,值之间使用逗号分隔。 例如:[1, 2, 3, 4, 5] 8. 对象使用花括号({})包围,键值对之间使用逗号分隔。 例如:{"name": "John", "age": 30} 9. JSON是严格区分大小写的,键和字符串值都应该使用双引号包围。 10. JSON可以嵌套,允许在对象中包含对象或数组,或在数组中包含对象或其他数组。 11. JSON不支持注释,不允许在JSON数据中添加注释。

讯享网

下面是一个简单的JSON

讯享网{ "name": "southernbrid", "age": 14, "gender": true, "height": 1.65, "grade": null, "skills": [ "JavaScript", "Java", "Python", "Lisp" ] }

分享个JSON格式校验网站

在线JSON校验格式化工具(Be JSON)

JSON的基本操作

JSON的基本操作通常涉及以下几个方面:

  1. 创建JSON对象: 可以使用编程语言提供的函数、类或库来创建JSON对象。通常,这些函数或方法接受键值对作为参数,用于指定JSON对象的属性和对应的值。
  2. 解析JSON字符串: 将JSON字符串解析为相应的数据结构,如对象、数组或基本数据类型。编程语言提供相应的解析函数或方法,可以将JSON字符串转换为可操作的数据对象。
  3. 生成JSON字符串: 将数据对象转换为JSON字符串的表示形式,以便于传输、存储或与其他系统进行交互。编程语言提供相应的函数或方法,可以将数据对象转换为符合JSON格式规范的字符串。
  4. 访问和修改JSON对象的属性: 通过键访问JSON对象的属性,并可以对其进行修改。可以使用编程语言提供的API来访问、读取和修改JSON对象的属性值。
  5. 遍历JSON数组: 遍历JSON数组中的元素,逐个访问和处理数组中的数据项。使用循环结构来遍历数组,根据索引或迭代器获取数组中的每个元素。
  6. 嵌套JSON操作: 处理嵌套的JSON结构,包括访问、修改和操作嵌套的对象或数组。可以使用递归、循环等方法来处理嵌套的JSON结构。
  7. 序列化和反序列化(重点): 将JSON对象序列化为字符串,或将JSON字符串反序列化为对象。序列化是将数据对象转换为JSON字符串,反序列化是将JSON字符串转换为数据对象。(本文主要介绍C语言的JSON库来进行序列化和反序列化)

下面是一个C库,用来完成本文教学

📎cJSON.chttps://www.yuque.com/attachments/yuque/0/2023/txt//15-b8398dec-d697-4507-b49e-1e2ea5595ce9.txt📎cJSON.hhttps://www.yuque.com/attachments/yuque/0/2023/txt//13-f66a28ef-8aaa-4fb0-8f7c-7fa49d94b608.txt

下面两篇文章也能帮助我们完成JSON序列化和JSON反序列化的操作

cJSON 使用详解_无痕眼泪的博客-CSDN博客由于c语言中,没有直接的字典,字符串数组等数据结构,所以要借助结构体定义,处理json。如果有对应的数据结构就方便一些, 如python中用json.loads(json)就把json字符串转变为内建的数据结构处理起来比较方便。一个重要概念:在cjson中,json对象可以是json,可以是字符串,可以是数字。。。cjson数据结构定义:#d..._cjsonhttps://blog.csdn.net/_/article/details/

https://www.cnblogs.com/liunianshiwei/p/6087596.htmlhttps://www.cnblogs.com/liunianshiwei/p/6087596.html

编译注意事项

编译cJSON库时候,gcc需要增加  -lm 选项,动态链接math库。

关键接口的梳理

/* 类型定义 */ #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 /* CJSON核心结构体 */ typedef struct cJSON { struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ int type; /* 节点的类型,取值是上面的6种 */ char *valuestring; /* 如果类型是cJSON_String,那么值会被存到这里 */ int valueint; /* 如果类型是cJSON_Number,且是整型,那么值会被存到这里 */ double valuedouble; /* 如果类型是cJSON_Number,且是浮点型,那么值会被存到这里 */ char *string; /* 键*/ } cJSON; /通用接口/ //把传入的字符串转成cJSON的结构(反序列化) cJSON *cJSON_Parse(const char *value); //把cJSON结构转成字符串(序列化),调用后需要配合free接口释放malloc的内存 char *cJSON_Print(cJSON *item); //无格式化序列化,节省内存,调用后需要配合free接口释放malloc的内存 char *cJSON_PrintUnformatted(cJSON *item); //释放节点的内存,防止内存泄露 void cJSON_Delete(cJSON *c); /反序列化相关接口/ //获取数组的大小 int cJSON_GetArraySize(cJSON *array); //从array数组中获取第item个子节点 cJSON *cJSON_GetArrayItem(cJSON *array,int item); //获取object大节点名字叫string的子节点 cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); //判断object大节点中是否有名字叫string的小节点 int cJSON_HasObjectItem(cJSON *object,const char *string); /序列化相关接口/ //创建一个普通节点 cJSON *cJSON_CreateObject(void); //创建一个数组节点 cJSON *cJSON_CreateArray(void); //把item节点增加到array的数组节点中 void cJSON_AddItemToArray(cJSON *array, cJSON *item); //把item节点增加到object中作为子节点,item节点的键名为string void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); //创建各种类型的cJSON节点 cJSON *cJSON_CreateNull(void); cJSON *cJSON_CreateTrue(void); cJSON *cJSON_CreateFalse(void); cJSON *cJSON_CreateBool(int b); cJSON *cJSON_CreateNumber(double num); cJSON *cJSON_CreateString(const char *string); cJSON *cJSON_CreateArray(void); cJSON *cJSON_CreateObject(void);

序列化

使用cJSON库序列化出下面的JSON内容

讯享网{ "name": "小明", "age": 14, "gender": true, "height": 1.65, "grade": null, "skills": [ "JavaScript", "Java", "Python", "Lisp" ] }

反序列化

使用cJSON库对下面的JSON文件进行反序列化操作。ver和login的子节点直接打印即可,data的数据节点解析后形成链表存储(将下面内容存为文件,读取后解析即可)。

{ "ver": "1.0", "login": { "user": "zhangsan", "pwd": 1234 }, "data": [{ "key": 1, "type": 2, "val": "10" }, { "key": 2, "type": 1, "val": "0" }, { "key": 3, "type": 3, "val": "22.5" } ] }

注意:上面的所有val值都是string类型,解析出来存到节点前,需要根据type的类型来进行转换,按照相应的类型存储到共用体中。

提示:对于数据解析后,形成新的节点存放链表,最好的方式是为每个节点分配单独的内存。例:

讯享网struct data { int key; int type; union val_t val; struct list_head list; }; struct data *node = (struct data *)malloc(sizeof(struct data)); node->xxx = xxx; 插入链表即可

答案和解析

序列化答案

#include <stdio.h> #include "cJSON.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char const *argv[]) { // 序列化 cJSON *root = cJSON_CreateObject(); // 创建根节点 cJSON *age = cJSON_CreateNumber(14); // 创建一个数值类型的节点 cJSON_AddItemToObject(root, "age", age); // 将age节点添加到root对象中,键名为"age" // 增加数组节点 cJSON *arr = cJSON_CreateArray(); // 创建一个数组类型的节点 cJSON_AddItemToArray(arr, cJSON_CreateString("JavaScript")); // 向数组中添加一个字符串节点 cJSON_AddItemToArray(arr, cJSON_CreateString("Java")); // 向数组中添加一个字符串节点 cJSON_AddItemToArray(arr, cJSON_CreateString("Python")); // 向数组中添加一个字符串节点 cJSON_AddItemToObject(root, "skills", arr); // 将数组节点添加到root对象中,键名为"skills" // 输出内容 char *p = cJSON_PrintUnformatted(root); // 将JSON对象转换为字符串表示形式 printf("root = %s\n", p); free(p); cJSON_Delete(root); // 释放JSON对象占用的内存 return 0; }

反序列化答案

第一种思路

讯享网#include <stdio.h> #include "cJSON.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include "list.h" #include <string.h> #define MAX 1024 union val_t { int i_val; float f_val; char *s_val[MAX]; }; struct data { int key; int type; union val_t val; struct list_head list; }; int main(int argc, char const *argv[]) { // 构造链表 struct list_head head; INIT_LIST_HEAD(&head); struct data mydate[10]; // 创建结构体数组 // 读取文件内容到缓冲区 int fd = open("data.json", O_RDONLY); if (fd < 0) { perror("open err"); return -1; } char buf[MAX] = {0}; size_t len = read(fd, buf, MAX); if (len < 0) { perror("open err"); return -1; } // 反序列化动作 cJSON *root = cJSON_Parse(buf); // 把传入的字符串转成cJSON的结构(反序列化) if (root == NULL) { printf("cJSON_Parse err."); return -1; } // 开始摘取数据 cJSON *item; cJSON *keyitem; cJSON *typeitem; cJSON *valitem; item = cJSON_GetObjectItem(root, "ver"); // 获取root的ver子节点 printf("%s : %s\n", item->string, item->valuestring); cJSON *login = cJSON_GetObjectItem(root, "login"); cJSON *user = cJSON_GetObjectItem(login, "user"); cJSON *pwd = cJSON_GetObjectItem(login, "pwd"); printf("%s :\n", login->string); printf("%s : %s\n", user->string, user->valuestring); printf("%s : %d\n", pwd->string, pwd->valueint); // 解析数组节点 cJSON *data; data = cJSON_GetObjectItem(root, "data"); printf("%s :\n", data->string); int count = cJSON_GetArraySize(data); // 获取数组大小用来进行遍历 for (size_t i = 0; i < count; i++) { cJSON *tmp = cJSON_GetArrayItem(data, i); // 获取数组节点中的第 i 个元素 keyitem = cJSON_GetObjectItem(tmp, "key"); typeitem = cJSON_GetObjectItem(tmp, "type"); valitem = cJSON_GetObjectItem(tmp, "val"); printf("key : %d\n", keyitem->valueint); printf("type : %d\n", typeitem->valueint); printf("val : %s\n", valitem->valuestring); mydate[i].key = keyitem->valueint; // 设置key值 mydate[i].type = typeitem->valueint; // 设置类型 strcpy(mydate[i].val.s_val, valitem->valuestring); // 将值拷贝到val数组 list_add(&mydate[i].list, &head); // 将结构体添加到链表中 } // 遍历链表并输出结果 struct list_head *pos; struct data *newtmp; list_for_each(pos, &head) { newtmp = list_entry(pos, struct data, list); printf("key = %d, type = %d, val = %s\n", newtmp->key, newtmp->type, newtmp->val.s_val); } list_del(pos); cJSON_Delete(root); // 释放JSON对象占用的内存 return 0; }

第二种思路

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "cJSON.h" #include "list.h" //定义共用体 typedef int BOOL; union val_t { BOOL b_val; //bool类型存储空间 int i_val; //整形值存储空间 float f_val; //浮点值存储空间 }; //定义结构体 struct student { int key; int type; union val_t val; struct list_head list;//指针域 }; int main(int argc, char const *argv[]) { struct list_head head; INIT_LIST_HEAD(&head); char * jsonStr = "{\"ver\":\"1.0\",\"login\":{\"user\":\"zhangsan\",\"pwd\":1234},\"data\":[{\"key\":1,\"type\":2,\"val\":\"10\"},{\"key\":2,\"type\":1,\"val\":\"0\"},{\"key\":3,\"type\":3,\"val\":\"22.5\"}]}"; cJSON * root = NULL; cJSON * item = NULL;//cjson对象 //把传入的字符串转成cJSON的结构(反序列化) root = cJSON_Parse(jsonStr);//取出root对象(根节点) if (!root) { printf("Error before: [%s]\n",cJSON_GetErrorPtr()); return -1; } else { printf("转换成功!\n"); //获取版本号--ver item = cJSON_GetObjectItem(root, "ver"); printf("版本号%s:%s\n",item->string,item->valuestring); //获取帐号密码 item = cJSON_GetObjectItem(root, "login"); cJSON * myuser = cJSON_GetObjectItem(item, "user"); printf("帐号%s:%s --- ",myuser->string,myuser->valuestring); cJSON * mypwd = cJSON_GetObjectItem(item, "pwd"); printf("密码%s:%d\n",mypwd->string,mypwd->valueint); cJSON * myData = cJSON_GetObjectItem(root, "data");//root节点下的data节点 item = myData->child;//item是数组或对象的子节点,即data节点下的每一个小的花括号节点,或者可以用cJSON *cJSON_GetArrayItem(cJSON *array,int item)获取数组中的子节点(花括号节点) printf("data数据列表:\n"); while(item != NULL) { //取出data里的每一个花括号里的每一个小元素的值:即(key,type,val)的值 cJSON * mykey = cJSON_GetObjectItem(item, "key"); printf("键:%d ",mykey->valueint); cJSON * mytype = cJSON_GetObjectItem(item, "type"); printf("类型:%d ",mytype->valueint); cJSON * myval = cJSON_GetObjectItem(item, "val");//注意val的数据类型 printf("值:%s\n",myval->valuestring); if(mykey != NULL && mytype != NULL && myval != NULL) { // printf("取值成功!以链表方式存储\n"); //将解析的数据放入链表中 struct student * stu = (struct student *)malloc(sizeof(struct student));//记得释放内存 stu->key = mykey->valueint; stu->type = mytype->valueint; if(mytype->valueint == 1) { int valnum = atoi(myval->valuestring); stu->val.i_val = valnum; } else if(mytype->valueint == 2) { int valnum = atoi(myval->valuestring); stu->val.i_val = valnum; } else if(mytype->valueint == 3) { int valnum = atof(myval->valuestring); stu->val.f_val = valnum; } // stu->val.i_val = myval->valuestring; //头插法插入 list_add(&stu->list,&head); } item = item->next; } //遍历打印 struct list_head *pos;//是指向一个结构体的一个指针域的指针 struct student *tmp;//是指向整个结构体的指针 // printf("init list\n"); printf("链表数据:\n"); list_for_each(pos, &head) { // sleep(3); tmp = list_entry(pos, struct student, list);//可以从指针域偏移到整个结构体,拿到整个结构体的首地址,因此能够拿到属于该指针域的数据域 if(tmp->type == 1) { printf("key=%d, type=%d, val=%d\n", tmp->key, tmp->type, tmp->val.i_val); } else if(tmp->type == 2) { printf("key=%d, type=%d, val=%d\n", tmp->key, tmp->type, tmp->val.b_val); } else if(tmp->type == 3) { printf("key=%d, type=%d, val=%.2f\n", tmp->key, tmp->type, tmp->val.f_val); } } printf("\n"); } cJSON_Delete(root); return 0; }

小讯
上一篇 2025-02-08 20:36
下一篇 2025-03-22 11:52

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/14771.html