Skip to content

JSON

The Ioto JSON parser is a high performance JSON parser, serializer and query engine.

It parses JSON text into an in-memory tree for efficient examination, storage and export.

Json Features

  • JSON and JSON5 parser
  • Stores parsed JSON as an in-memory tree
  • Fast, flexible query engine mange and navigate the JSON tree
  • Simple get/set API to retrieve and update JSON values.
  • APIs to walk, iterate and navigate a parsed tree
  • Overlay and blend JSON trees
  • Supports JSON/5 with extensions
  • Serialize in strict or JSON/5 formats
  • Persist to flash/disk.

API Quick Tour

To parse a JSON string, call the jsonParse API:

Json *json = jsonParse("{Weather: 'Sunny'}", 0);

This parses the given JSON text and returns a Json instance which represents the in-memory parsed JSON tree.

Note

You can provide JSON or JSON/5 which permits more relaxed JSON format where keys may omit quotes and single quotes can be used on values.

To query a value from the JSON tree, use jsonGet:

cchar *value = jsonGet(json, 0, "weather", NULL);

This will retrieve the weather value (Sunny) as a static string that does not need freeing.

When calling jsonGet, you can provide keys with dots:

cchar *value = jsonGet(json, 0, "address.city", NULL);

and you can provide a default value to be returned as the last parameter if the property is not defined in the JSON tree.

cchar *value = jsonGet(json, 0, "weather", "rainy");

You can use the jsonGetInt and jsonGetBool APIs to return data as an integer or boolean data type.

To update or set a value, use the jsonSet API:

jsonSet(json, 0, "weather", "sunny", 0);

This will update the value of the given property in-memory. Again, you can use dotted key properties of any depth.

Data Types

The last parameter to jsonSet can be used to specify a data type for the value. In general, the Ioto JSON API can sleuth the data type for you. But as data values are supplied as strings, you may need to specify a type if you want the value to be stored as a number.

The valid types are: JSON_OBJECT, JSON_ARRAY, JSON_STRING and JSON_PRIMITIVE. The primitives are false, true, null, undefined and numbers.

To remove a property, use jsonRemove:

jsonRemove(json, 0, "weather");

When you are finished with a JSON tree, free it with jsonFree

jsonFree(json)

This will release allocated memory.

Serialization

To save your in-memory tree as a string, use jsonToString:

char *string = jsonToString(json, 0, 0, 0);

This will save the in-memory tree as JSON/5.

To save in strict JSON, use:

char *string = jsonToString(json, 0, 0, JSON_STRICT);

To save a sub-set of the tree, specify the root node to export:

char *string = jsonToString(json, 0, "address", JSON_STRICT);

This will save all properties under the "address" (including address) property.

Working with Files

You can parse a JSON file with the jsonParseFile API:

Json *json = jsonParseFile("./file.json", NULL, 0);

and you can save the in-memory JSON tree using jsonSave:

jsonSave(json, 0, "data.json", 0644, 0);

Properties in the JSON tree are stored as nodes. These nodes can be identified by a numeric ID or by node reference. Nodes and node IDs are used to very efficiently traverse and enumerate property values.

To get a node ID, use jsonGetId:

int id = jsonGetId(json, 0, "address");

You can retrieve a node using another node as a starting point:

int addressId = jsonGetId(json, 0, "address");
int cityId = jsonGetId(json, addressId, "city");

In fact, most APIs such as jsonGet and jsonSet take a node ID as a parameter that specifies a root of the tree to base the operation. For example, these are equivalent:

1
2
3
4
5
6
int addressId = jsonGetId(json, 0, "address");
int cityId = jsonSet(json, addressId, "city", "Seattle", 0);

// and

jsonGetSet(json, 0, "address.city", "Brisbane", 0);

Similarly, you can retreive a node reference:

JsonNode *node = jsonGetNode(json, "address", "city");

You can iterate over nodes using the ITERATE_JSON macro:

1
2
3
4
5
JsonNode *child;
int id;
for (ITERATE_JSON(json, 0, child, id)) {
    printf("Property %s has value %s\n", child->name, child->value);
}

Under the hood, ITERATE_JSON follows child

Debugging

Use the jsonPrint API to print a JSON tree to the console:

jsonPrint(json);

JSON/5

JSON/5 an extension of JSON that makes it easier to create, read and maintain configuration files in JSON.

JSON/5 adds the following JavaScript features to JSON.

  • Object keys may be JavaScript identifiers without quotes
  • Objects or arrays may have a trailing comma
  • Strings may be single quoted
  • Strings may span multiple lines (single, double or back-tick quotes)
  • Numbers may have a leading or trailing decimal point, be hexadecimal, may begin with a +.
  • Values may be regular expressions
  • Undefined is a valid value
  • Single and multiline comments are allowed and preserved
{
    // single-comment
    /*
        Multi-line comment
    */
    unquotedKey: 42,
    singleQuoteString: 'The "lazy brown fox" jumped...',
    multiLine: "Line one
        line two
    ",
    hex: 0x42,
    trailingComma: {
        one: 1,
        two: 2,
    },
}

Memory References

The JSON engine returns results as static pointers into the in-memory tree. Results are returned as (const char) or (cchar) values and this saves having to duplicate strings. This reduces memory footprint and is much more efficient.

It is important not to cast returned values to (char*) or to modify the referenced strings using "dirty" programming to break the (const char) typing protection.

References

JSON5 Spec