Introduction
Libjansson is a library for C applications to process JSON-encoded messages sent between a client and server application. Some developer use this library to process JSON encoded configuration files as well. JSON (JavaScript Object Notation) is a lightweight data interchange format that is easy for humans to read and for machines to parse. It is popular for transmitting data between a server and a web application as an alternative to XML. In fact, it is so common that developers in most fields have worked with JSON at least once. Libjansson is one of the libraries for C to handle all things JSON.
Refer to official libjansson project page here to learn more.
In this post, we will explore how to parse an input and produce an output in JSON format using libjansson library.
Parse JSON Data
Example JSON to parse
Consider this JSON encoded message:
{ "ver":2, "location":"Vancouver", "devices": [ { "mac":"AABBCCDDEE11", "serial":"1234567811" }, { "mac":"AABBCCDDEE22", "serial":"1234567822" } ], "resources": { "mincpu":1, "maxcpu":2 } }
Obtain the Root of JSON Message
The root
refers to the highest level of JSON hierarchy, which also represents the entire JSON message. You can consider it as “everything within the first pair of curly brackets {}
. For example:
#include <stdio.h> #include "jansson.h" /* assume myjson char * contains the entire JSON encoded message */ int parse_json(const char * myjson) { json_t * root = NULL; json_error_t error; /* load myjson string into json structure called root */ root = json_loads(myjson, 0, &error); if (!root) { /* in case of error, print where the error line number and message */ printf("syntax error in json message: line %d, error %s\n", error.line, error.text); return -1; } /* make sure "root" is an object, so that it can contain more members for further parsing */ if (!json_is_object(root)) { printf("json input is not an object\n"); /* * decrease reference count, which increases as we parse further, but since we have not * done any further parsing yet, calling it will also free the memory of the entire * structure */ json_decref(root); return -1; } }
Parse Integer Data Type
we can modify the “parse_json” function above to parse the rest of members in the json message. Depending on the next expected member type, we will call different json function to parse. For example, to parse an integer value, we use libjansson function json_object_get
to access the member with the name “ver”. Once we have obtained this reference, we use json_is_integer()
and json_integer_value()
to validate and obtain the integer value. For example:
/* let's parse integer value "ver" */ json_t * ver = NULL; ver = json_object_get(root, "ver"); if (ver) { if(!json_is_integer(ver)) { printf("JSON error: 'ver' is not a number\n"); json_decref(root); return -1; } printf("ver = %d\n", json_integer_value(ver)); }
Parse String Data Type
Parsing a string data type is similar to that of an integer. We first use json_object_get()
to access the member with the name “location”. Then, we use libjansson function json_is_string()
and json_string_value()
to validate and obtain the string value. For example:
json_t * location = NULL; /* let's parse string value "location" */ location = json_object_get(root, "location"); if (location) { if(!json_is_string(location)) { printf("JSON error: 'location' is not a string\n"); json_decref(root); return -1; } printf("location = %s\n", json_string_value(location)); }
Parse Array Type
Parsing an array is slightly more complex than a regular integer and string data types, but not by much. Again, we would first use libjansson function json_object_get()
to obtain the reference to “devices” member and call json_is_array()
to make sure it is indeed an array.
To access each member in the array, we can write a simple for loop
iterating from 0 to json_array_size()
and use json_array_get()
to obtain a reference to each array member.
Having a reference to each array member, we can then call the respective libjansson functions to parse based on its data type. In the above example, each array member is of type object
as indicated by the curly brackets
and each object containing 2 string values, “mac” and “serial”. So we can use json_is_string()
and json_string_value()
to access them. For example:
json_t * devices = NULL; json_t * devices_element = NULL; json_t * mac = NULL; json_t * serial = NULL; /* let's parse array object "devices" */ devices = json_object_get(root, "devices"); if (devices) { if(!json_is_array(devices)) { printf("JSON error: 'devices' is not an array\n"); json_decref(root); return -1; } for (i = 0; i < (int)json_array_size(devices); i++) { /* obtain 'devices' object */ devices_element = json_array_get(devices, i); if (!devices_element) { printf("JSON error: 'devices' has no valid element"); continue; } /* let's parse string value "mac" */ mac = json_object_get(devices_element, "mac"); if (mac) { if(!json_is_string(mac)) { printf("JSON error: 'mac' is not a string\n"); continue; } printf("mac = %s\n", json_string_value(mac)); } /* let's parse string value "serial" */ serial = json_object_get(devices_element, "serial"); if (serial) { if(!json_is_string(serial)) { printf("JSON error: 'serial' is not a string\n"); continue; } printf("serial = %s\n", json_string_value(serial)); } } }
Parse Object Type
Parsing an object type is similar to parsing an object type as an array element above. We first call libjansson function json_object_get()
to obtain the reference to the object. Then, based on the data type of each member within the object, we will use the respective function. In the above example, the object named “resources” have 2 integer values “mincpu” and “maxcpu”. We can parse them with this code block:
json_t * resources = NULL; json_t * mincpu = NULL; json_t * maxcpu = NULL; /* let's parse object "resources" */ resources = json_object_get(root, "resources"); if (resources) { if(!json_is_object(resources)) { printf("JSON error: 'resources' is not an object\n"); json_decref(root); return -1; } /* let's parse integer value "mincpu" */ mincpu = json_object_get(resources, "mincpu"); if (mincpu) { if(!json_is_integer(mincpu)) { printf("JSON error: 'mincpu' is not a number\n"); json_decref(root); return -1; } printf("mincpu = %d\n", json_integer_value(mincpu)); } /* let's parse integer value "mincpu" */ maxcpu = json_object_get(resources, "maxcpu"); if (maxcpu) { if(!json_is_integer(maxcpu)) { printf("JSON error: 'maxcpu' is not a number\n"); json_decref(root); return -1; } printf("maxcpu = %d\n", json_integer_value(maxcpu)); } }
Clean Up
After parsing, we will call libjansson function json_decref()
on the root object to release the resource of json parser.
json_decref(root);
Putting it all Together
This is the full parsing code for your reference:
#include <stdio.h> #include "jansson.h" /* assume myjson char * contains the entire JSON encoded message */ int parse_json(const char * myjson) { int i = 0; json_t * root = NULL; json_error_t error; /* json objects */ json_t * ver = NULL; json_t * location = NULL; json_t * devices = NULL; json_t * devices_element = NULL; json_t * mac = NULL; json_t * serial = NULL; json_t * resources = NULL; json_t * mincpu = NULL; json_t * maxcpu = NULL; /* load myjson string into json structure called root */ root = json_loads(myjson, 0, &error); if (!root) { /* in case of error, print where the error line number and message */ printf("syntax error in json message: line %d, error %s\n", error.line, error.text); return -1; } /* make sure "root" is an object, so that it can contain more members for further parsing */ if (!json_is_object(root)) { printf("json input is not an object\n"); /* * decrease reference count, which increases as we parse further, but since we have not * done any further parsing yet, calling it will also free the memory of the entire * structure */ json_decref(root); return -1; } /* let's parse integer value "ver" */ ver = json_object_get(root, "ver"); if (ver) { if(!json_is_integer(ver)) { printf("JSON error: 'ver' is not a number\n"); json_decref(root); return -1; } printf("ver = %d\n", json_integer_value(ver)); } /* let's parse string value "location" */ location = json_object_get(root, "location"); if (location) { if(!json_is_string(location)) { printf("JSON error: 'location' is not a string\n"); json_decref(root); return -1; } printf("location = %s\n", json_string_value(location)); } /* let's parse array object "devices" */ devices = json_object_get(root, "devices"); if (devices) { if(!json_is_array(devices)) { printf("JSON error: 'devices' is not an array\n"); json_decref(root); return -1; } for (i = 0; i < (int)json_array_size(devices); i++) { /* obtain 'devices' object */ devices_element = json_array_get(devices, i); if (!devices_element) { printf("JSON error: 'devices' has no valid element"); continue; } /* let's parse string value "mac" */ mac = json_object_get(devices_element, "mac"); if (mac) { if(!json_is_string(mac)) { printf("JSON error: 'mac' is not a string\n"); continue; } printf("mac = %s\n", json_string_value(mac)); } /* let's parse string value "serial" */ serial = json_object_get(devices_element, "serial"); if (serial) { if(!json_is_string(serial)) { printf("JSON error: 'serial' is not a string\n"); continue; } printf("serial = %s\n", json_string_value(serial)); } } } /* let's parse object "resources" */ resources = json_object_get(root, "resources"); if (resources) { if(!json_is_object(resources)) { printf("JSON error: 'resources' is not an object\n"); json_decref(root); return -1; } /* let's parse integer value "mincpu" */ mincpu = json_object_get(resources, "mincpu"); if (mincpu) { if(!json_is_integer(mincpu)) { printf("JSON error: 'mincpu' is not a number\n"); json_decref(root); return -1; } printf("mincpu = %d\n", json_integer_value(mincpu)); } /* let's parse integer value "mincpu" */ maxcpu = json_object_get(resources, "maxcpu"); if (maxcpu) { if(!json_is_integer(maxcpu)) { printf("JSON error: 'maxcpu' is not a number\n"); json_decref(root); return -1; } printf("maxcpu = %d\n", json_integer_value(maxcpu)); } } json_decref(root); return 0; }
Write JSON Data
libjansson is also capable of producing JSON-encoded, in which we can use to write to a file or send out over network. We will use the same JSON example here but instead of parsing it, we will use the library to create it:
{ "ver":2, "location":"Vancouver", "devices": [ { "mac":"AABBCCDDEE11", "serial":"1234567811" }, { "mac":"AABBCCDDEE22", "serial":"1234567822" } ], "resources": { "mincpu":"0.25", "maxcpu":"2" } }
Create a root Object
Creating a root object to write to is rather simple. We simply call json_object()
to allocate the memory for this structure. All other parameters will be added under this root structure. For example:
#include <stdio.h> #include "jansson.h" /* assume myjson char * contains the entire JSON encoded message */ int create_json(void) { json_t *root = json_object(); if (!root) { printf("JSON error: failed to create root object\n"); } return 0; }
Add Integer and String Member
to add an integer or string member, we can use libjansson’s universal routine json_object_set_new()
to add. For example, this block of code adds an integer value called “ver” under root:
json_object_set_new(root, "ver", json_integer(2));
and this block of code adds a string value called “location” under root:
json_object_set_new(root, "location", json_string("Vancouver"));
so far, we have added 2 values (1 integer and 1 string), we can use libjansson’s json_dumps()
routine to see the JSON structure we have built so far:
printf("%s\n", json_dumps(root, 0));
which should print:
{
"ver":2,
"location":"Vancouver"
}
Add Array Member
Creating an array element in JSON is slightly more complicated than creating regular integer or string values, but not by much. We will have to call json_array()
to allocate memory for building the array then call json_object()
to construct individual elements (one call per element). Based on the data type of the element (in our case, it is object type containing 2 strings), we will call the corresponding functions to add the values. Finally, we will use json_array_append_new()
to add each element to the array and json_object_set_new()
to add the array under root.structure. For example:
json_t * devices = NULL; json_t * devices_elements = NULL; devices = json_array(); /* construct array structure */ if (devices) { devices_elements = json_object(); /* construct array element*/ if (devices_elements) { json_object_set_new(devices_elements, "mac", json_string("AABBCCDDEE11")); json_object_set_new(devices_elements, "serial", json_string("1234567811")); json_array_append_new(devices, devices_elements); /* add elements to array */ } devices_elements = json_object(); if (devices_elements) { json_object_set_new(devices_elements, "mac", json_string("AABBCCDDEE22")); json_object_set_new(devices_elements, "serial", json_string("1234567822")); json_array_append_new(devices, devices_elements); /* add elements to array */ } } json_object_set_new(root, "devices", devices); /* add array to root */
Add Object Member
Adding an object is similar to adding new elements to an array structure. We will use json_object()
to allocate memory for the new object and depending on the data types inside this object, we will call the corresponding functions to construct. For example:
json_t *resources = json_object(); /* create a new object */ json_object_set_new(resources, "mincpu", json_integer(1)); /* add integer value to object */ json_object_set_new(resources, "maxcpu", json_integer(2)); /* add integer value to object */ json_object_set_new(root, "resources", resources); /* add object to root */
Related Reads
- How Not To Exploit The C Loops
- Create Custom Data Types With the C Struct
- Easy Config File Management with libconfig Tutorial in C

Hi, this is Cary, your friendly tech enthusiast, educator and author. Currently working as a software architect at Highgo Software Canada. I enjoy simplifying complex concepts, diving into coding challenges, unraveling the mysteries of software. Most importantly, I like sharing and teaching others about all things tech. Find more blogs from me at highgo.ca