目录

了解json

json数据类型

格式规范

json格式校验

JSON基本操作

JSON解析(反序列化)

 JSON构造(序列化)

练习


了解json

JSON: JavaScript 的对象表示法( JavaScript Object Notation)。是一种轻量级的数据交换格式
        JSON采用完全独立于语言的文本格式, 但是也使用了类似于C语言家族的习惯( 包括C、 C++、 C#、 Java、 JavaScript、 Perl、 Python等)。JSON 具有自我描述性, 语法简洁, 易于理解。这些特性使JSON成为理想的数据交换语言。 易于人阅读和编写, 同时也易于机器解析和生成(一般用于提升网络传输速率)。
        JSON 解析器和 JSON 库支持许多不同的编程语言。 JSON 文本格式在语法上与创建 JavaScript 对象的代码相同。 由于这种相似性, 无需解析器, JavaScript 程序能够使用内建的 eval() 函数, 用 JSON 数据来生成原生的 JavaScript 对象,而在C语言中我们一般使用cJSON解析器来进行json字符串的解析。

json数据类型

  • number:和JavaScript的number完全一致;相当于C中的int类型
  • boolean:就是JavaScript的true或false;相当于c++中的bool类型
  • string:就是JavaScript的string;相当于c++的string类型
  • null:就是JavaScript的null;相当于C的NULL类型
  • array:就是JavaScript的Array表示方式——[];相当于C的数组
  • object:就是JavaScript的{ ... }表示方式。相当于C++的类或者C的结构体

注:
1.json的数据类型在源码实现中和具体的编程语言有关,比如boolean在C中并没有相应的类型,C相关的实现库可能会用0和1表示。
2.number的数据虽然是相当于C中的int类型,但是也可以存放浮点型数据等内容。

格式规范

  • json以大括号起始和结尾
  • 内容都是以键值对的形式存在
  • 所有的键都是字符串
  • 值的类型不一定,属于JavaScript 的基本数据类型
  • 每个键值对以,分割
  • 最后一个键值对不加逗号

json格式校验

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

JSON基本操作

Json序列化:可以理解为利用程序生成Json字符串的过程。

Json反序列化:可以理解为利用程序将已有的Json字符串解析出我们需要的值的过程。

JSON解析(反序列化)

        cJSON解析器对象的实现采用了树形结构,每个对象是树的一个节点,每个节点由cJSON这个结构体组成,对象中的元素也由cJSON这个结构体组成。同一层的对象和元素是双向链表结构,由next和prev指针链接。不同层的对象或元素由child指针链接起来。type表示对象或元素类型,string表示对象或节点的名称。元素的值存储在valuestring, valueint和valuedouble中,cJSON.h中有详细的注释。解析json我们一般借助以下函数:

cJSON *cJSON_Parse(const char *value);
//功能:将一个JSON数据包,按照cJSON结构体的结构序列化整个数据包,并在堆中开辟一块内存存储cJSON结构体
//返回值:成功返回一个指向内存块中的cJSON的指针,失败返回NULL

cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
//功能:获取JSON字符串字段值
//返回值:成功返回一个指向cJSON类型的结构体指针,失败返回NULL

int cJSON_GetArraySize(cJSON *array);
//功能:获取数组成员对象个数
//返回值:数组成员对象个数

int cJSON_HasObjectItem(cJSON *object,const char *string)
//功能:判断cjson对象中是否有某键
//返回值:如果有返回1 否则返回0 

cJSON *cJSON_GetArrayItem(cJSON *array,int item);
//根据下标获取cjson对象数组中的对象
 
void  cJSON_Delete(cJSON *c);
/*作用:释放位于堆中cJSON结构体内存
返回值:无*/
 
char *cJSON_GetErrorPtr(void);
//获取错误字符串
 
char  *cJSON_Print(cJSON *item);
//从cjson对象中获取有格式的json对象,打印到终端
 
char  *cJSON_PrintUnformatted(cJSON *item);
//从cjson对象中获取无格式的json对象,打印到终端

 JSON构造(序列化)

CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);    
//创建对象---常用
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);    
//创建数组---常用
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
//创建整型数组
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
//创建双浮点型数组
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
//在对象中添加null
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
//在对象中添加true
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
//在对象中添加false
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
//在对象中添加数字
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
//在对象中添加字符串
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);    
//在对象中添加项目
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
//在数组中添加项目
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
//JSON数据结构转换为JSON字符串---有格式
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);    
//JSON数据结构转换为JSON字符串---无格式
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); 
//清除结构体

练习

1.对以下json字符串进行序列化。

2.使用cJSON库对下面的将下面内容存为json文件,读取后解析,进行反序列化操作。

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

序列化例程:


	
    // 1.构造根节点root
    cJSON * root =  cJSON_CreateObject();

    // 2.给 root 添加 ver 的子节点,子节点类型是 string
    cJSON_AddItemToObject(root, "ver", cJSON_CreateString("1.0"));

    // 3.给 root 添加 login 的子节点,子节点类型是 object
	cJSON * object1 =  cJSON_CreateObject();
    cJSON_AddItemToObject(root, "login", object1);

    // 4.给 login 节点添加 user 和 key 节点
    cJSON_AddItemToObject(object1, "user", cJSON_CreateString("zhangsan"));
    cJSON_AddItemToObject(object1, "key", cJSON_CreateString("123456"));


    // 5.创建数组节点
    cJSON *array  = cJSON_CreateArray();
    
	// 6.将数组data加入根节点中
    cJSON_AddItemToObject(root, "data", array);

    // 7.往data数组节点遍历增加项
    list_for_each(p, &head)
    {
        tmp = list_entry(p, struct data, list);

        // 7.1 创建数组data的子节点(此时还没放进数组data中)
        cJSON *tmp_son = cJSON_CreateObject();
        
        // 7.2 往数组data字节点中增加key和type
        cJSON_AddItemToObject(tmp_son, "key", cJSON_CreateNumber(tmp->key));
        cJSON_AddItemToObject(tmp_son, "type", cJSON_CreateNumber(tmp->type));

        // 7.3 往数组data字节点中增加val
        // 7.3.1 处理val
        char buf_tmp[32] = "";
        switch (tmp->type)
        {
        case 1:
            sprintf(buf_tmp, "%d", tmp->val.b);
            break;
        case 2:
            sprintf(buf_tmp, "%d", tmp->val.i);
            break;
        case 3:
            sprintf(buf_tmp, "%0.2f", tmp->val.f);
            break;
        }
        // 7.3.2 将处理好的val即string基本类型添加到数组data的字节点中
        cJSON_AddItemToObject(tmp_son, "val", cJSON_CreateString(buf_tmp));

        // 7.3.3 将字节点tmp_son增加到数组data中
        cJSON_AddItemToArray(array, tmp_son);
    }

    // 8.打印cJSON验证
    printf("\n打印Json字符串验证:\n");
    printf("%s\n", cJSON_Print(root));

 反序列化例程:

#include <stdio.h>
#include <stdlib.h>
#include "list.h"
#include "cJSON.h"
#include "cJSON.c"

typedef int BOOL;

union val_t {
    BOOL b;
    int i;
    float f;
};

struct data
{
    int key;
    int type;
    union val_t val;
    struct list_head list;
};

int main(int argc, char const *argv[])
{
    /* ----------读取文件---------- */
    FILE *fd = NULL;
    fd = fopen("./test.json", "r");
    if (NULL == fd)
    {
        perror("fopen failed.");
        return -1;
    }

    char buf[500] = "";
    
    if (fread(buf, 500, 1, fd) < 0)
    {
        perror("fread failed.");
        return -1;
    }

    /* -----------JSON的反序列化----------- */
    // 1.取出对象object
    cJSON *object = cJSON_Parse(buf);
    if (NULL == object)
    {
        printf("Error before: [%s]\n", cJSON_GetErrorPtr());
        return -1;
    }

    // 2.取出对象object下的节点ver和login
    cJSON *item = cJSON_GetObjectItem(object, "ver");
    printf("ver: %s\n", item->valuestring); 
    cJSON *item_login = cJSON_GetObjectItem(object, "login");
    
    // 3.从login节点中取出user和key两子节点
    item = cJSON_GetObjectItem(item_login, "user");
    printf("user: %s\n", item->valuestring);
    item = cJSON_GetObjectItem(item_login, "key");
    printf("key: %s\n", item->valuestring);

    // 4.取出对象object下的数组节点data
    item = cJSON_GetObjectItem(object, "data");

    // 5.链表初始化
    struct list_head head;
    INIT_LIST_HEAD(&head);

    // 6.遍历取出数组中每个项并加到链表里面去
    for (int i = 0; i < cJSON_GetArraySize(item); i++)
    {
        // 6.1 根据下标从数组节点中取出第i个节点
        cJSON *value = cJSON_GetArrayItem(item, i);

        // 6.2 从第i个节点中取子节点key和type
        cJSON *value_key = cJSON_GetObjectItem(value, "key");
        cJSON *value_type = cJSON_GetObjectItem(value, "type");

        // 6.3 malloc出结构体指针node
        struct data *node = (struct data *)malloc(sizeof(struct data));

        // 6.4 通过指针对结构体赋值
        node->key = value_key->valueint;
        node->type = value_type->valueint;
        
        cJSON *value_val = cJSON_GetObjectItem(value, "val");
        switch (value_type->valueint)
        {
        case 1:
            node->val.b = atoi(value_val->valuestring);
            break;
        case 2:
            node->val.i = atoi(value_val->valuestring);
            break;
        case 3:
            node->val.f = atof(value_val->valuestring);
            break;
        }
        // 7.加到链表里由链表存储
        list_add(&node->list, &head);
    }

    /* ~~~~~~~~~~~~~~~~~~~~~~~遍历输出链表,验证已经由链表存储~~~~~~~~~~~~~~~~~~~~~~~ */
    printf("\n遍历输出链表, 验证已经由链表存储:\n");
    struct list_head *p;
    struct data *tmp;
    list_for_each(p, &head)
    {
        tmp = list_entry(p, struct data, list);
        printf("key = %d, type = %d, ", tmp->key, tmp->type);
        switch (tmp->type)
        {
        case 1:
            printf("val = %d\n", tmp->val.b);
            break;
        case 2:
            printf("val = %d\n", tmp->val.i);
            break;
        case 3:
            printf("val = %0.2f\n", tmp->val.f);
            break;
        }
    }

    return 0;
}

注意事项:

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

GitHub 加速计划 / cj / cJSON
10.45 K
3.16 K
下载
Ultralightweight JSON parser in ANSI C
最近提交(Master分支:3 个月前 )
424ce4ce This reverts commit 5b502cdbfb21fbe5f6cf9ffbd2b96e4281a741e6. Related to #860 4 个月前
32497300 - 6 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐