New features of Jansson 2.0, part 1
This post starts a series of articles that give insight to the new features of Jansson 2.0.
First up is
the json_unpack()
API. I think it's the most powerful new feature, allowing the user
to perform two things on a JSON value: data extraction, and
validation against a simple schema. The idea has been stolen from
Python's C API.
Example:
/* Assume that obj is the following JSON object: * {"x": 15.4, "y": 99.8, "z": 42}} */ json_t *obj; double x, y, z; if(json_unpack(obj, "{s:f, s:f, s:f}", "x", &x, "y", &y, "z", &z)) return -1; /* error */ assert(x == 15.4 && y == 99.8 && z == 42);
The format string passed to json_unpack()
describes the structure of the object. The s
format
denotes an object key, and the f
format means a real
number value. Whitespace, :
and ,
are
ignored, so {sfsfsf}
would be an equivalent format
string to the one above.
After the format string, there's one argument for each format character. For object keys, a string specifies what key is accessed, and for real numbers, a pointer to double gives an address where to store the value.
The equivalent code without json_unpack()
would be
something like this:
json_t *obj, *tmp; double x, y, x; tmp = json_object_get(obj, "x"); if(!json_is_real(tmp)) return -1; /* error */ x = json_real_value(tmp); /* repeat for y and z */ /* ... */ printf("x: %f, y: %f, z: %f\n", x, y, z); /* ==> x: 15.4, y: 99.8, z: 42 */
The code that uses json_unpack()
is much shorter and
cleaner, and it's easier to see what it's doing.
Nested values are supported, too:
/* Assume that nested is the following JSON object: * {"foo": {"bar": [11, 12, 13]}} */ json_t *nested; int i1, i2, i3; if(json_unpack(nested, "{s:{s:[iii]}}", "foo", "bar", &i1, &i2, &i3)) return -1; /* error */ assert(i1 == 11 && i2 == 12 && i3 == 13);
This time, the format string has two nested objects and a nested array. There's no limit on the nesting levels. The variable arguments are used in the "flat" order in which they appear in the format string.
The same API can also be used in a validation-only mode, i.e. without extracting any values. Error messages are also available:
/* Assume the same JSON object as in the previous example */ json_t *nested; json_error_t error; if(json_unpack_ex(nested, &error, JSON_VALIDATE_ONLY, "{s:{s:[iii]}}", "foo", "bar")) { fprintf(stderr, "Error: %d:%d: %s\n", error.line, error.column, error.text); return -1; }
The json_unpack_ex()
function is the extended version
of json_unpack()
. It takes an error parameter, similar
to decoding functions, and optional flags to control the behaviour.
The JSON_VALIDATE_ONLY
flags tells it to only validate
and not to extract anything. Extra arguments after the format sting
are only required for object keys. The available validation is quite
simple, only the object/array structure and value types can be
checked, but usually this saves a lot of code.
I strongly believe that this feature, along with
the json_pack()
API described in the next part, will
make it an order of magnitude more pleasant to manipulate JSON data
in C. Many thanks to Graeme Smecher for suggesting
this and providing the initial implementation.
This article only gave a few examples. For full details, all available format characters and flags, see the documentation.