19.0.0 released Nov 08, 2023
New json

Purpose: Parse JSON text.

new-json [ define ] <json> from <text> \
    [ length <length> ] \
    [ status [ define ] <status> ] \
    [ error-text [ define ] <error text> ] \
    [ error-position [ define ] <error position> ] \
    [ max-hash-size <max-hash-size> ] \
    [ noencode ] \
    [ no-hash ] \
    [ node-handler <node handler> ]

new-json will parse <text> into <json> variable (a pointer to type "vely_json") which can be created with optional "define".

The length of <text> may be specified with "length" clause in <length> variable, or if not, it will be calculated as the string length of <text>.

The "status" clause specifies the return <status>, which is VV_OKAY if successful or VV_ERR_JSON if there is an error. The number variable <error position> in "error-position" clause is the byte position in <text> where error was found, in which case <error text> in "error-text" clause is the error message. Both can be created with optional "define".

See read-json on obtaining values from JSON document.
No copying
String <text> is modified during parsing for performance reasons. It is parceled out and <json> contains pointers to it that hold the actual primitive values (string, numbers, boolean, null). This way no data is ever copied for faster parsing. If you don't wish <text> to be modified, make a copy of it before parsing it (see copy-string). In many cases though, this is not necessary, allowing for better performance.
Hash table
Hash table is used to provide fast access to any value in JSON text, with the number of lookups being close to 1, which means near-direct memory access. By default, the maximum size of a hash table is limited to 10000. If your JSON document has considerably more values than that, use "max-hash-size" clause to specify the maximum hash table size. Hash table mechanism is the same as used internaly in new-hash.
Encoding
"noencode" clause will not encode strings, i.e. convert from JSON Unicode strings to UTF8 (see read-json), nor will it perform any validity checks on strings. This may be useful as a performance boost, however it is not recommended in general.
Limitations
The maximum depth of nested structures in JSON document (i.e. objects and arrays) is 32, and the maximum length of normalized leaf node name is 1024 (see read-json for more on normalized names). There is no limit on document size.

Duplicate normalized names are valid, however, only one of them is reported, and the very last value encountered is actually stored (the others from duplicate names are discarded).
Creating JSON
To create a JSON document, you can use write-string to programmatically construct one - use utf8-json to create JSON-compatible Unicode string values.
Allocated internals
<json> is allocated memory along with additional internal memory, which can be released if delete-json is used with <json> from a previously executed new-json.
Skip hash building
If you do not need to randomly access nodes in a JSON document, you may skip hash building with "no-hash" clause. In this case read-json will always return VV_ERR_EXIST, i.e. not-found error code, regardless of whether you are using "traverse" clause or not. "no-hash" clause may be useful if you want to just validate JSON document (i.e. find if it has any errors), or if you want to use a node handler to process data in some other way (see "Node processing").
Node processing
You can process JSON leaf nodes as they become available during parsing. To do that, use "node-handler" clause and implement a node handler. A node handler is a function with the following signature:
num my_json_handler (num node_count, json_node *list, char *val, num type);

The data passed to your handler is "node_count", which is the number of nodes in the path leading to a leaf node (inclusive of it), the list of such nodes ("list"), the value of JSON node ("value") and its type ("type") which is one of the aforementioned types (such as VV_JSON_TYPE_STRING for instance). The node structure is:
typedef struct
{
    char *name; // name of node
    num name_len; // length of name of node
    num index; // index of node if array, otherwise -1
} json_node;

In this structure, you can obtain the "name" of each node, its length ("name_len"), and the index of a node in a JSON array of values (if it is an array, otherwise "-1"). Here's an example to specify such a handler for JSON parsing:
new-json define my_json from my_text node-handler my_json_handler

An example implementation of a node handler that displays normalized values may be:
num my_json_handler (num node_count, json_node *list, char *val, num type) {
    num i;
    p-out "Name ["
    // Loop through all nodes that lead to a leaf node
    for (i = 0; i < node_count; i++) {
        char *arr;
        // Check if any given node is an array
        if (list[i].index == -1) arr = "";
        else {
            // if it's an array, construct an index
            pf-out "[%lld]", list[i].index to arr
        }
        // display a node, as "node_name"[index in array] (if part of an array)
        // or just "node_name" (if not part of an array). Add a dot at the end
        // if not the very last (i.e. leaf) node.
        pf-out format i==node_count-1 ? "\"%s\"%s":"\"%s\"%s.", list[i].name, arr
    }
    // display leaf node type and value, and return VV_OKAY (or VV_ERR_JSON to stop processing)
    pf-out "] type [%lld] value [%s]\n", type, val
    return VV_OKAY;
}

The return value from a node handler should be VV_OKAY to continue processing of a JSON document, or VV_ERR_JSON to stop it, in which case the "status" clause in new-json will be VV_ERR_JSON and "error-text" clause will indicate that the user has interrupted the JSON processing. This is useful if you have found all the data you wanted from the document and wish to stop processing.

If you only want to use a node handler to process JSON data (and do not need to use read-json), you should also use "no-hash" clause for maximum performance.
Examples
Parse text "json_text1" and store the result in "json_var" variable, get status, error text and the location of error:
...
new-json json_var from json_text1 status define st error-text errt error-position errp
read-json json_var key "glossary"."title" value d

See also
JSON
delete-json  
new-json  
read-json    
See all
documentation


You are free to copy, redistribute and adapt this web page (even commercially), as long as you give credit and provide a dofollow link back to this page - see full license at CC-BY-4.0. Copyright (c) 2019-2023 Dasoftver LLC. Vely and elephant logo are trademarks of Dasoftver LLC. The software and information on this web site are provided "AS IS" and without any warranties or guarantees of any kind. Icons from table-icons.io copyright Paweł Kuna, licensed under MIT license.