目前最快的通用JSON库!

嵌入式大杂烩 2023-08-01 20:26

来源:https://gitee.com/lengjingzju/json


LJSON 说明

LJSON 是一个远远快于 cJSON、大幅度快于 RapidJSON 的 C 实现的 JSON 库,他是目前最快的通用 JSON 库。

LJSON 支持 JSON 的解析、打印、编辑,提供 DOM 和 SAX 接口,I/O 支持字符串和文件,且完全支持 nativejson-benchmark 的测试用例。

LJSON 默认使用个人开发的 ldouble 算法打印浮点数,和标准库对比可能只有第15位小数的区别,是目前最快的浮点数转字符串算法;也可选择个人优化过的 grisu2 算法或 dragonbox 算法。

功能特点

  • 更快:打印和解析速度比 cJSON 和 RapidJSON 都要快,速度最高可比 CJSON 快19倍,比 Rapid JSON 快1倍,见测试结果
  • 更省:提供多种省内存的手段,例如内存池、文件边读边解析、边打印边写文件、SAX方式的接口,可做到内存占用是个常数
  • 更强:支持DOM和SAX风格的API,提供普通模式和内存池模式JSON的接口,支持字符串和文件作为输入输出(可扩展支持其它流),扩展支持长长整形和十六进制数字
  • 更友好:C语言实现,不依赖任何库,不含平台相关代码,只有一个头文件和库文件,和cJSON对应一致的接口,代码逻辑比任何JSON库都更清晰

编译运行

编译方法

  • 直接编译
gcc -o ljson json.c json_test.c -O2 -ffunction-sections -fdata-sections -W -Wall
  • IMAKE 编译
make O=<编译输出目录> && make O=<编译输出目录> DESTDIR=<安装目录>
  • 交叉编译
make O=<编译输出目录> CROSS_COMPILE=<交叉编译器前缀> && make O=<编译输出目录> DESTDIR=<安装目录>
  • 选择浮点数转字符串算法 gcc -DJSON_DTOA_ALGORITHM=n, n可能为 0 / 1 / 2 / 3
    • 0: 个人实现的 ldouble 算法: 比谷歌的 grisu2 的默认实现快 117% ,比腾讯优化的 grisu2 实现快 30% ,比 sprintf 快 13.3
    • 1: C标准库的 sprintf
    • 2: 个人优化的 grisu2 算法: 谷歌的 grisu2 的默认实现比 sprintf 快 5.7 倍,腾讯优化的 grisu2 实现比 sprintf 快 9.1 倍,LJSON 的优化实现比 sprintf 快 11.4
    • 3: 个人优化的 dragonbox 算法: 性能和 ldouble 算法基本相差无几

运行方法

./json  <测试序号0-7>

调试方法

  • 设置 json.c 中的变量 JSON_ERROR_PRINT_ENABLE 的值为 1 后重新编译

错误检测

  • 设置 json.c 中的变量 JSON_STRICT_PARSE_MODE 的值为 0 / 1 / 2 后重新编译
    • 设置为2时 100% 符合 nativejson-benchmark 的测试用例
    • 0: 关闭不是常见的错误检测,例如解析完成后还剩尾后字符
    • 1: 检测更多的错误,且允许 key 为空字符串
    • 2: 除去 1 开启的错误检测之外,还关闭某些不是标准的特性,例如十六进制数字,第一个json对象不是array或object

性能测试

注:主要是测试速度,O2 优化等级且默认选项编译,测试文件来自 nativejson-benchmark 项目

测试平台: Ambarella CV25M Board | CPU: ARM CortexA53 | OS: Linux-5.15
测试结果: LJSON 比cJSON 解析最快可达 475%,打印最快可达 2225%,LJSON 比 RapidJSON 解析最快可达 131%,打印最快可达 137%

AARCH64-Linux测试结果

测试平台: PC | CPU: Intel i7-10700 | OS: Ubuntu 18.04 (VirtualBox)
测试结果: :LJSON 比cJSON 解析最快可达 560%,打印最快可达 2894%,LJSON 比 RapidJSON 解析最快可达 75%,打印最快可达 124%

x86_64-Linux测试结果
ldouble-x86_64测试结果

测试平台: Nationalchip STB | CPU: CSKY | DDR3: 128MB, 533MHz | OS: ECOS
注: 老版本测试结果,新版本删除了临时buffer,且解析速度提升了两倍

ECOS测试结果

json对象结构

使用 long long 类型支持,编译时需要设置 json.h 中的 JSON_LONG_LONG_SUPPORT 值为 1

struct json_list {
    struct json_list *next;
};                                      // 单向链表

struct json_list_head {
    struct json_list *next, *prev;
};                                      // 链表头,分别指向链表的第一个元素和最后一个元素

typedef enum {
    JSON_NULL = 0,
    JSON_BOOL,
    JSON_INT,
    JSON_HEX,
#if JSON_LONG_LONG_SUPPORT
    JSON_LINT,
    JSON_LHEX,
#endif
    JSON_DOUBLE,
    JSON_STRING,
    JSON_ARRAY,
    JSON_OBJECT
json_type_t;                          // json对象类型

typedef struct {
    unsigned int type:4;                // json_type_t,json_string_t作为key时才有type
    unsigned int escaped:1;             // str是否包含需要转义的字符
    unsigned int alloced:1;             // str是否是malloc的,只用于SAX APIs
    unsigned int reserved:2;
    unsigned int len:24;                // str的长度
    char *str;
json_string_t;                        // json string 对象或 type+key

typedef union {
    bool vbool;
    int vint;
    unsigned int vhex;
#if JSON_LONG_LONG_SUPPORT
    long long int vlint;
    unsigned long long int vlhex;
#endif
    double vdbl;
json_number_t;                        // json数字对象值

#if JSON_SAX_APIS_SUPPORT
typedef enum {
    JSON_SAX_START = 0,
    JSON_SAX_FINISH
json_sax_cmd_t;                       // 只用于SAX APIs,JSON_ARRAY或JSON_OBJECT有开始和结束
#endif

typedef union {
    json_number_t vnum;                 // json数字对象的值
    json_string_t vstr;                 // json字符串对象的值
#if JSON_SAX_APIS_SUPPORT
    json_sax_cmd_t vcmd;
#endif
    struct json_list_head head;         // json结构体/数组对象的值
json_value_t;                         // json对象值

typedef struct {
    struct json_list list;              // json链表节点
    json_string_t jkey;                 // json对象的type和key
    json_value_t value;                 // json对象的值
} json_object;                          // json对象

typedef struct {
    unsigned int hash;                  // json key的hash,只有JSON_OBJECT的子项才有key
    json_object *json;                  // json对象的指针
json_item_t;

typedef struct {
    unsigned int conflicted:1;          // key的hash是否有冲突
    unsigned int reserved:31;
    unsigned int total;                 // items分配的内存数目
    unsigned int count;                 // items中子项的个数
    json_item_t *items;                 // 存储子项的数组
json_items_t;                         // 存储JSON_ARRAY或JSON_OBJECT的所有子项
  • 使用单向链表管理json节点树

经典编辑模式接口

void json_memory_free(void *ptr);
  • json_item_total_get: 释放经典编辑模式申请的内存或打印到字符串返回的指针
int json_item_total_get(json_object *json);
  • json_item_total_get: 获取节点总数
void json_del_object(json_object *json);
json_object *json_new_object(json_type_t type);
json_object *json_create_item(json_type_t type, void *value);
json_object *json_create_item_array(json_type_t type, void *values, int count);

static inline json_object *json_create_null(void);
static inline json_object *json_create_bool(bool value);
static inline json_object *json_create_int(int value);
static inline json_object *json_create_hex(unsigned int value);
#if JSON_LONG_LONG_SUPPORT
static inline json_object *json_create_lint(long long int value);
static inline json_object *json_create_lhex(unsigned long long int value);
#endif
static inline json_object *json_create_double(double value);
static inline json_object *json_create_string(json_string_t *value);
static inline json_object *json_create_array(void);
static inline json_object *json_create_object(void);

static inline json_object *json_create_bool_array(bool *values, int count);
static inline json_object *json_create_int_array(int *values, int count);
static inline json_object *json_create_hex_array(unsigned int *values, int count);
#if JSON_LONG_LONG_SUPPORT
static inline json_object *json_create_lint_array(long long int *values, int count);
static inline json_object *json_create_lhex_array(unsigned long long int *values, int count);
#endif
static inline json_object *json_create_double_array(double *values, int count);
static inline json_object *json_create_string_array(json_string_t *values, int count);
  • json_del_object: 删除节点(并递归删除子节点)
  • json_new_object: 创建指定类型的空节点
  • json_create_item: 创建指定类型的有值节点
  • json_create_item_array: 快速创建指定类型的数组节点,使用要点同上
  • 要点:创建的节点使用完后需要使用json_del_object删除,但是如果把该节点加入了array或object,该节点无需再删除
void json_string_info_update(json_string_t *jstr);
unsigned int json_string_hash_code(json_string_t *jstr);
int json_string_strdup(json_string_t *src, json_string_t *dst);
static inline int json_set_key(json_object *json, json_string_t *jkey);
static inline int json_set_string_value(json_object *json, json_string_t *jstr);
  • json_string_info_update: 更新jstr的len和escaped,如果传入的len大于0,则什么都不做
  • json_string_hash_code: 获取字符串的hash值
  • json_string_strdup: 修改LJSON中的字符串
  • json_set_key: 修改节点的key(JSON_OBJECT类型下的子节点才有key)
  • json_set_string_value: 修改string类型节点的value
int json_get_number_value(json_object *json, json_type_t type, void *value);
int json_set_number_value(json_object *json, json_type_t type, void *value);

static inline bool json_get_bool_value(json_object *json);
static inline int json_get_int_value(json_object *json);
static inline unsigned int json_get_hex_value(json_object *json);
#if JSON_LONG_LONG_SUPPORT
static inline long long int json_get_lint_value(json_object *json);
static inline unsigned long long int json_get_lhex_value(json_object *json);
#endif
static inline double json_get_double_value(json_object *json);

static inline int json_set_bool_value(json_object *json, bool value);
static inline int json_set_int_value(json_object *json, int value);
static inline int json_set_hex_value(json_object *json, unsigned int value);
#if JSON_LONG_LONG_SUPPORT
static inline int json_set_lint_value(json_object *json, long long int value);
static inline int json_set_lhex_value(json_object *json, unsigned long long int value);
#endif
static inline int json_set_double_value(json_object *json, double value);
  • json_get_number_value: 获取number类型节点的value,返回值: 正值(原有类型枚举值)表示成功有强制转换,0表示成功且类型对应,-1表示失败不是number类型
  • json_set_number_value: 修改number类型节点的value,返回值说明同上
int json_get_array_size(json_object *json);
int json_get_object_size(json_object *json);
json_object *json_get_array_item(json_object *json, int seq, json_object **prev);
json_object *json_get_object_item(json_object *json, const char *key, json_object **prev);
  • json_get_array_size: 获取array类型节点的大小(有多少个一级子节点)
  • json_get_object_size: 获取object类型节点的大小(有多少个一级子节点)
  • json_get_array_item: 获取array类型节点的的第seq个子节点
  • json_get_object_item: 获取object类型节点的指定key的子节点
json_object *json_search_object_item(json_items_t *items, json_string_t *jkey, unsigned int hash);
void json_free_items(json_items_t *items);
int json_get_items(json_object *json, json_items_t *items);
  • json_search_object_item: 二分法查找items中的指定key的json对象
  • json_free_items: 释放items中分配的内存
  • json_get_items: 获取JSON_ARRAY或JSON_OBJECT中的所有一级子节点,加速访问
int json_add_item_to_array(json_object *array, json_object *item);
int json_add_item_to_object(json_object *object, json_object *item);
  • 将节点加入到array或object,加入object需要先设置item的key
  • 经典模式如果该节点加入成功,无需再调用json_del_object删除该节点
json_object *json_detach_item_from_array(json_object *json, int seq);
json_object *json_detach_item_from_object(json_object *json, const char *key);
  • 将指定的子节点从array或object取下并返回
  • 使用完成后需要使用json_del_object删除返回的子节点
  • 注:使用内存cache的json不需要调用json_del_object删除返回的子节点
int json_del_item_from_array(json_object *json, int seq);
int json_del_item_from_object(json_object *json, const char *key);
  • 将指定的子节点从array或object删除
int json_replace_item_in_array(json_object *arrayint seq, json_object *new_item);
int json_replace_item_in_object(json_object *object, json_object *new_item);
  • 将array或object指定的子节点替换成new_item
  • 如果原来的子节点不存在就直接新增new_item
json_object *json_deepcopy(json_object *json);
int json_copy_item_to_array(json_object *array, json_object *item);
int json_copy_item_to_object(json_object *object, json_object *item);
  • json_deepcopy: 节点深度复制
  • json_copy_item_to_xxxx: 将节点复制并加入到array或object
  • 如果该节点加入成功,还需要再调用json_del_object删除原来传入的节点
json_object *json_add_new_item_to_array(json_object *arrayjson_type_t type, void* value);
json_object *json_add_new_item_to_object(json_object *object, json_type_t type, json_string_t *jkey, void* value);

static inline json_object *json_add_null_to_array(json_object *array);
static inline json_object *json_add_bool_to_array(json_object *arraybool value);
static inline json_object *json_add_int_to_array(json_object *arrayint value);
static inline json_object *json_add_hex_to_array(json_object *arrayunsigned int value);
#if JSON_LONG_LONG_SUPPORT
static inline json_object *json_add_lint_to_array(json_object *arraylong long int value);
static inline json_object *json_add_lhex_to_array(json_object *arrayunsigned long long int value);
#endif
static inline json_object *json_add_double_to_array(json_object *arraydouble value);
static inline json_object *json_add_string_to_array(json_object *arrayjson_string_t *value);
static inline json_object *json_add_array_to_array(json_object *array);
static inline json_object *json_add_object_to_array(json_object *array);

static inline json_object *json_add_null_to_object(json_object *object, json_string_t *jkey);
static inline json_object *json_add_bool_to_object(json_object *object, json_string_t *jkey, bool value);
static inline json_object *json_add_int_to_object(json_object *object, json_string_t *jkey, int value);
static inline json_object *json_add_hex_to_object(json_object *object, json_string_t *jkey, unsigned int value);
#if JSON_LONG_LONG_SUPPORT
static inline json_object *json_add_lint_to_object(json_object *object, json_string_t *jkey, long long int value);
static inline json_object *json_add_lhex_to_object(json_object *object, json_string_t *jkey, unsigned long long int value);
#endif
static inline json_object *json_add_double_to_object(json_object *object, json_string_t *jkey, double value);
static inline json_object *json_add_string_to_object(json_object *object, json_string_t *jkey, json_string_t *value);
static inline json_object *json_add_array_to_object(json_object *object, json_string_t *jkey);
static inline json_object *json_add_object_to_object(json_object *object, json_string_t *jkey);
  • json_add_new_item_to_array: 新建指定类型的节点,并将该节点加入array
  • json_add_new_item_to_object: 新建指定类型的节点,并将该节点加入object
/*
 * The below APIs are also available to pool json:
 * json_item_total_get
 * json_string_info_update
 * json_get_number_value / ...
 * json_set_number_value / ...
 * json_get_array_size
 * json_get_object_size
 * json_get_array_item
 * json_get_object_item
 * json_search_object_item
 * json_free_items
 * json_get_items
 * json_add_item_to_array
 * json_add_item_to_object
 * json_detach_item_from_array
 * json_detach_item_from_object
 */

  • 编辑(一般模式)的一些API(内部没有调用malloc/free)也可以用于内存池
  • 注意: pool模式时,json_detach_item_from_array/object返回的json节点不能使用json_del_object删除

内存池结构

typedef struct {
    struct json_list list;              // 链表节点
    size_t size;                        // 内存大小
    char *ptr;                          // 首部地址
    char *cur;                          // 当前地址
json_mem_node_t;

typedef struct {
    struct json_list_head head;         // json_mem_node_t挂载节点
    size_t mem_size;                    // 默认分配块内存大小
    json_mem_node_t *cur_node;          // 当前使用的内存节点
json_mem_mgr_t;

typedef struct {
    json_mem_mgr_t obj_mgr;             // 对象节点的内存管理
    json_mem_mgr_t key_mgr;             // 字符串key的内存管理
    json_mem_mgr_t str_mgr;             // 字符串value的内存管理
json_mem_t;
  • 内存池原理是先分配一个大内存,然后从大内存中分配小内存
  • 内存池只能统一释放申请

内存池编辑模式接口

void pjson_memory_free(json_mem_t *mem);
void pjson_memory_init(json_mem_t *mem);
+int pjson_memory_statistics(json_mem_mgr_t *mgr);
  • pjson_memory_free: 释放json内存池管理的所有内存
  • pjson_memory_init: 初始化json内存池管理结构
  • pjson_memory_statistics: 统计内存池分配的内存
  • 注:编辑模式初始化内存池后可修改mem_size
  • 注:使用内存池前需要使用pjson_memory_init初始化内存池入口,全部使用完成后使用pjson_memory_free释放
  • 注:绝对不要调用存在malloc, free之类的api,例如json_new_objectjson_del_object
json_object *pjson_new_object(json_type_t type, json_mem_t *mem);
json_object *pjson_create_item(json_type_t type, void *value, json_mem_t *mem);
json_object *pjson_create_item_array(json_type_t item_type, void *values, int count, json_mem_t *mem);

static inline json_object *pjson_create_null(json_mem_t *mem);
static inline json_object *pjson_create_bool(bool value, json_mem_t *mem);
static inline json_object *pjson_create_int(int value, json_mem_t *mem);
static inline json_object *pjson_create_hex(unsigned int value, json_mem_t *mem);
#if JSON_LONG_LONG_SUPPORT
static inline json_object *pjson_create_lint(long long int value, json_mem_t *mem);
static inline json_object *pjson_create_lhex(unsigned long long int value, json_mem_t *mem);
#endif
static inline json_object *pjson_create_double(double value, json_mem_t *mem);
static inline json_object *pjson_create_string(json_string_t *value, json_mem_t *mem);
static inline json_object *pjson_create_array(json_mem_t *mem);
static inline json_object *pjson_create_object(json_mem_t *mem);

static inline json_object *pjson_create_bool_array(bool *values, int count, json_mem_t *mem);
static inline json_object *pjson_create_int_array(int *values, int count, json_mem_t *mem);
static inline json_object *pjson_create_hex_array(unsigned int *values, int count, json_mem_t *mem);
#if JSON_LONG_LONG_SUPPORT
static inline json_object *pjson_create_lint_array(long long int *values, int count, json_mem_t *mem);
static inline json_object *pjson_create_lhex_array(unsigned long long int *values, int count, json_mem_t *mem);
#endif
static inline json_object *pjson_create_double_array(double *values, int count, json_mem_t *mem);
static inline json_object *pjson_create_string_array(json_string_t *values, int count, json_mem_t *mem);
  • pjson_new_object: 在内存池中创建指定类型的空节点
  • pjson_create_item: 在内存池中创建指定类型的有值节点
  • pjson_create_item_array: 在内存池中创建(子节点指定类型)的array节点
int pjson_string_strdup(json_string_t *src, json_string_t *dst, json_mem_mgr_t *mgr);
static inline int pjson_set_key(json_object *json, json_string_t *jkey, json_mem_t *mem);
static inline int pjson_set_string_value(json_object *json, json_string_t *jstr, json_mem_t *mem);
  • pjson_string_strdup: 修改JSON中的字符串,该字符串在内存池中分配
  • pjson_set_key: 修改json节点的key,该key在内存池中分配
  • pjson_set_string_value: 修改 JSON_STRING 类型json节点的值,该值在内存池中分配
int pjson_replace_item_in_array(json_object *arrayint seq, json_object *new_item);
int pjson_replace_item_in_object(json_object *object, json_object *new_item);
  • 将array或object指定的子节点替换成new_item
  • 如果原来的子节点不存在就直接新增new_item
json_object *pjson_deepcopy(json_object *json, json_mem_t *mem);
int pjson_copy_item_to_array(json_object *array, json_object *item, json_mem_t *mem);
int pjson_copy_item_to_object(json_object *object, json_object *item, json_mem_t *mem);
  • pjson_deepcopy: 节点深度复制
  • pjson_copy_item_to_xxxx: 将节点复制并加入到array或object
json_object *pjson_add_new_item_to_array(json_object *arrayjson_type_t type, void *value, json_mem_t *mem);
json_object *pjson_add_new_item_to_object(json_object *object, json_type_t type, json_string_t *jkey, void *value, json_mem_t *mem);

static inline json_object *pjson_add_null_to_array(json_object *arrayjson_mem_t *mem);
static inline json_object *pjson_add_bool_to_array(json_object *arraybool value, json_mem_t *mem);
static inline json_object *pjson_add_int_to_array(json_object *arrayint value, json_mem_t *mem);
static inline json_object *pjson_add_hex_to_array(json_object *arrayunsigned int value, json_mem_t *mem);
#if JSON_LONG_LONG_SUPPORT
static inline json_object *pjson_add_lint_to_array(json_object *arraylong long int value, json_mem_t *mem);
static inline json_object *pjson_add_lhex_to_array(json_object *arrayunsigned long long int value, json_mem_t *mem);
#endif
static inline json_object *pjson_add_double_to_array(json_object *arraydouble value, json_mem_t *mem);
static inline json_object *pjson_add_string_to_array(json_object *arrayjson_string_t *value, json_mem_t *mem);
static inline json_object *pjson_add_array_to_array(json_object *arrayjson_mem_t *mem);
static inline json_object *pjson_add_object_to_array(json_object *arrayjson_mem_t *mem);

static inline json_object *pjson_add_null_to_object(json_object *object, json_string_t *jkey, json_mem_t *mem);
static inline json_object *pjson_add_bool_to_object(json_object *object, json_string_t *jkey, bool value, json_mem_t *mem);
static inline json_object *pjson_add_int_to_object(json_object *object, json_string_t *jkey, int value, json_mem_t *mem);
static inline json_object *pjson_add_hex_to_object(json_object *object, json_string_t *jkey, unsigned int value, json_mem_t *mem);
#if JSON_LONG_LONG_SUPPORT
static inline json_object *pjson_add_lint_to_object(json_object *object, json_string_t *jkey, long long int value, json_mem_t *mem);
static inline json_object *pjson_add_lhex_to_object(json_object *object, json_string_t *jkey, unsigned long long int value, json_mem_t *mem);
#endif
static inline json_object *pjson_add_double_to_object(json_object *object, json_string_t *jkey, double value, json_mem_t *mem);
static inline json_object *pjson_add_string_to_object(json_object *object, json_string_t *jkey, json_string_t *value, json_mem_t *mem);
static inline json_object *pjson_add_array_to_object(json_object *object, json_string_t *jkey, json_mem_t *mem);
static inline json_object *pjson_add_object_to_object(json_object *object, json_string_t *jkey, json_mem_t *mem);
  • pjson_add_new_item_to_array: 在内存池中创建指定类型的子节点,并加入到array
  • pjson_add_new_item_to_object: 在内存池中创建指定类型的子节点,并加入到object

DOM打印/DOM解析

typedef struct {
    size_t str_len;                     // 打印到字符串时返回生成的字符串长度(strlen)
    size_t plus_size;                   // 打印生成的字符串的realloc的增量大小 / write buffer的缓冲区大小
    size_t item_size;                   // 每个json对象生成字符串的预估的平均长度
    int item_total;                     // json对象节点的总数
    bool format_flag;                   // 字符串是否进行格式化
    const char *path;                   // 文件保存路径
json_print_choice_t;
  • plus_size: 经典模式下打印字符串realloc的增量,或write buffer的缓冲区大小,最小值/默认值为 JSON_PRINT_SIZE_PLUS_DEF
  • item_size: 每个json对象生成字符串的预估的平均长度,最小值/默认值为 JSON_UNFORMAT_ITEM_SIZE_DEF 和 JSON_FORMAT_ITEM_SIZE_DEF
  • item_total: json对象节点的总数如果此值未设置,将自动计算总数;否则取默认值JSON_PRINT_NUM_PLUS_DEF
  • format_flag: 格式化打印选项,false: 压缩打印;true: 格式化打印
  • path: 如果path不为空,将直接边打印边输出到文件;否则是打印到一个大的完整字符串
char *json_print_common(json_object *json, json_print_choice_t *choice);

static inline char *json_print_format(json_object *json, int item_total, size_t *length);
static inline char *json_print_unformat(json_object *json, int item_total, size_t *length);
static inline char *json_fprint_format(json_object *json, int item_total, const char *path);
static inline char *json_fprint_unformat(json_object *json, int item_total, const char *path);
  • json_print_common: 打印通用接口
  • json_print_format: 格式化打印成字符串的简写接口,需要 json_memory_free释放返回的字符串
  • json_print_unformat: 类似json_print_format,只是非格式化打印
  • json_fprint_format: 格式化直接边打印边输出到文件的简写接口,成功返回"ok"字符串,不需要 json_memory_free释放返回的字符串
  • json_fprint_unformat: 类似json_fprint_format,只是非格式化打印
typedef struct {
    size_t mem_size;                    // 内存池每个内存块的大小
    size_t read_size;                   // json读缓冲的初始大小
    size_t str_len;                     // 要解析的字符串长度
    bool reuse_flag;                    // 是否复用原始json字符串,原始json字符串会被修改
    json_mem_t *mem;                    // 内存池管理结构
    const char *path;                   // 要解析的json文件的路径
    char *str;                          // 要解析的json字符串的指针
json_parse_choice_t;
  • mem_size: 内存池每个内存块的大小,最小值为 (str_len / JSON_PARSE_NUM_DIV_DEF) 的值
  • read_size: json读缓冲的初始大小,最小值 JSON_PARSE_READ_SIZE_DEF
  • str_len: 要解析的字符串长度 strlen(str),使用内存池时该参数有效,如果为0,json_parse_common会自己计算一次
  • path: 要解析的json文件,str 和 path 有且只有一个有值
  • str: 要解析的json字符串,str 和 path 有且只有一个有值
json_object *json_parse_common(json_parse_choice_t *choice);
static inline json_object *json_parse_str(char *str, size_t str_len);
static inline json_object *json_fast_parse_str(char *str, size_t str_len, json_mem_t *mem);
static inline json_object *json_reuse_parse_str(char *str, size_t str_len, json_mem_t *mem);
static inline json_object *json_parse_file(const char *path);
static inline json_object *json_fast_parse_file(const char *path, json_mem_t *mem);
  • json_parse_common: 解析通用接口
  • json_parse_str: 类似cJSON的经典字符串解析的简写接口,用完后需要json_del_object释放返回的管理结构
  • json_fast_parse_str: 使用内存池的字符串解析的简写接口,使用前必须使用pjson_memory_init初始化mem,用完后需要pjson_memory_free释放
  • json_reuse_parse_str: 使用内存池极速解析并复用原始字符串,会修改传入的字符串,使用过程中不要释放原始的str , 速度最快,占用内存最少
  • json_parse_file: 类似json_parse_str,只是从文件边读边解析
  • json_fast_parse_file: 类似json_parse_str, 只是边读文件边解析

SAX打印/SAX解析

使用 SAX APIs 编译时需要设置 json.h 中的 JSON_SAX_APIS_SUPPORT 值为 1

typedef void* json_sax_print_hd;
  • json_sax_print_hd: 实际是json_sax_print_t指针
json_sax_print_hd json_sax_print_start(json_print_choice_t *choice);
static inline json_sax_print_hd json_sax_print_format_start(int item_total);
static inline json_sax_print_hd json_sax_print_unformat_start(int item_total);
static inline json_sax_print_hd json_sax_fprint_format_start(int item_total, const char *path);
static inline json_sax_print_hd json_sax_fprint_unformat_start(int item_total, const char *path);
  • json_sax_print_start: sax打印时必须先调用此函数,进行资源初始化并获取句柄 json_sax_print_hd
    • 如果打印到字符串,最好给一个item_total值,用于计算生成字符串的增量
int json_sax_print_value(json_sax_print_hd handle, json_type_t type, json_string_t *jkey, const void *value);
static inline int json_sax_print_null(json_sax_print_hd handle, json_string_t *jkey);
static inline int json_sax_print_bool(json_sax_print_hd handle, json_string_t *jkey, bool value);
static inline int json_sax_print_int(json_sax_print_hd handle, json_string_t *jkey, int value);
static inline int json_sax_print_hex(json_sax_print_hd handle, json_string_t *jkey, unsigned int value);
#if JSON_LONG_LONG_SUPPORT
static inline int json_sax_print_lint(json_sax_print_hd handle, json_string_t *jkey, long long int value);
static inline int json_sax_print_lhex(json_sax_print_hd handle, json_string_t *jkey, unsigned long long int value);
#endif
static inline int json_sax_print_double(json_sax_print_hd handle, json_string_t *jkey, double value);
static inline int json_sax_print_string(json_sax_print_hd handle, json_string_t *jkey, json_string_t *value);
static inline int json_sax_print_array(json_sax_print_hd handle, json_string_t *jkey, json_sax_cmd_t value);
static inline int json_sax_print_object(json_sax_print_hd handle, json_string_t *jkey, json_sax_cmd_t value);
  • json_sax_print_value: sax 条目通用打印接口,如果要打印节点的父节点是object,key必须有值;其它情况下key填不填值均可
    • array 和 object 要打印两次,一次值是 JSON_SAX_START 表示开始,一次值是 JSON_SAX_FINISH 表示完成
    • 传入key时可以先不用json_saxstr_update 计算长度
char *json_sax_print_finish(json_sax_print_hd handle, size_t *length);
  • json_sax_print_finish: sax打印完成必须调用此函数,释放中间资源并返回字符串
    • 打印成字符串时,该函数返回打印的字符串, 需要 json_memory_free释放返回的字符串
    • 直接边打印边输出到文件时,成功返回"ok"字符串,不需要 json_memory_free释放返回的字符串
typedef enum {
    JSON_SAX_PARSE_CONTINUE = 0,
    JSON_SAX_PARSE_STOP
json_sax_ret_t;

typedef struct {
    int total;
    int index;
    json_string_t *array;
    json_value_t value;
json_sax_parser_t;
typedef json_sax_ret_t (*json_sax_cb_t)(json_sax_parser_t *parser);

typedef struct {
    char *str;
    const char *path;
    size_t read_size;
    json_sax_cb_t cb;
json_sax_parse_choice_t;
  • json_sax_ret_t: JSON_SAX_PARSE_CONTINUE 表示SAX解析器继续解析,JSON_SAX_PARSE_STOP 表示中断解析
  • json_sax_cb_t: 调用者自己填写的回调函数,必须有值,返回 JSON_SAX_PARSE_STOP 表示中断解析并返回
  • json_sax_parser_t: 传给回调函数的值
    • array 是 array/object 类型+key 的层次结构,total表示当前分配了多少层次,index表示当前用了多少层次,即当前层为 array[index]
    • value 是当前层的值
  • json_sax_parse_choice_t: 参考 json_parse_choice_t 说明
int json_sax_parse_common(json_sax_parse_choice_t *choice);
static inline int json_sax_parse_str(char *str, size_t str_len, json_sax_cb_t cb);
static inline int json_sax_parse_file(const char *path, json_sax_cb_t cb);
  • json_sax_parse_common: sax解析通用接口,因为不需要保存json树结构,所以不需要使用内存池
  • json_sax_parse_str: 从字符串解析的快捷接口
  • json_sax_parse_file: 从文件边读边解析的快捷接口

本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。

往期推荐

《嵌入式Linux驱动大全》

在公众号聊天界面回复1024,可获取嵌入式资源

嵌入式大杂烩 专注于嵌入式技术,包括但不限于C/C++、嵌入式、物联网、Linux等编程学习笔记,同时,内包含大量的学习资源。欢迎关注,一同交流学习,共同进步!
评论
  • 作为优秀工程师的你,已身经百战、阅板无数!请先醒醒,新的项目来了,这是一个既要、又要、还要的产品需求,ARM核心板中一个处理器怎么能实现这么丰富的外围接口?踌躇之际,你偶阅此文。于是,“潘多拉”的魔盒打开了!没错,USB资源就是你打开新世界得钥匙,它能做哪些扩展呢?1.1  USB扩网口通用ARM处理器大多带两路网口,如果项目中有多路网路接口的需求,一般会选择在主板外部加交换机/路由器。当然,出于成本考虑,也可以将Switch芯片集成到ARM核心板或底板上,如KSZ9897、
    万象奥科 2024-12-03 10:24 68浏览
  • 当前,智能汽车产业迎来重大变局,随着人工智能、5G、大数据等新一代信息技术的迅猛发展,智能网联汽车正呈现强劲发展势头。11月26日,在2024紫光展锐全球合作伙伴大会汽车电子生态论坛上,紫光展锐与上汽海外出行联合发布搭载紫光展锐A7870的上汽海外MG量产车型,并发布A7710系列UWB数字钥匙解决方案平台,可应用于数字钥匙、活体检测、脚踢雷达、自动泊车等多种智能汽车场景。 联合发布量产车型,推动汽车智能化出海紫光展锐与上汽海外出行达成战略合作,联合发布搭载紫光展锐A7870的量产车型
    紫光展锐 2024-12-03 11:38 103浏览
  • RDDI-DAP错误通常与调试接口相关,特别是在使用CMSIS-DAP协议进行嵌入式系统开发时。以下是一些可能的原因和解决方法: 1. 硬件连接问题:     检查调试器(如ST-Link)与目标板之间的连接是否牢固。     确保所有必要的引脚都已正确连接,没有松动或短路。 2. 电源问题:     确保目标板和调试器都有足够的电源供应。     检查电源电压是否符合目标板的规格要求。 3. 固件问题: &n
    丙丁先生 2024-12-01 17:37 102浏览
  • 最近几年,新能源汽车愈发受到消费者的青睐,其销量也是一路走高。据中汽协公布的数据显示,2024年10月,新能源汽车产销分别完成146.3万辆和143万辆,同比分别增长48%和49.6%。而结合各家新能源车企所公布的销量数据来看,比亚迪再度夺得了销冠宝座,其10月新能源汽车销量达到了502657辆,同比增长66.53%。众所周知,比亚迪是新能源汽车领域的重要参与者,其一举一动向来为外界所关注。日前,比亚迪汽车旗下品牌方程豹汽车推出了新车方程豹豹8,该款车型一上市就迅速吸引了消费者的目光,成为SUV
    刘旷 2024-12-02 09:32 119浏览
  • 11-29学习笔记11-29学习笔记习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-02 23:58 73浏览
  • 戴上XR眼镜去“追龙”是种什么体验?2024年11月30日,由上海自然博物馆(上海科技馆分馆)与三湘印象联合出品、三湘印象旗下观印象艺术发展有限公司(下简称“观印象”)承制的《又见恐龙》XR嘉年华在上海自然博物馆重磅开幕。该体验项目将于12月1日正式对公众开放,持续至2025年3月30日。双向奔赴,恐龙IP撞上元宇宙不久前,上海市经济和信息化委员会等部门联合印发了《上海市超高清视听产业发展行动方案》,特别提到“支持博物馆、主题乐园等场所推动超高清视听技术应用,丰富线下文旅消费体验”。作为上海自然
    电子与消费 2024-11-30 22:03 98浏览
  • 遇到部分串口工具不支持1500000波特率,这时候就需要进行修改,本文以触觉智能RK3562开发板修改系统波特率为115200为例,介绍瑞芯微方案主板Linux修改系统串口波特率教程。温馨提示:瑞芯微方案主板/开发板串口波特率只支持115200或1500000。修改Loader打印波特率查看对应芯片的MINIALL.ini确定要修改的bin文件#查看对应芯片的MINIALL.ini cat rkbin/RKBOOT/RK3562MINIALL.ini修改uart baudrate参数修改以下目
    Industio_触觉智能 2024-12-03 11:28 87浏览
  • 《高速PCB设计经验规则应用实践》+PCB绘制学习与验证读书首先看目录,我感兴趣的是这一节;作者在书中列举了一条经典规则,然后进行详细分析,通过公式推导图表列举说明了传统的这一规则是受到电容加工特点影响的,在使用了MLCC陶瓷电容后这一条规则已经不再实用了。图书还列举了高速PCB设计需要的专业工具和仿真软件,当然由于篇幅所限,只是介绍了一点点设计步骤;我最感兴趣的部分还是元件布局的经验规则,在这里列举如下:在这里,演示一下,我根据书本知识进行电机驱动的布局:这也算知行合一吧。对于布局书中有一句:
    wuyu2009 2024-11-30 20:30 125浏览
  • TOF多区传感器: ND06   ND06是一款微型多区高集成度ToF测距传感器,其支持24个区域(6 x 4)同步测距,测距范围远达5m,具有测距范围广、精度高、测距稳定等特点。适用于投影仪的无感自动对焦和梯形校正、AIoT、手势识别、智能面板和智能灯具等多种场景。                 如果用ND06进行手势识别,只需要经过三个步骤: 第一步&
    esad0 2024-12-04 11:20 58浏览
  • 概述 说明(三)探讨的是比较器一般带有滞回(Hysteresis)功能,为了解决输入信号转换速率不够的问题。前文还提到,即便使能滞回(Hysteresis)功能,还是无法解决SiPM读出测试系统需要解决的问题。本文在说明(三)的基础上,继续探讨为SiPM读出测试系统寻求合适的模拟脉冲检出方案。前四代SiPM使用的高速比较器指标缺陷 由于前端模拟信号属于典型的指数脉冲,所以下降沿转换速率(Slew Rate)过慢,导致比较器检出出现不必要的问题。尽管比较器可以使能滞回(Hysteresis)模块功
    coyoo 2024-12-03 12:20 116浏览
  •         温度传感器的精度受哪些因素影响,要先看所用的温度传感器输出哪种信号,不同信号输出的温度传感器影响精度的因素也不同。        现在常用的温度传感器输出信号有以下几种:电阻信号、电流信号、电压信号、数字信号等。以输出电阻信号的温度传感器为例,还细分为正温度系数温度传感器和负温度系数温度传感器,常用的铂电阻PT100/1000温度传感器就是正温度系数,就是说随着温度的升高,输出的电阻值会增大。对于输出
    锦正茂科技 2024-12-03 11:50 111浏览
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2024-12-02 10:40 120浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦