libjson

All Top-level Files
Login

Files in the top-level directory in any check-in


libjson

libjson is a json parser/generator library for C.

Installation

To use libjson, copy the json.h and json.c files in your project.

You can also clone this repository using fossil to compile the library and play with the examples provided:

$ fossil clone https://foutaise.org/fossil/libjson

Compile libjson:

$ cd libjson
$ make

Documentation

struct json

libjson use a struct json structure to represent any JSON element.

create JSON elements

The following API calls can be used to create JSON elements:

/* create a JSON null */
struct json *json_null(void);

/* create a JSON boolean */
struct json *json_bool(bool);

/* create a JSON number */
struct json *json_nbr(double);

/* create a JSON string */
struct json *json_str(const char *);

/* create an empty JSON array */
struct json *json_arr(void);

/* create an empty JSON object */
struct json *json_obj(void);

JSON arrays methods

Specific methods are available for JSON arrays:

/*
 * add a single child to a JSON array:
 * - if first argument 'array' is NULL, an array is created beforehand.
 * - the JSON array is returned.
 */
struct json *json_arr_add(struct json *array, struct json *child);

/*
 * add multiple childs to a JSON array:
 * - if first argument 'array' is NULL, an array is created beforehand.
 * - variadic arguments must be a succession of (struct json *),
 *   NULL terminated.
 * - the JSON array is returned.
 */
struct json *json_arr_addv(struct json *array, ...);

/*
 * array size (number of elements)
 */
size_t json_arr_size(struct json *array);

So, JSON arrays can be created in two different ways: you can create an empty JSON array then feed the array, using json_arr_add:

struct json *array = json_arr();
for (int i = 1; i < 4; i++)
    json_arr_add(array, json_nbr(i));
assert(json_arr_size(array) == 3);

or you can create and fill a JSON array in one go, using json_arr_addv:

struct json *array = json_arr_addv(NULL,
    json_nbr(1),
    json_nbr(2),
    json_nbr(3),
    NULL);
assert(json_arr_size(array) == 3);

JSON objects methods

Specific methods are available for JSON objects:

/*
 * add a single (key, value) to a JSON object:
 * - if first argument 'object' is NULL, an object is created beforehand.
 * - 'key' must be a valid utf8 string
 * - the JSON object is returned.
 */
struct json *json_obj_add(struct json *object, const char *key, struct json* value);

/*
 * add multiple (key, value) pairs to a JSON object:
 * - if first argument 'object' is NULL, an object is created beforehand.
 * - variadic arguments must be a succession of (key, value) pairs of type
 *   (const char *, struct json *), NULL terminated.
 * - each 'key' must be a valid utf8 string
 * - the JSON object is returned.
 */
struct json *json_obj_addv(struct json *object, ...);

/*
 * object size (number of entries)
 */
size_t json_obj_size(struct json *object);

Like JSON arrays, JSON objects can be created in two different ways: you can create an empty JSON object, then feed it using json_obj_add:

struct json *object = json_obj();
json_obj_add(object, "one", json_nbr(1));
json_obj_add(object, "two", json_nbr(2));
json_obj_add(object, "three", json_nbr(3));
assert(json_obj_size(object) == 3);

or you can create and fill a JSON object in one go, using json_obj_addv:

struct json *object = json_obj_addv(NULL,
    "one", json_nbr(1),
    "two", json_nbr(2),
    "three", json_nbr(3),
    NULL);
assert(json_obj_size(object) == 3);

JSON getters

These are the methods to extract values from an existing JSON element:

/* JSON predicates */
bool json_is_null(struct json *json);
bool json_is_bool(struct json *json);
bool json_is_nbr(struct json *json);
bool json_is_str(struct json *json);
bool json_is_arr(struct json *json);
bool json_is_obj(struct json *json);

/*
 * extract value from JSON element of type boolean:
 * - 'json' argument must be a JSON boolean value
 *   (crash otherwise).
 */
bool json_get_value_bool(struct json *json);

/*
 * extract value from JSON element of type boolean:
 * - return 'dflt' value if 'json' argument is NULL
 *   or isn't a JSON boolean value.
 */
bool json_get_value_bool_dflt(struct json *json, bool dflt);

/*
 * extract value from JSON element of type number:
 * - 'json' argument must be a JSON number value
 *   (crash otherwise).
 */
double json_get_value_nbr(struct json *json);

/*
 * extract value from JSON element of type number:
 * - return 'dflt' value if 'json' argument is NULL
 *   or isn't a JSON number value.
 */
double json_get_value_nbr_dflt(struct json *json, double dflt);

/*
 * extract value from JSON element of type string:
 * - 'json' argument must be a JSON string value
 *   (crash otherwise).
 */
char *json_get_value_str(struct json *json);

/*
 * extract value from JSON element of type string:
 * - return 'dflt' value if 'json' argument is NULL
 *   or isn't a JSON string value.
 */
char *json_get_value_str_dflt(struct json *json, char *dflt);

/*
 * extract JSON element from a JSON array:
 * - 'json' argument must be a JSON array value
 *   (crash otherwise).
 * - 'index' is the 0 based index value of the element to retrieve.
 * - return NULL if index is out of bound.
 */
struct json *json_arr_get(struct json *json, size_t index);

/*
 * extract JSON element from a JSON object:
 * - 'json' argument must be a JSON object value
 *   (crash otherwise).
 * - 'key' of the JSON element to retrieve.
 * - return NULL if no entry found for 'key'.
 */
struct json *json_obj_get(struct json *json, const char *key);

/*
 * extract nested JSON element from a JSON object:
 * - 'json' argument must be a JSON object value
 *   (crash otheriwse)
 * - follows a NULL terminated list of keys,
 *   each key being either:
 *   - a JSON object key
 *     (example "name")
 *   - a JSON array index in format "[<number>]"
 *     (example "[1]")
 * - return NULL if no entry found in the nested
 *   structure
 */
struct json *json_getv(struct json *json, ...);

/*
 * return JSON parent element
 */
struct json *json_parent(struct json *json);

Example of usage:

struct json *object = json_obj_addv(NULL,
    "one", json_nbr(1),
    "two", json_nbr(2),
    "three", json_nbr(3),
    NULL);
assert(json_get_value_nbr(json_obj_get(object, "two")) == 2);

JSON iterator

A specific structure can be used to iterate over JSON elements:

/*
 * JSON iterator to iterate over JSON elements:
 * - an iterator on a JSON element that isn't a JSON array
 *   or a JSON object will return the element itself.
 * - and iterator on a JSON array or JSON object will
 *   return successively each child.
 */
struct json_iter {
    size_t count;
    struct json *parent;
    struct json *current_child;
};

/* create a JSON iterator for a JSON element */
struct json_iter json_iter_init(struct json *);

/* return next JSON element, or NULL when finished */
struct json *json_iter_next(struct json_iter *);

/* return count of elements already returned */
size_t json_iter_count(struct json_iter *iter);

Example of iteration over a JSON array to sum its values:

struct json *array = json_arr_addv(NULL,
    json_nbr(1),
    json_nbr(2),
    json_nbr(3),
    NULL);
struct json_iter iterator = json_iter_init(array);
struct json *element;
double sum = 0;
while ((element = json_iter_next(&iterator)) != NULL)
    sum += json_get_value_nbr(element);
assert(sum == 6);

Rendering JSON elements

The following API calls can be used to render a JSON element, either to a string or to stdout:

/* render JSON element to a new malloc() string */
char *json_render(struct json *);

/* pretty rendering of JSON element to a new malloc() string */
char *json_render_pretty(struct json *);

/* print JSON element to stdout */
void json_print(struct json *);

/* pretty printing of JSON element to stdout */
void json_print_pretty(struct json *);

The following code:

struct json *object = json_obj_addv(NULL,
    "one", json_nbr(1),
    "two", json_nbr(2),
    "three", json_nbr(3),
    NULL);
json_print_pretty(object);

would display this output:

{
  "one": 1,
  "two": 2,
  "three": 3
}

JSON parsing

The following API calls are avaiblable to parse JSON data:

struct json_parser;

/* create a new JSON parser */
struct json_parser* json_parser_new(void);

/*
 * parse a JSON string:
 * - NULL is returned in case of parsing error
 */
struct json *json_parser_parse_str(struct json_parser *parser, const char *str);

/*
 * parse a JSON file:
 * - NULL is returned in case of parsing error
 */
struct json *json_parser_parse_file(struct json_parser *parser, const char *filename);

/* fetch error string in case of parsing error */
char *json_parser_error_msg(struct json_parser *parser);

/* free JSON parser structure */
void json_parser_free(struct json_parser *parser);

/*
 * Convenient functions to quickly parse a JSON string or file,
 * without the need to instantiate and free a JSON parser:
 * - return NULL in case of parsing error.
 * - no possiblity to get an error string in case of parsing error.
 */
struct json *json_parse_str(const char *str);
struct json *json_parse_file(const char *filename);

Example of parsing a JSON string using a parser:

struct json_parser *parser = json_parser_new();
struct json *object = json_parser_parse_str(parser, "{\"name\" : \"bobby\"}");
if (object == NULL) {
    warnx("%s", json_parser_error_msg(parser));
} else {
    json_print_pretty(object);
    json_free(object);
}
json_parser_free(parser);

Same example using json_parse_str (no need to instantiate a parser):

struct json *object = json_parse_str("{\"name\" : \"bobby\"}");
if (object == NULL) {
    warnx("invalid json input");
} else {
    json_print_pretty(object);
    json_free(object);
}

Parsing of a JSON file:

struct json *json = json_parse_file("file.json");

Free JSON elements

Memory used by a JSON element can be released using json_free:

/*
 * free json element
 */
void json_free(struct json *);

Example

See the examples directory for several examples of libjson usage.