实现功能:解析JSON

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 实现功能:解析JSON

实现功能:解析JSON

  • 使用前先使用cJSON_InitHooks函数绑定当前平台malloc个free函数(嵌入式平台这里需要注意,能够直接使用malloc及free函数的平台可以不调用cJSON_InitHooks函数初始化cJSON)
  • 当读取json文本文档时,注意文档编码格式改为“UTF-8”格式,还有注意中文乱码问题
  • cJSON源码很多情况下只申请内存,使用完成后并不释放内存,所以需自己手动释放内存,以免造成内存泄漏
  • 别删除“LICENSE”文件
  • 移植及使用说明:
  • 下载cJSON工程源码后,其中有效文件仅一个cJSON.c和cJSON.h文件,另外移植时“LICENSE”文件保留,其它均可删除。
  • 参考网上各种资料,都是直接一开始对cJSON结构体做讲解,云里雾里讲了一堆,我个人认为先研究数据结构并不科学,应该先从方法(即函数)开始研究,函数涉及到哪个变量,再仔细分析这个变量。所以这里只需要先简单了解一下cJSON结构体就行。
/* cJSON结构体 */
typedef struct cJSON 
{ 
    struct cJSON *next,*prev;          /* 遍历数组或对象链的前向或后向链表指针*/
    struct cJSON *child;               /* 数组或对象的孩子节点*/
    int type;                          /* key的类型*/
    char *valuestring;                 /* 字符串值*/
    int valueint;                      /* 整数值*/
    double valuedouble;                /* 浮点数值*/
    char *string;                      /* key的名字*/
} cJSON;
  • 先来了解5个常用的函数
/* 
** 作用:将字符串value按照cJSON结构体的结构序列化,并在堆中开辟一块内存存储cJSON结构体
** 返回值:成功返回一个指向内存块中的cJSON的指针,失败返回NULL 
*/
cJSON *cJSON_Parse(const char *value);
/* 
** 作用:获取数组成员或对象个数
** 返回值:数组成员或者对象个数
*/
int cJSON_GetArraySize(cJSON *array);
/* 
** 作用:获取JSON字符串字段值
** 返回值:成功返回一个指向cJSON类型的结构体指针,失败返回NULL
*/
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
/* 
** 作用:将cJSON数据解析成JSON字符串,并在堆中开辟一块char*的内存空间存储JSON字符串
** 返回值:成功返回一个char*指针该指针指向位于堆中JSON字符串,失败返回NULL
*/
char  *cJSON_Print(cJSON *item);
/* 
** 作用:释放位于堆中cJSON结构体内存
** 返回值:无
*/
void  cJSON_Delete(cJSON *c);
• 假设json_string字符串内容如下【json的基本单元可以理解成一组键值对(key:value)】:
{
    "key1":"str_value",
    "key2":12,
    "key3":13.0
}
• 示例代码:
#include <stdio.h>
#include "cJSON.h"
int main(void)
{
    cJSON *cjson;
    cJSON *cjson_item;
    /* 我们一般从文件中读取字符串到json_string,为了测试方便直接给json_string赋值 */
    char json_string[] = "{                 \
                \"key1\":\"str_value\", \
                \"key2\":12,         \
                \"key3\":13.0         \
              }"; 
    /* 我们首先将json_string这个字符串序列化成cJSON格式,并给cJSON结构申请内存 */
    cjson = cJSON_Parse(json_string); 
    /* 判断cJSON_Parse函数返回值确定是否序列化成功 */
    if(cjson == NULL)
    {
      printf("cJSON_Parse err\n");
          return -1;
    }
    printf("cJSON_Parse ok\n");
    /* 打印cjson对象成员个数 */
    printf("num = %d\n", cJSON_GetArraySize(cjson));
    /* 依次打印key对应的value值 */
    printf("key1 = %s\n", cJSON_GetObjectItem(cjson,"key1")->valuestring);   
    printf("key2 = %d\n", cJSON_GetObjectItem(cjson,"key2")->valueint);    
    printf("key3 = %lf\n", cJSON_GetObjectItem(cjson,"key3")->valuedouble); 
    printf("-----------------------\n");
    /* 另一种方式 */  
    /* 获取cjson第一个成员对象 */
    cjson_item = cjson->child;
    /* 打印第一个成员key和value */
    printf("%s = %s\n", cjson_item->string, cjson_item->valuestring);
    /* 指向cjson下一个成员对象 */
    cjson_item = cjson_item->next;
    /* 打印下一个成员key和value */
    printf("%s = %d\n", cjson_item->string, cjson_item->valueint);
    /* 指向cjson下一个成员对象 */
    cjson_item = cjson_item->next;
    /* 打印下一个成员key和value */
    printf("%s = %lf\n", cjson_item->string, cjson_item->valuedouble);
    /* 别忘记释放内存 */
    cJSON_Delete(cjson);
    return 0;
}
  • 上述代码运行结果:
cJSON_Parse ok
num = 3
key1 = str_value
key2 = 12
key3 = 13.000000
-----------------------
key1 = str_value
key2 = 12
key3 = 13.000000
• 到这里是不是很easy?下面看一下如何使用cJSON解析数组!
• 假设json_arr_string字符串内容如下:
{
    "test_arr":[
    {
        "key1":"str_value1",
        "key2":12,
        "key3":13.0
    },
    {
        "key1":"str_value2",
        "key2":22,
        "key3":23.0
    }]
}
  • 示例代码:
#include <stdio.h>
#include "cJSON.h"
int main(void)
{
    cJSON *cjson;
    cJSON *arr;
    cJSON *arr_child_item;
    int arr_size;
    int index;
    /* 我们一般从文件中读取字符串到json_arr_string,为了测试方便直接给json_arr_string赋值 */
  char json_arr_string[] = "{      \
                                    \"test_arr\":[    \
                                    {     \
                                        \"key1\":\"str_value1\",  \
                                        \"key2\":12,    \
                                        \"key3\":13.0   \
                                    },      \
                                    {     \
                                        \"key1\":\"str_value2\",  \
                                        \"key2\":22,    \
                \"key3\":23.0   \
      }]                                 \
    }";
  /* 我们首先将json_arr_string这个字符串序列化成cJSON格式,并给cJSON结构申请内存 */
  cjson = cJSON_Parse(json_arr_string); 
  /* 判断cJSON_Parse函数返回值确定是否序列化成功 */
  if(cjson == NULL)
  {
  printf("cJSON_Parse err\n");
        return -1;
  }
  printf("cJSON_Parse ok\n");
    /* 从cjson中获取test_arr数组对象 */
    arr = cJSON_GetObjectItem(cjson,"test_arr");
    /* 获取arr数组元素个数,用于数组遍历 */
    arr_size = cJSON_GetArraySize(arr); // 2个
    /* 获取arr数组对象的子对象 */
    arr_child_item = arr->child;
    for(index = 0; index < arr_size; index++)
    {       
        /* 依次打印arr_child_item的key对应的value值 */
        printf("key1 = %s\n", cJSON_GetObjectItem(arr_child_item,"key1")->valuestring);   
        printf("key2 = %d\n", cJSON_GetObjectItem(arr_child_item,"key2")->valueint);    
        printf("key3 = %lf\n", cJSON_GetObjectItem(arr_child_item,"key3")->valuedouble);
        printf("---------------------------------\n");
        /* 指向下一个子对象 */
        arr_child_item = arr_child_item->next; 
    }
  /* 别忘记释放内存 */
  cJSON_Delete(cjson);
    return 0;
}
  • 上述代码运行结果:
cJSON_Parse ok
key1 = str_value1
key2 = 12
key3 = 13.000000
---------------------------------
key1 = str_value2
key2 = 22
key3 = 23.000000
---------------------------------
  • 到此我们已经初步掌握了如何解析JSON,接下来我们看一下c如何创建JSON字符串
  • 我们需要新学习4个函数
/* 
** 作用:创建一个cJSON对象并为该cJSON对象申请内存空间
** 返回值:成功返回该cJSON对象内存空间首地址,失败返回NULL
*/
cJSON *cJSON_CreateObject(void);
/* 
** 作用:创建一个字符串型数据项,还有cJSON_CreateNumber等函数与之功能类似,这里就不一一介绍了
** 返回值:成功返回cJSON数据项指针,失败返回NULL
*/
cJSON *cJSON_CreateString(const char *string);
/* 
** 作用:将上一个函数创建的cJSON数据项与与其键“string”组成键值对一起添加到第一个函数创建的cJSON对象中
** 返回值:无
*/
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
/* 
** 作用:申请一块内存,cJSON对象转成字符串形式打印到该内存中,并返回该内存首地址
** 返回值:成功返回该字符串所在内存的首地址,失败返回NULL
*/
char  *cJSON_Print(cJSON *item);
  • 示例代码【先看下面运行结果再看示例代码更容易】:
#include <stdio.h>
#include "cJSON.h"
#include <stdlib.h>
int main(void)
{
    cJSON *cjson;
    cJSON *cjson_item;
    char  *print_out;
    /* 首先创建一个cJSON对象 */
    cjson = cJSON_CreateObject();
    /* 创建一个字符串型数据项,并与键“key1”组成一组键值对,添加到cjson对象中 */
    cjson_item = cJSON_CreateString("str_value");
    cJSON_AddItemToObject(cjson, "key1", cjson_item);
    /* 
    ** 创建一个整型数据项,并与键“key2”组成一组键值对,添加到cjson对象中,
    ** 注:cJSON工程对整型和浮点型并没有很好的区分开来,内部实际上统一按浮点型处理
    */
    cjson_item = cJSON_CreateNumber(12);
    cJSON_AddItemToObject(cjson, "key2", cjson_item);
    /* 创建一个浮点型数据项,并与键“key3”组成一组键值对,添加到cjson对象中 */
    cjson_item = cJSON_CreateNumber(13.1);
    cJSON_AddItemToObject(cjson, "key3", cjson_item);
    /* 将cJSON对象的内容解析为字符串并打印到到print_out中 */
    print_out = cJSON_Print(cjson);
    /* 打印print_out字符串 */
    printf("%s\n", print_out);
    /* 别忘记释放内存 */
    free(print_out); 
    cJSON_Delete(cjson);
    return 0;
}
  • 运行结果:
{
    "key1": "str_value",
    "key2": 12,
    "key3": 13.100000
}
• 上述看完了之后,下面我们来看一下如何将一个结构体转化成JSON字符串,结构体如下:
typedef struct
{
    char  * key1;
    int     key2;
    double  key3;
}STRUCT_TYPE;
  • 示例代码:
#include <stdio.h>
#include "cJSON.h"
#include <stdlib.h>
typedef struct
{
    char  * key1;
    int     key2;
    double  key3;
}STRUCT_TYPE;
int main(void)
{
    cJSON *cjson_root, *cjson_struct, *cjson_item;
    char  *print_out;
    /* 定义结构体struct_test并给其元素赋值 */
    STRUCT_TYPE struct_test;
    struct_test.key1 = "str_value";
    struct_test.key2 = 12;
    struct_test.key3 = 13.1;
    /* 首先创建一个cJSON跟对象,想象一下树状分支能更好的理解各对象之间的关系 */
    cjson_root = cJSON_CreateObject();
    /* 再次创建一个cJSON对象,用于挂载结构体成员的对象,挂载好结构体的成员后再挂载到跟对象上 */
    cjson_struct = cJSON_CreateObject();
    /* 创建一个字符串型数据项,并挂载到cjson_struct对象中 */
    cjson_item = cJSON_CreateString(struct_test.key1);
    cJSON_AddItemToObject(cjson_struct, "key1", cjson_item);
    /* 创建一个整型数据项,并添加到cjson_root对象中 */
    cjson_item = cJSON_CreateNumber(struct_test.key2);
    cJSON_AddItemToObject(cjson_struct, "key2", cjson_item);
    /* 创建一个cJSON浮点型数据项,并添加到cjson_root对象中 */
    cjson_item = cJSON_CreateNumber(struct_test.key3);
    cJSON_AddItemToObject(cjson_struct, "key3", cjson_item);
    /* 将cjson_struct对象挂载到跟对象cjson_root上 */
    cJSON_AddItemToObject(cjson_root, "struct_test", cjson_struct);
    /* 将cJSON对象的内容解析为字符串到print_out中 */
    print_out = cJSON_Print(cjson_root);
    /* 打印print_out字符串 */
    printf("%s\n", print_out);
    /* 别忘记释放内存 */
    free(print_out); 
    /* 只需要释放树跟对象就可以释放从这个树跟上所挂载的所有分支分配的内存 */ 
    cJSON_Delete(cjson_root); 
    return 0;
}
• 上述代码运行结果:
{
        "struct_test":  {
                "key1": "str_value",
                "key2": 12,
                "key3": 13.100000
        }
}
  • 稍微增加点难度,将一个结构体数组转化成JSON字符串
  • 我们又要认识2个新函数了
/* 
** 作用:创建一个cJSON数组对象并为该cJSON对象申请内存空间
** 返回值:成功返回该cJSON对象内存空间首地址,失败返回NULL
*/
cJSON *cJSON_CreateArray(void);
/* 
** 作用:将对象item添加到array数组对象中
** 返回值:无
*/
void cJSON_AddItemToArray(cJSON *array, cJSON *item);
• 示例代码:
#include <stdio.h>
#include "cJSON.h"
#include <stdlib.h>
typedef struct
{
    char  * key1;
    int     key2;
    double  key3;
}STRUCT_TYPE;
int main(void)
{
    cJSON *cjson_root, *cjson_struct_arr, *cjson_struct_item, *cjson_item;
    char  *print_out;
    int index = 0;
    /* 定义结构体数组struct_test_arr并给其成员赋值 */
    STRUCT_TYPE struct_test_arr[2];
    struct_test_arr[0].key1 = "str_value1";
    struct_test_arr[0].key2 = 12;
    struct_test_arr[0].key3 = 13.1;
    struct_test_arr[1].key1 = "str_value2";
    struct_test_arr[1].key2 = 22;
    struct_test_arr[1].key3 = 23.1;
    /* 首先创建一个cJSON跟对象,想象一下树状分支能更好的理解各对象之间的关系 */
    cjson_root = cJSON_CreateObject();
    /* 创建一个cJSON数组对象cjson_struct_arr, 填充完成后在挂载到跟对象上 */
    cjson_struct_arr = cJSON_CreateArray();
    for(index = 0; index < 2; index++)
    {
        /* 创建一个cJSON对象,用于挂载结构体成员的对象,挂载好结构体的成员后再挂载到cjson_struct_arr数组成员对象上 */
        cjson_struct_item = cJSON_CreateObject();
        /* 创建一个字符串型数据项,并挂载到cjson_struct_item对象中 */
        cjson_item = cJSON_CreateString(struct_test_arr[index].key1);
        cJSON_AddItemToObject(cjson_struct_item, "key1", cjson_item);
        /* 创建一个整型数据项,并添加到cjson_struct_item对象中 */
        cjson_item = cJSON_CreateNumber(struct_test_arr[index].key2);
        cJSON_AddItemToObject(cjson_struct_item, "key2", cjson_item);
        /* 创建一个cJSON浮点型数据项,并添加到cjson_struct_item对象中 */
        cjson_item = cJSON_CreateNumber(struct_test_arr[index].key3);
        cJSON_AddItemToObject(cjson_struct_item, "key3", cjson_item);
        /* 将cjson_struct_item对象挂载到跟对象cjson_struct_item上 */
        cJSON_AddItemToArray(cjson_struct_arr, cjson_struct_item);
    }
    /* 将cjson_struct_arr对象挂载到跟对象cjson_root上 */
    cJSON_AddItemToObject(cjson_root, "struct_test_arr", cjson_struct_arr);
    /* 将cJSON对象的内容解析为字符串到print_out中 */
    print_out = cJSON_Print(cjson_root);
    printf("%s\n", print_out);
    /* 别忘记释放内存 */
    free(print_out); 
    /* 只需要释放树跟对象内存就可以释放从这个树跟上所挂载的所有分支分配的内存 */ 
    cJSON_Delete(cjson_root); 
    return 0;
}
• 运行结果:
{
        "struct_test_arr":      [{
                        "key1": "str_value1",
                        "key2": 12,
                        "key3": 13.100000
                }, {
                        "key1": "str_value2",
                        "key2": 22,
                        "key3": 23.100000
                }]
}
  • 到这里便基本掌握了cJSON的使用,更多使用方法建议多分析分析源码。
目录
相关文章
|
11天前
|
人工智能 监控 算法
销售易CRM:功能与优势全解析
销售易CRM是国内领先的客户关系管理(CRM)系统,提供强大的销售管理、全方位客户管理、丰富的营销自动化工具、智能AI赋能及灵活的开放性平台。其功能涵盖线索获取、商机管理、客户画像、营销活动策划、智能预测等,支持企业高效管理客户、优化业务流程、提升销售效率和客户满意度。通过灵活的二次开发和API接口,销售易CRM可无缝集成企业现有系统,助力企业在数字化转型中实现业绩高质量增长。
|
3天前
|
弹性计算 运维 安全
优化管理与服务:操作系统控制平台的订阅功能解析
本文介绍了如何通过操作系统控制平台提升系统效率,优化资源利用。首先,通过阿里云官方平台开通服务并安装SysOM组件,体验操作系统控制平台的功能。接着,详细讲解了订阅管理功能,包括创建订阅、查看和管理ECS实例的私有YUM仓库权限。订阅私有YUM仓库能够集中管理软件包版本、提升安全性,并提供灵活的配置选项。最后总结指出,使用阿里云的订阅和私有YUM仓库功能,可以提高系统可靠性和运维效率,确保业务顺畅运行。
|
2月前
|
搜索推荐 UED Python
实现一个带有昼夜背景切换的动态时钟:从代码到功能解析
本文介绍了一个使用Python和Tkinter库实现的动态时钟程序,具有昼夜背景切换、指针颜色随机变化及整点和半点报时功能。通过设置不同的背景颜色和随机变换指针颜色,增强视觉吸引力;利用多线程技术确保音频播放不影响主程序运行。该程序结合了Tkinter、Pygame、Pytz等库,提供了一个美观且实用的时间显示工具。欢迎点赞、关注、转发、收藏!
142 94
|
8天前
|
数据采集 JSON 数据可视化
JSON数据解析实战:从嵌套结构到结构化表格
在信息爆炸的时代,从杂乱数据中提取精准知识图谱是数据侦探的挑战。本文以Google Scholar为例,解析嵌套JSON数据,提取文献信息并转换为结构化表格,通过Graphviz制作技术关系图谱,揭示文献间的隐秘联系。代码涵盖代理IP、请求头设置、JSON解析及可视化,提供完整实战案例。
JSON数据解析实战:从嵌套结构到结构化表格
|
10天前
|
JSON 自然语言处理 前端开发
WebSocket调试工具深度对比:Postman与Apipost功能实测解析
本文深入对比了Postman与Apipost两款WebSocket调试工具。作为实时通讯系统工程师,作者在开发智能客服系统时遇到了传统工具调试复杂、文档管理不便的问题。通过引入Apipost的智能连接池、消息分组管理和自动化文档生成等功能,实现了多环境自动切换、消息分类和接口文档自动生成,极大提升了调试效率和团队协作效果。最终,使用Apipost使接口调试时间减少40%,文档维护成本降低70%,跨团队沟通效率提升50%。
|
10天前
|
人工智能 搜索推荐 数据挖掘
销售易CRM:功能与优势全解析
销售易CRM是国内领先的客户关系管理系统,提供从线索获取到订单成交的完整销售漏斗管理,涵盖销售、客户、营销管理和AI赋能等功能。其强大的销售管理功能包括线索与商机管理、销售预测等;全方位客户管理实现360度客户视图;丰富的营销自动化工具支持多渠道营销活动;智能AI技术提升销售效率和客户满意度;灵活的开放性平台满足定制化需求;现代化界面设计简洁直观,支持多设备访问;移动端功能齐全,协同工具丰富;优质的客户服务确保快速响应和技术支持。销售易CRM助力企业优化业务流程,推动销售增长。
|
15天前
|
JSON 前端开发 安全
WebSocket调试工具深度对比:Postman与Apipost功能实测解析
如果你在寻找既能搞定WebSocket调试,又能完美管理文档的工具,不妨试试Apipos!
30 1
|
25天前
|
人工智能 小程序 API
销售易NeoCRM与纷享销客:功能、体验与价格全解析
销售易NeoCRM和纷享销客是国内知名的CRM解决方案,各有特色。销售易功能全面,涵盖销售、客户、营销管理及AI赋能,适合中大型企业;纷享销客则以强大的连接能力和业务协同见长,用户体验佳,性价比高,更适合中小企业。两者在价格、用户体验和适用场景上有所差异,企业应根据自身需求选择合适的CRM系统。
|
23天前
|
人工智能 自然语言处理 供应链
国产与国外CRM系统:功能与优势全解析
随着企业数字化转型加速,CRM系统成为提升竞争力的关键工具。国产CRM系统如销售易、神州云动、八骏科技等,以高性价比、本地化服务和灵活定制见长;国外CRM系统如Salesforce、Zoho CRM、Microsoft Dynamics 365等,则在功能创新、全球化支持和技术成熟度上表现突出。企业在选择时应综合考虑自身需求,选取最适合的CRM系统,助力业务高质量增长。
|
7天前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。

热门文章

最新文章

推荐镜像

更多