varch/doc/json.en.md

378 lines
15 KiB
Markdown

# JSON
## Introduction
It's a JSON interpreter in the C language. It includes the parsing and generation of JSON text files, occupies a small amount of space, is secure, efficient, concise, and flexible. It can be transplanted to most C language platforms with no or only minor modifications.
## Usage Examples
### Generation
**Test Code**
```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);
}
```
**Generated File Name**: **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"
}
}
```
### Parsing
Parse the previously generated file: **test.json**
**Test Code**
```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);
}
```
**Printed Results**
```
module name: json parser
open: yes
keywords[1]: streamlined
```
## JSON Syntax
JSON syntax is a subset of the JavaScript object representation syntax.
1. Data is in `key-value pairs`, and the key-value is indicated by `:`.
2. Data is separated by commas `,`.
3. Use the backslash `\` to escape characters.
4. Square brackets `[]` hold arrays, and arrays can contain multiple values of different types.
5. Curly braces `{}` hold objects, and objects can contain multiple key-value pairs.
### JSON Data Types
```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 Key-Value Pairs
The way to write key-value pairs:
```json
"key" : "value"
```
The key is of the string type and needs to be enclosed in double quotes `""`.
The value can be any of the following basic types:
* Null type (`null`)
* Boolean type (`true`, `false`)
* Numeric type (integer or floating-point number)
* String type (in double quotes `""`)
* Array type (in square brackets `[]`)
* Object type (in curly braces `{}`)
### Syntax Example
```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
}
```
## Operation Methods
### Common Methods
#### JSON Parsing
**Method Prototypes**
```c
json_t json_loads(const char* text); // Load text
json_t json_file_load(char* filename); // Load file
```
The `json_loads` function takes in JSON text information and can return the handle of the parsed JSON object. The `json_file_load` function can load a file and return a JSON object just by passing in the file name. Inside the function, it reads the file through the standard file operation function set in the C language and then applies the `json_loads` function for parsing. It supports UTF8 encoded files.
#### JSON Generation
**Method Prototypes**
```c
char* json_dumps(json_t json, int preset, int unformat, int* len); // Generate text
int json_file_dump(json_t json, char* filename); // Generate file
```
The `json_dumps` function converts a JSON object into text information. The `preset` is the preset text length. If the preset length is close to the final output text length, the number of memory reallocations can be reduced and the conversion efficiency can be improved. `unformat` indicates whether to use formatted output or not. If not using formatted output, the text will be squeezed into one line. `len` is the output length of the conversion.
The `json_file_dump` function applies the `json_dumps` function to store the text information into a file with the specified name.
#### JSON Getting Sub-objects
**Method Prototypes**
```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,...)
```
In a JSON object, keys are not checked for duplication, that is, in the same level of JSON, there may be multiple keys with the same name. The `json_get_child` method can be used to match specific keys. For this function, when `key` is passed as NULL, only the index takes effect and it matches the sub-object according to the index. When `key` is not NULL, it will only match the sub-object of the corresponding key and use the index to indicate which object named `key` to match.
```c
t = json_get_child(json, NULL, 3); // Find the sub-object with index 3
t = json_get_child(json, "a", 3); // Find the sub-object with key "a" and index 3
```
The `json_to_index` and `json_to_key` methods can both conveniently get sub-objects and can also be used as search methods to check whether corresponding sub-objects exist.
The `json_to_index` method gets sub-objects by index. This method can be used regardless of whether the object type is an array or an object.
The `json_to_key` method gets sub-objects by key, but this method is only applicable to object-type objects because arrays don't have keys.
The parameters of these two methods have variable arguments, which can input several indexes or keys to continuously get sub-objects of the next level. For example:
```c
t = json_to_key(json, "information", "module", "name");
```
is equivalent to
```c
t = json_to_key(json, "information");
t = json_to_key(t, "module");
t = json_to_key(t, "name");
```
#### JSON Getting Object's Value Type
**Method Prototypes**
```c
#define json_type(json) // Get type
#define json_isnull(json) // Check if it's null type
#define json_isbool(json) // Check if it's boolean type
#define json_isnumber(json) // Check if it's numeric type
#define json_isint(json) // Check if it's integer numeric type
#define json_isfloat(json) // Check if it's floating-point numeric type
#define json_isstring(json) // Check if it's string type
#define json_isarray(json) // Check if it's array type
#define json_isobject(json) // Check if it's object type
```
#### JSON Getting Object's Key and Value
**Method Prototypes**
```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);
```
Before performing operations to get values, it is recommended to first check whether it is the expected type. If operations are performed on incorrect types, it may damage the storage structure of JSON or even cause the program to crash.
#### JSON Creating and Deleting Objects
**Method Prototypes**
```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))
```
These methods can create the basic types of JSON. Arrays and objects can store JSON objects, so by default, empty arrays and empty objects are created. Except for these two, other methods can specify initialization values when creating.
When creating an object and specifying a `key`, if a key is passed in, the created object can be added to an object type. If NULL is passed in, the created object can be added to an array type.
Arrays can store data of any type, but generally, they store data of the same type. Therefore, additional initialization methods are provided for creating arrays.
```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);
```
Initialize data according to C language arrays into JSON arrays.
#### JSON Linking and Unlinking Objects
**Method Prototypes**
```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);
```
The `json_attach` method links a created object to another object according to the index. The value type of the object to be linked must be of array type or object type. It returns the item itself on success and NULL on failure.
The `json_detach` method, in an array or object, matches the specified sub-object according to the same `key` and `index` matching logic as `json_get_child` and unlinks it, returning the sub-object on success and NULL on failure.
Both of these methods do not involve the creation or deletion of objects but only the adjustment of the storage structure. They achieve addition or removal operations by cooperating with other methods.
#### JSON Adding Objects
```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)
```
These methods are formed by combining creation methods and linking methods to add specific types of data to JSON objects of array or object type.
#### JSON Removing Sub-objects
```c
#define json_erase(json, key, index)
#define json_erase_by_index(json, index)
#define json_erase_by_key(json, key)
```
These methods are formed by combining deletion methods and unlinking methods to remove specific sub-objects in arrays or objects.
#### JSON Object Modification
**Method Prototypes**
```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);
```
Modifying an object will overwrite the original content.
#### JSON Object Copying
**Method Prototypes**
```c
json_t json_copy(json_t json);
```
Deep copy a JSON object based on the source JSON object.
#### JSON Parsing Error Reporting
**Method Prototypes**
```c
int json_error_info(int* line, int* column);
```
This JSON parser has a relatively accurate error reporting mechanism. When executing `json_loads`-type loading functions and a null value is returned indicating a parsing error, the `json_error_info` method can be called to view specific error information. The `json_file_load` function already outputs error information internally.
In the parameters, `*line` is the output error line, `*column` is the output error column, and the return value is the error type.
For example, in the following error where there is an extra minus sign in front of `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"
}
}
```
When loading this file, an error occurs, indicating that an error with code 7 occurs near `"true"` at line 8, column 12.
```
Parsing error, code 7 line 8 column 12, near [true].
```
The error types include the following:
```c
#define JSON_E_OK (0) // No error
#define JSON_E_INVALID (1) // Invalid
#define JSON_E_GRAMMAR (2) // Common syntax error
#define JSON_E_END (3) // Extra invalid text at the end of the text
#define JSON_E_KEY (4) // Error occurred when parsing the key
#define JSON_E_VALUE (5) // Error occurred when parsing the value
#define JSON_E_MEMORY (6) // Memory allocation failure
#define JSON_E_NUMBER (7) // Invalid number
#define JSON_E_INDICATOR (8) // Missing indicator ':'
```