An easy to use, very fast JSON parsing implementation written in pure C
result
type used throughout fallible calls-DJSON_SKIP_WHITESPACE
to parse non-minified JSON with whitespace in betweenCopy the following from this repository in your source
json.h
json.c
And in your code
#include "json.h"
typed
helperA uniform type system used throughout the API
typed(x)
is alias for x_t
typed(json_element) // json_element_t
result
A tagged union comprising two variants, either ok
with the data or err
with typed(json_error)
with simplified API to manage variants
result(json_element) // json_element_result_t
result(json_element) json_parse(typed(json_string) json_str);
result(json_element) json_object_find(typed(json_object) * object, typed(json_string) key);
void json_print(typed(json_element) *element, int indent);
void json_free(typed(json_element) *element);
typed(json_string) json_error_to_string(typed(json_error) error);
A null-terminated char-sequence
typed(json_string) // alias for const char *
A 64-bit floating point number
typed(json_number) // alias for double
An array of key-value entries
typed(json_object)
Name | Type | Description |
---|---|---|
count |
typed(size) |
The number of entries |
entries |
typed(json_entry) * |
The array of entries |
A hetergeneous array of elements
typed(json_array)
Name | Type | Description |
---|---|---|
count |
typed(size) |
The number of elements |
elements |
typed(json_element) * |
The array of elements |
A boolean value
typed(json_boolean)
A tagged union representing a JSON value with its type
typed(json_element)
Name | Type | Description |
---|---|---|
type |
typed(json_element_type) |
The type of the value |
value |
typed(json_element_value) |
The actual value |
An enum which represents a JSON type
typed(json_element_type)
Variant | Description |
---|---|
JSON_ELEMENT_TYPE_STRING |
JSON String |
JSON_ELEMENT_TYPE_NUMBER |
JSON Number |
JSON_ELEMENT_TYPE_OBJECT |
JSON Object |
JSON_ELEMENT_TYPE_ARRAY |
JSON Array |
JSON_ELEMENT_TYPE_BOOLEAN |
JSON Boolean |
JSON_ELEMENT_TYPE_NULL |
JSON Null |
A union for interpreting JSON data
typed(json_element_value)
Name | Type | Interpret data as |
---|---|---|
as_string |
typed(json_string) |
JSON String |
as_number |
typed(json_number) |
JSON Number |
as_object |
typed(json_object) * |
JSON Object |
as_array |
typed(json_array) * |
JSON Array |
as_boolean |
typed(json_boolean) |
JSON Boolean |
An enum which represents an error
typed(json_error)
Variant | Description |
---|---|
JSON_ERROR_EMPTY |
Null or empty value |
JSON_ERROR_INVALID_TYPE |
Type inference failed |
JSON_ERROR_INVALID_KEY |
Key is not a valid string |
JSON_ERROR_INVALID_VALUE |
Value is not a valid JSON type |
#include "json.h"
const char * some_json_str = "{\"hello\":\"world\",\"key\":\"value\"}";
int main() {
result(json_element) element_result = json_parse(some_json_str);
// Guard if
if(result_is_err(json_element)(&element_result)) {
typed(json_error) error = result_unwrap_err(json_element)(&element_result);
fprintf(stderr, "Error parsing JSON: %s\n", json_error_to_string(error));
return -1;
}
// Extract the data
typed(json_element) element = result_unwrap(json_element)(&element_result);
// Fetch the "hello" key value
result(json_element) hello_element_result = json_object_find(element.value.as_object, "hello");
if(result_is_err(json_element)(&hello_element_result)) {
typed(json_error) error = result_unwrap_err(json_element)(&hello_element_result);
fprintf(stderr, "Error getting element \"hello\": %s\n", json_error_to_string(error));
return -1;
}
typed(json_element) hello_element = result_unwrap(json_element)(&hello_element_result);
// Use the element
printf("\"hello\": \"%s\"\n", hello_element.value.as_string);
json_print(&element, 2);
json_free(&element);
return 0;
}
Outputs
"hello": "world"
{
"hello": "world",
"key": "value"
}
git clone https://github.com/forkachild/C-Simple-JSON-Parser
clang example.c json.c -o example.out
./example.out
At each Key-Value pair typed(json_entry_t)
, there is a member type
#include "json.h"
...
typed(json_element) element = ...; // See example above
typed(json_entry) entry = element.value.as_object->entries[0];
switch(entry.element.type) {
case JSON_TYPE_STRING:
// `entry.element.value.as_string` is a `json_string_t`
break;
case JSON_TYPE_NUMBER:
// `entry.element.value.as_number` is a `json_number_t`
break;
case JSON_TYPE_OBJECT:
// `entry.element.value.as_object` is a `json_object_t *`
break;
case JSON_TYPE_ARRAY:
// `entry.element.value.as_array` is a `json_array_t *`
break;
case JSON_TYPE_BOOLEAN:
// `entry.element.value.as_boolean` is a `json_boolean_t`
break;
}
In each typed(json_object)
, there is a member count
#include "json.h"
...
int i;
typed(json_element) element = ...; // See example above
typed(json_object) *obj = element.value.as_object;
for(i = 0; i < obj->count; i++) {
typed(json_entry) entry = obj->entries[i];
typed(json_string) key = entry.key;
typed(json_element_type) type = entry.element.type;
typed(json_element_value) value = entry.element.value;
// Do something with `key`, `type` and `value`
}
In each typed(json_array)
, there is a member count
#include "json.h"
...
int i;
typed(json_element) element = ...; // See example above
typed(json_array) *arr = element.value.as_array;
for(i = 0; i < arr->count; i++) {
typed(json_element) element = arr->elements[i];
typed(json_element_type) type = element.type;
typed(json_element_value) value = element.value;
// Do something with `value`
}
Compile using -DJSON_SKIP_WHITESPACE