varch/doc/json.en.md

15 KiB

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

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

{
    "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

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

#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:

"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

{
    "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

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

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

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.

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:

t = json_to_key(json, "information", "module", "name");

is equivalent to

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

#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

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

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.

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

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

#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

#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

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

json_t json_copy(json_t json);

Deep copy a JSON object based on the source JSON object.

JSON Parsing Error Reporting

Method Prototypes

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:

{
    "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:

#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 ':'