一文搞懂JSON

您所在的位置:网站首页 海关编码格式是什么样的 一文搞懂JSON

一文搞懂JSON

2024-07-17 18:52| 来源: 网络整理| 查看: 265

目录

什么是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的特点和优势(了解) 简洁和易读:JSON使用简洁的文本格式表示数据,易于阅读和编写。平台无关性:JSON是一种独立于编程语言和平台的数据格式,可被多种编程语言解析和生成。易于解析和生成:JSON的解析和生成相对简单,各种编程语言都提供了相应的JSON解析器和生成器。支持复杂数据结构:JSON支持嵌套、复杂的数据结构,可以表示对象、数组和各种组合类型的数据。与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的基本操作通常涉及以下几个方面:

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

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

📎cJSON.chttps://www.yuque.com/attachments/yuque/0/2023/txt/35243076/1687951166715-b8398dec-d697-4507-b49e-1e2ea5595ce9.txt📎cJSON.hhttps://www.yuque.com/attachments/yuque/0/2023/txt/35243076/1687951166713-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/qq_32172673/article/details/88305781

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 #include "cJSON.h" #include #include #include #include #include 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 #include "cJSON.h" #include #include #include #include #include #include "list.h" #include #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 #include #include #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; }



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3