【嵌入式开源库】cJSON的使用,高效精简的json解析库

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【嵌入式开源库】cJSON的使用,高效精简的json解析库

简介

JSON 全称 JavaScript Object Notation,即 JS对象简谱,是一种轻量级的数据格式。

它采用完全独立于编程语言的文本格式来存储和表示数据,语法简洁、层次结构清晰,易于人阅读和编写,同时也易于机器解析和生成,有效的提升了网络传输效率。

cJSON是一个使用C语言编写的JSON数据解析器并采用ANSI C(C89)编写以支持尽可能多的平台和编译器,该项目同时也具有超轻便,可移植,单文件的特点,使用MIT开源协议。

json格式

{
    "name": "Awesome 4K",
    "resolutions": [
        {
            "width": 1280,
            "height": 720
        },
        {
            "width": 1920,
            "height": 1080
        },
        {
            "width": 3840,
            "height": 2160
        }
    ]
}

本章使用环境:

虚拟机ubuntu1804

下载

cJSON项目托管在Github,下载地址:https://github.com/DaveGamble/cJSON

也可以通过git工具进行项目克隆(保证自己电脑配好git环境)

git clone https://github.com/DaveGamble/cJSON.git

使用介绍

因为整个库只有一个C文件和一个头文件,所以我们只需要复制cJSON.h和cJSON.c到项目中就可以使用了。

工程创建

mkdir study_json
cd study_json/
touch main.c
cp ../cJSON/cJSON.c ./
cp ../cJSON/cJSON.h ./

main.c中内容

#include <stdio.h>
#include "cJSON.h"
int main(int argc, char *argv[])
{
  printf("hello json!\n");
  return 0;
}

编译指令

gcc main.c cJSON.c -o app
// 执行
./app

然后我们来简单看一下cjson的源代码,

cJSON结构体

在源代码中我们可以找到一个结构体是用来存放我们将要打包或者解析的数据,结构体如下

/* The cJSON structure: */
typedef struct cJSON
{
    struct cJSON *next;
    struct cJSON *prev;
    struct cJSON *child;
    int type;
    char *valuestring;
    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    int valueint;
    double valuedouble;
    char *string;
} cJSON;

从结构体看来可以看出来cJSON的数据存储是采用链表的方式存储的(next指向下一个键值对,prev指向上一个键值对,child指针是用来存储子object对象),这就涉及到一个释放的问题,刚开始使用很容易忽略这个问题最后导致程序跑飞问题,通过结构体的数据变量可以看到cjson支持的数据类型有bool型、字符串类型、int类型、双进精度浮点数(最后的char *string表示的是对象key的名称并非值value对象);然后我们来看一下.h文件给我们提供了那些可以操作的接口;

节点创建

// 创建指定类型的json对象
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);

添加节点到对象

// 将创建好的json数据添加到object中
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
// 创建数据同时添加到object中去
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
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*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);

内存释放

// 将链表数据输出为char *字符串,也就是打印格式
cJSON_Print(const cJSON *item);
// 释放内存
cJSON_free(void *object);
cJSON_Delete(cJSON *item);

这三个函数都非常重要,第一个是我们把创建好的cjson数据给输出成字符串然后供我们使用,当我们使用完成过后一定要使用cJSON_free函数进行释放,因为print这个函数也是通过申请内存的方式来制造这个字符串的,delete这个函数是用来释放我们的object的,和释放链表的方式一样,我们只需要释放根节点就可以了。

同时cJSON支持自定义malloc函数和free函数,如果我们是在单片机等平台上使用了外部sram芯片,就可以使用下面这个接口将外部sram的malloc接口和free接口初始化上去

typedef struct cJSON_Hooks
{
      /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
      void *(CJSON_CDECL *malloc_fn)(size_t sz);
      void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;
(void) cJSON_InitHooks(cJSON_Hooks* hooks);

节点类型判断

// 解析json对象是属于上面类型的api函数
cJSON_IsInvalid(const cJSON * const item);
cJSON_IsFalse(const cJSON * const item);
cJSON_IsTrue(const cJSON * const item);
cJSON_IsBool(const cJSON * const item);
cJSON_IsNull(const cJSON * const item);
cJSON_IsNumber(const cJSON * const item);
cJSON_IsString(const cJSON * const item);
cJSON_IsArray(const cJSON * const item);
cJSON_IsObject(const cJSON * const item);
cJSON_IsRaw(const cJSON * const item);
//返回值
/* cJSON Types: */
#define cJSON_Invalid (0)
#define cJSON_False  (1 << 0)
#define cJSON_True   (1 << 1)
#define cJSON_NULL   (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array  (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_Raw    (1 << 7) /* raw json */

数据解析

// 解析json数据需要用到的函数
(cJSON *) cJSON_Parse(const char *value); // 将json数据解析到cjson结构体中
(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);// 根据string键值来获取内容
// 如果对象是数组可以用以下函数解析
(int) cJSON_GetArraySize(const cJSON *array);
(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
// 获取对象中的数据
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
为了防止堆栈溢出做出的保护措施,在一些小型嵌入式系统中可以给改此值。
#define CJSON_NESTING_LIMIT 1000

节点删除

// 删除一个cJSON数据
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);

数据打包json格式

目标:创建下列格式json数据并通过printf打印

{
    "name": "stylle",
    "resolutions": [
        {
            "width": 1280,
            "height": 720
        },
        {
            "width": 1920,
            "height": 1080
        }
    ]
}

main.c

#include <stdio.h>
#include "cJSON.h"
int main(int argc, char *argv[])
{
  printf("hello json!\n");
  cJSON *name = NULL;
  cJSON *resolutions = NULL;
  cJSON *resolution = NULL;
    cJSON *width = NULL;
    cJSON *height = NULL;
  //   根节点的创建
  cJSON *root = cJSON_CreateObject();
    if (root == NULL)
    {
    // 内存申请失败,调査到结尾释放根节点
        goto end;
    }
  // name节点
  name = cJSON_CreateString("stylle");
  if(name == NULL)
  {
    goto end;
  }
  cJSON_AddItemToObject(root, "name",name); // 添加到根节点,键值为name
  // 节点数组
  resolutions = cJSON_CreateArray();
  if(resolutions == NULL)
  {
    goto end;
  }
  cJSON_AddItemToObject(root, "resolutions", resolutions);
  // 数组内容[0]
  resolution = cJSON_CreateObject();
  if (resolution == NULL)
  {
    goto end;
  }
  cJSON_AddItemToArray(resolutions, resolution);
  width = cJSON_CreateNumber(1280);
  if (width == NULL)
  {
    goto end;
  }
  cJSON_AddItemToObject(resolution, "width", width);
  height = cJSON_CreateNumber(720);
  if (height == NULL)
  {
    goto end;
  }
  cJSON_AddItemToObject(resolution, "height", height);
  // 数组内容[1]
  resolution = cJSON_CreateObject();
  if (resolution == NULL)
  {
    goto end;
  }
  cJSON_AddItemToArray(resolutions, resolution);
  width = cJSON_CreateNumber(1920);
  if (width == NULL)
  {
    goto end;
  }
  cJSON_AddItemToObject(resolution, "width", width);
  height = cJSON_CreateNumber(1080);
  if (height == NULL)
  {
    goto end;
  }
  cJSON_AddItemToObject(resolution, "height", height);
  // 打印数据
  char *print_buffer = cJSON_Print(root);
  if(print_buffer == NULL)
  {
    goto end;
  }
  printf("%s\n", print_buffer);
  cJSON_free(print_buffer);
end:
  printf("cJSON ERROR : %s\n", cJSON_GetErrorPtr());
  cJSON_Delete(root);
  return 0;
}

json数据解析

目标:解析下列格式json数据并通过printf打印所有的键值对;

{
        "students":     [{
                        "name": "liulu",
                        "age":  22,
                        "learning":     true
                }, {
                        "name": "wangmazi",
                        "age":  25,
                        "learning":     false
                }]
}

main.c

int main(int argc, char *argv[])
{
  const char *str = "{\"students\":[{\"name\" : \"liulu\", \"age\" : 22, \"learning\" : true},{\"name\" : \"wangmazi\", \"age\" : 25, \"learning\" : false}]}";
    cJSON *root = NULL;
    cJSON *students = NULL, *students1 = NULL, *students2 = NULL;
    cJSON *name1 = NULL, *age1 = NULL, *learning1 = NULL;
    cJSON *name2 = NULL, *age2 = NULL, *learning2 = NULL;
    root = cJSON_Parse(str);
    if (root == NULL){   
        goto end;
    } 
    students = cJSON_GetObjectItem(root, "students");
  if(students == NULL)
  {
    goto end;
  }
    students1 = cJSON_GetArrayItem(students, 0);
  if(students1 == NULL)
  {
    goto end;
  }
    students2 = cJSON_GetArrayItem(students, 1);
  if(students2 == NULL)
  {
    goto end;
  }
  // 数组1内容解析
    name1 = cJSON_GetObjectItem(students1, "name");
  if(name1 == NULL)
  {
    goto end;
  }
    age1 = cJSON_GetObjectItem(students1, "age");
  if(age1 == NULL)
  {
    goto end;
  }
    learning1 = cJSON_GetObjectItem(students1, "learning");
  if(learning1 == NULL)
  {
    goto end;
  }
  // 数组2内容解析
    name2 = cJSON_GetObjectItem(students2, "name");
  if(name2 == NULL)
  {
    goto end;
  }
    age2 = cJSON_GetObjectItem(students2, "age");
  if(age2 == NULL)
  {
    goto end;
  }
    learning2 = cJSON_GetObjectItem(students2, "learning");
  if(learning2 == NULL)
  {
    goto end;
  }
  // 数据打印
    printf("name[0]:%s\n", cJSON_GetStringValue(name1));
    printf("age[0]: %0.f\n", cJSON_GetNumberValue(age1));
    printf("learning [0]: %d\n\n", cJSON_IsTrue(learning1));
    printf("name[1]: %s\n", cJSON_GetStringValue(name2));
    printf("age [1]: %0.f\n", cJSON_GetNumberValue(age2));
    printf("learning [1]: %d\n", cJSON_IsTrue(learning2));
end:
  printf("\ncJSON ERROR : %s\n", cJSON_GetErrorPtr());
    cJSON_Delete(root);
  return 0;
}


相关文章
|
1月前
|
SQL 存储 JSON
SQL,解析 json
SQL,解析 json
67 8
|
1月前
|
JSON JavaScript Java
在Java中处理JSON数据:Jackson与Gson库比较
本文介绍了JSON数据交换格式及其在Java中的应用,重点探讨了两个强大的JSON处理库——Jackson和Gson。文章详细讲解了Jackson库的核心功能,包括数据绑定、流式API和树模型,并通过示例演示了如何使用Jackson进行JSON解析和生成。最后,作者分享了一些实用的代码片段和使用技巧,帮助读者更好地理解和应用这些工具。
在Java中处理JSON数据:Jackson与Gson库比较
|
1月前
|
SQL Oracle 关系型数据库
SQL整库导出语录:全面解析与高效执行策略
在数据库管理和维护过程中,整库导出是一项常见的需求,无论是为了备份、迁移还是数据分析,掌握如何高效、准确地导出整个数据库至关重要
|
2月前
|
XML JSON 网络协议
超级好用的C++实用库之字节流解析器
超级好用的C++实用库之字节流解析器
28 3
|
1月前
|
JSON JavaScript API
商品详情数据接口解析返回的JSON数据(API接口整套流程)
商品详情数据接口解析返回的JSON数据是API接口使用中的一个重要环节,它涉及从发送请求到接收并处理响应的整个流程。以下是一个完整的API接口使用流程,包括如何解析返回的JSON数据:
|
2月前
|
缓存 网络协议 分布式数据库
超级好用的C++实用库之DNS解析
超级好用的C++实用库之DNS解析
51 0
|
2月前
|
设计模式 存储 算法
PHP中的设计模式:策略模式的深入解析与应用在软件开发的浩瀚海洋中,PHP以其独特的魅力和强大的功能吸引了无数开发者。作为一门历史悠久且广泛应用的编程语言,PHP不仅拥有丰富的内置函数和扩展库,还支持面向对象编程(OOP),为开发者提供了灵活而强大的工具集。在PHP的众多特性中,设计模式的应用尤为引人注目,它们如同精雕细琢的宝石,镶嵌在代码的肌理之中,让程序更加优雅、高效且易于维护。今天,我们就来深入探讨PHP中使用频率颇高的一种设计模式——策略模式。
本文旨在深入探讨PHP中的策略模式,从定义到实现,再到应用场景,全面剖析其在PHP编程中的应用价值。策略模式作为一种行为型设计模式,允许在运行时根据不同情况选择不同的算法或行为,极大地提高了代码的灵活性和可维护性。通过实例分析,本文将展示如何在PHP项目中有效利用策略模式来解决实际问题,并提升代码质量。
|
26天前
|
数据采集 JSON 数据处理
抓取和分析JSON数据:使用Python构建数据处理管道
在大数据时代,电商网站如亚马逊、京东等成为数据采集的重要来源。本文介绍如何使用Python结合代理IP、多线程等技术,高效、隐秘地抓取并处理电商网站的JSON数据。通过爬虫代理服务,模拟真实用户行为,提升抓取效率和稳定性。示例代码展示了如何抓取亚马逊商品信息并进行解析。
抓取和分析JSON数据:使用Python构建数据处理管道
|
12天前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
|
15天前
|
JSON 缓存 前端开发
PHP如何高效地处理JSON数据:从编码到解码
在现代Web开发中,JSON已成为数据交换的标准格式。本文探讨了PHP如何高效处理JSON数据,包括编码和解码的过程。通过简化数据结构、使用优化选项、缓存机制及合理设置解码参数等方法,可以显著提升JSON处理的性能,确保系统快速稳定运行。

推荐镜像

更多