# json ## 介绍 C语言json解释器。包含json文本文件解析和生成,占用空间小、安全高效、简洁灵活,能无差别或者小修改移植到大部分的C语言平台。 ## 使用例子 ### 生成 **测试代码** ```c void test_dump(void) { json_t json, t; /* create root node */ json = json_create_object(NULL); /* Add to root node */ json_add_string_to_object(json, "name", "json parser"); json_add_string_to_object(json, "version", "1.6.0"); json_add_string_to_object(json, "description", "This is a C language version of json streamlined parser."); json_add_string_to_object(json, "repository", "https://gitee.com/Lamdonn/json"); /* Add an empty array to the root node */ t = json_add_array_to_object(json, "keywords"); /* t receive added array */ json_add_string_to_array(t, "json"); json_add_string_to_array(t, "streamlined"); json_add_string_to_array(t, "parser"); /* Add an empty object to the root node */ t = json_add_object_to_object(json, "others"); /* t receive added object */ json_add_bool_to_object(t, "open", JSON_TRUE); json_add_string_to_object(t, "license", "GPL3.0"); /* Dump JSON objects to a file */ json_file_dump(json, "test.json"); /* Delete after end of use */ json_delete(json); } ``` 生成文件名: **test.json** ```json { "name": "json parser", "version": "1.6.0", "description": "This is a C language version of json streamlined parser.", "repository": "https://gitee.com/Lamdonn/json", "keywords": ["json", "streamlined", "parser"], "others": { "open": true, "license": "GPL3.0" } } ``` ### 解析 解析前面生成的文件: **test.json** **测试代码** ```c void test_load(void) { json_t json, t; /* Load json file */ json = json_file_load("test.json"); if (!json) return; t = json_to_key(json, "name"); if (json_isstring(t)) printf("module name: %s\r\n", json_value_string(t)); t = json_to_key(json, "others", "open"); if (json_isbool(t)) printf("open: %s\r\n", json_value_bool(t) ? "yes" : "no"); t = json_to_index(json, 4, 1); if (json_isstring(t)) printf("keywords[1]: %s\r\n", json_value_string(t)); /* Delete after end of use */ json_delete(json); } ``` **打印结果** ``` module name: json parser open: yes keywords[1]: streamlined ``` ## json语法 json语法是**JavaScript**对象表示语法的子集。 1. 数据在`键值对`中,键值用`:`指示 2. 数据由逗号`,`分隔 3. 使用斜杆`\`来转义字符 4. 中括号`[]`保存数组,数组可以包含多个不同类型的值 5. 大括号`{}`保存对象,对象可以包含多个键值对 ### json数据类型 ```c #define JSON_TYPE_NULL (1) /* base type, null */ #define JSON_TYPE_BOOL (2) /* base type, bool */ #define JSON_TYPE_NUMBER (3) /* base type, number */ #define JSON_TYPE_STRING (4) /* base type, string */ #define JSON_TYPE_ARRAY (5) /* extension type, array */ #define JSON_TYPE_OBJECT (6) /* extension type, object */ ``` ### json键值对 键值对书写方式 ```json "key" : "value" ``` 其中键的类型为字符串类型,需要用双引号`""`括住。 而值可以是以下基本类型的任意一种 * 空类型(`null`) * 布尔类型(`true`、`false`) * 数字类型(整数或浮点数) * 字符串类型(在双引号`""`中) * 数组类型(在中括号`[]`中) * 对象类型(在大括号`{}`中) ### 语法例子 ```json { "information": { "module": "json", "history": [1.0, 1.1, 1.2, 1.21, 1.3, 1.31, 1.32, 1.42], "paser": true, "print": false }, "other": null } ``` ## 操作方法 ### 常用方法 #### json解析 方法原型 ```c json_t json_loads(const char* text); // 加载文本 json_t json_file_load(char* filename); // 加载文件 ``` `json_loads`函数传进json文本信息,则可以返回解析出来的json对象句柄。 `json_file_load`函数则是直接传入文件名即可加载文件返回json对象,函数内部通过C语言标准文件操作函数集对文件进行读取,然后套用`json_loads`函数进行解析,支持utf8编码文件。 #### json生成 方法原型 ```c char* json_dumps(json_t json, int preset, int unformat, int* len); // 生成文本 int json_file_dump(json_t json, char* filename); // 生成文件 ``` `json_dumps`函数将json对象转换成文本信息,其中`preset`为预置的文本长度,预置的长度和最终输出文本长度接近则可以减小内存重分配的次数而提高转换效率;`unformat`是否不采用格式化输出,不采用格式化则文本会挤在一行;`len`是转换的输出长度。 `json_file_dump`函数套用了`json_dumps`函数将文本信息存储到指定名字的文件。 #### json获取子对象 方法原型 ```c json_t json_get_child(json_t json, const char* key, int index); #define json_to_index(json, i, ...) #define json_to_key(json, key, ...) ``` 在json对象中,key是不具备查重的,也就是在同一个层级的json中,可能存在多个同名的key,`json_get_child`方法则是可以用于匹配特定的key。此函数,当`key`传入NULL时,则只有index起作用,按照索引来匹配子对象,当`key`不为NULL的时候,则只会匹配相应key的子对象,并通过index来指示匹配第几个名为`key`的对象。 ```c t = json_get_child(json, NULL, 3); // 找索引为3的子对象 t = json_get_child(json, "a", 3); // 找键为"a"索引为3的子对象 ``` `json_to_index`和`json_to_key`这两个方法都可以很方便的获取到子对象,同时可以当做查找方法查找是否存在相应的子对象。 `json_to_index`方法通过索引的方式去获取子对象,不管对象类型是数组的还是对象的,此方法都能使用。 `json_to_key`方法通过键的方式去获取子对象,但是此方法只适用于是对象类型的对象,因为数组没有键。 这两个方法的参数都带有了不定参数,这个不定参数可以输入若干个索引或者键去连续获取下个层级的子对象。如下例子: ```c t = json_to_key(json, "information", "module", "name"); ``` 等同 ```c t = json_to_key(json, "information"); t = json_to_key(t, "module"); t = json_to_key(t, "name"); ``` #### json获取对象的值类型 方法原型 ```c #define json_type(json) // 获取类型 #define json_isnull(json) // 判断是不是空类型 #define json_isbool(json) // 判断是不是布尔类型 #define json_isnumber(json) // 判断是不是数字类型 #define json_isint(json) // 判断是不是数字整型 #define json_isfloat(json) // 判断是不是数字浮点型 #define json_isstring(json) // 判断是不是字符串型 #define json_isarray(json) // 判断是不是数组型 #define json_isobject(json) // 判断是不是对象型 ``` #### json获取对象的键和值 方法原型 ```c const char* json_key(json_t json); int json_value_bool(json_t json); int json_value_int(json_t json); double json_value_float(json_t json); const char* json_value_string(json_t json); json_t json_value_array(json_t json); json_t json_value_object(json_t json); ``` 在获取值对值操作之前,建议先判断一下是不是期待的类型,如果操作不对的类型,可能破坏json的存储结构甚至导致程序奔溃。 #### json创建对象和删除对象 方法原型 ```c json_t json_create(void); void json_delete(json_t json); #define json_create_null_for_object(key) (json_set_key(json_set_null(json_create()),(key))) #define json_create_true_for_object(key) (json_set_key(json_set_bool(json_create(),JSON_TRUE),(key))) #define json_create_false_for_object(key) (json_set_key(json_set_bool(json_create(),JSON_FALSE),(key))) #define json_create_bool_for_object(key, b) (json_set_key(json_set_bool(json_create(),(b)),(key))) #define json_create_int_for_object(key, n) (json_set_key(json_set_int(json_create(),(n)),(key))) #define json_create_float_for_object(key, n) (json_set_key(json_set_float(json_create(),(n)),(key))) #define json_create_string_for_object(key, s) (json_set_key(json_set_string(json_create(),(s)),(key))) #define json_create_array_for_object(key) (json_set_key(json_set_array(json_create(),NULL),(key))) #define json_create_object_for_object(key) (json_set_key(json_set_object(json_create(),NULL),(key))) #define json_create_null_for_array() (json_set_null(json_create())) #define json_create_true_for_array() (json_set_bool(json_create(),JSON_TRUE)) #define json_create_false_for_array() (json_set_bool(json_create(),JSON_FALSE)) #define json_create_bool_for_array(b) (json_set_bool(json_create(),(b))) #define json_create_int_for_array(n) (json_set_int(json_create(),(n))) #define json_create_float_for_array(n) (json_set_float(json_create(),(n))) #define json_create_string_for_array(s) (json_set_string(json_create(),(s))) #define json_create_array_for_array() (json_set_array(json_create(),NULL)) #define json_create_object_for_array() (json_set_object(json_create(),NULL)) ``` 此类方法可以创建json的基本类型,数组和对象又可以存储json对象,所以默认都创建为空的数组和空的对象,除了这两个,其他方法都可以在创建时候指定初始化值。 创建对象指定了`key`,如果传入key则创建出来的对象可以添加到对象类型中,如果传入空则创建出来的对象可以添加到数组类型中。 数组可以存储任意类型的数据,但是一般都是存储同种类型的数据,因此数组的创建方法额外提供了初始化的方法。 ```c json_t json_create_array_int(char* key, const int* numbers, int count); json_t json_create_array_float(char* key, const float* numbers, int count); json_t json_create_array_double(char* key, const double* numbers, int count); json_t json_create_array_string(char* key, const char** strings, int count); ``` 按照C语言数组,初始化数据到json数组。 #### json链结和断链对象 方法原型 ```c json_t json_attach(json_t json, int index, json_t ins); json_t json_detach(json_t json, const char* key, int index); ``` `json_attach`方法是将创建后的对象按照索引链结到另一个对象中,而被链结的对象其值类型必须为数组型或者对象型才可以。成功返回item自身,失败则是NULL。 `json_detach`方法是将数组或者对象中,按照`json_get_child`同样的`key`和`index`配合匹配逻辑,将指定的子对象断链出来,返回其子对象,失败则返回NULL。 这两个方法都不涉及对象的创建或者删除,只是存储结构的调整,通过配合其他方法实现添加或者移除的操作。 #### json添加对象 ```c #define json_add_null_to_array(json) #define json_add_bool_to_array(json, b) #define json_add_int_to_array(json, n) #define json_add_float_to_array(json, n) #define json_add_string_to_array(json, s) #define json_add_array_to_array(json) #define json_add_object_to_array(json) #define json_add_null_to_object(json, key) #define json_add_bool_to_object(json, key, b) #define json_add_int_to_object(json, key, n) #define json_add_float_to_object(json, key, n) #define json_add_string_to_object(json, key, s) #define json_add_array_to_object(json, key) #define json_add_object_to_object(json, key) ``` 这些方法是通过创建方法和链结方法配合而成,将特定类型的数据添加到array或者object型的json对象中。 #### json移除子对象 ```c #define json_erase(json, key, index) #define json_erase_by_index(json, index) #define json_erase_by_key(json, key) ``` 这些方法是通过删除方法和断链方法配合而成,移除array或者object中特定的子对象。 #### json对象修改 方法原型 ```c json_t json_set_key(json_t json, const char* key); json_t json_set_null(json_t json); json_t json_set_bool(json_t json, int b); json_t json_set_int(json_t json, int num); json_t json_set_float(json_t json, double num); json_t json_set_string(json_t json, const char* string); json_t json_set_object(json_t json, json_t object); json_t json_set_array(json_t json, json_t array); json_t json_set_array_int(json_t json, const int* numbers, int count); json_t json_set_array_float(json_t json, const float* numbers, int count); json_t json_set_array_double(json_t json, const double* numbers, int count); json_t json_set_array_string(json_t json, const char** strings, int count); ``` 修改对象会把原来的内容覆盖掉 #### json对象复制 方法原型 ```c json_t json_copy(json_t json); ``` 根据源json对象深拷贝出一份json对象 #### json解析报错 方法原型 ```c int json_error_info(int* line, int* column); ``` 此json解析器具备较为精准的报错机制,在执行`json_loads`类加载函数时候,返回空值表明解析出错时候则可以调用`json_error_info`方法来查看具体的错误信息,`json_file_load`函数内部已经输出错误信息。 参数中,`*line`为输出的错误行;`*column`为输出的错误列,返回值则为错误类型。 如下例子,在`true`前面多了一个负号的错误 ```json { "name": "json parser", "version": "1.6.0", "description": "This is a C language version of json streamlined parser.", "repository": "https://gitee.com/Lamdonn/json", "keywords": ["json", "streamlined", "parser"], "others": { "open": -true, "license": "GPL3.0" } } ``` 加载该文件时,出现错误,表明第 8 行第 12 列的“true”附近出现错误代码为 7 的错误。 ``` Parsing error, code 7 line 8 column 12, near [true]. ``` 错误类型包含以下几种 ```c #define JSON_E_OK (0) // 没有错误 #define JSON_E_INVALID (1) // 无效 #define JSON_E_GRAMMAR (2) // 常见语法错误 #define JSON_E_END (3) // 文本末尾额外的无效文本 #define JSON_E_KEY (4) // 解析密钥时发生错误 #define JSON_E_VALUE (5) // 解析值时发生错误 #define JSON_E_MEMORY (6) // 内存分配失败 #define JSON_E_NUMBER (7) // 无效数字 #define JSON_E_INDICATOR (8) // 缺少指示符 ':' ```