1. Yaroslav Stavnichiy
  2. nxjson


NXJSON ================================ Very small JSON parser written in C. ##Features - Parses JSON from null-terminated string - Easy to use tree traversal API - Allows // line and /\* block \*/ comments (except before colon ':') - Operates on single-byte or multi-byte characters (like UTF-8), but not on wide characters - Unescapes string values (including Unicode codepoints & surrogates) - Can use custom Unicode encoder, UTF-8 encoder built in - Can use custom memory allocator - Can use custom macro to print errors - Test suite included ## Limitations - Non-validating parser; might accept invalid JSON (eg., extra or missing commas, comments, octal or hex numeric values, etc.) ## API Parsed JSON tree consists of nodes. Each node has type: typedef enum nx_json_type { NX_JSON_NULL, // this is null value NX_JSON_OBJECT, // this is an object; properties can be found in child nodes NX_JSON_ARRAY, // this is an array; items can be found in child nodes NX_JSON_STRING, // this is a string; value can be found in text_value field NX_JSON_INTEGER, // this is an integer; value can be found in int_value field NX_JSON_DOUBLE, // this is a double; value can be found in dbl_value field NX_JSON_BOOL // this is a boolean; value can be found in int_value field } nx_json_type; The node itself: typedef struct nx_json { nx_json_type type; // type of json node, see above const char* key; // key of the property; for object's children only const char* text_value; // text value of STRING node long int_value; // the value of INTEGER or BOOL node double dbl_value; // the value of DOUBLE node int length; // number of children of OBJECT or ARRAY nx_json* child; // points to first child nx_json* next; // points to next child } nx_json; #### Parsing const nx_json* nx_json_parse(char* text, nx_json_unicode_encoder encoder); Parses null-terminated string `text` into `nx_json` tree structure. The string is **modified in place**. Parsing ends right after retrieving first valid JSON value. Remainder of the text is not analysed. Returns `NULL` on syntax error. Error details are printed out using user-redefinable macro `NX_JSON_REPORT_ERROR(msg, ptr)`. Inside parse function `nx_json` nodes get allocated using user-redefinable macro `NX_JSON_CALLOC()` and freed by `NX_JSON_FREE(json)`. All `text_value` pointers refer to the content of original `text` string, which is modified in place to unescape and null-terminate JSON string literals. `encoder` is a function defined as follows: int unicode_to_my_encoding(unsigned int codepoint, char* p, char** endp) { ... } Encoder takes Unicode codepoint and writes corresponding encoded value into buffer pointed by `p`. It should store pointer to the end of encoded value into `*endp`. The function should return 1 on success and 0 on error. Number of bytes written must not exceed 6. NXJSON includes sample encoder `nx_json_unicode_to_utf8`, which converts all `\uXXXX` escapes into UTF-8 sequences. In case `encoder` parameter is `NULL` all unicode escape sequences (`\uXXXX`) are ignored (remain untouched). const nx_json* nx_json_parse_utf8(char* text); This is shortcut for `nx_json_parse(text, nx_json_unicode_to_utf8)` where `nx_json_unicode_to_utf8` is unicode to UTF-8 encoder provided by NXJSON. void nx_json_free(const nx_json* js); Frees resources (`nx_json` nodes) allocated by `nx_json_parse()`. #### Traversal const nx_json* nx_json_get(const nx_json* json, const char* key); Gets object's property by key. If `json` points to `OBJECT` node returns first the object's property identified by key `key`. If there is no such property returns *dummy* node of type `NX_JSON_NULL`. Never returns literal `NULL`. const nx_json* nx_json_item(const nx_json* json, int idx); Gets array's item by its index. If `json` points to `ARRAY` node returns array's element identified by index `idx`. If `json` points to `OBJECT` node returns object's property identified by index `idx`. If there is no such item/property returns *dummy* node of type `NX_JSON_NULL`. Never returns literal `NULL`. ## Usage Example JSON code: { "some-int": 195, "array": [ 3, 5.1, -7, "nine", /*11*/ ], "some-bool": true, "some-dbl": -1e-4, "some-null": null, "hello": "world!", //"other": "/OTHER/", "obj": {"KEY": "VAL"} } C API: const nx_json* json=nx_json_parse(code, 0); if (json) { printf("some-int=%ld\n", nx_json_get(json, "some-int")->int_value); printf("some-dbl=%lf\n", nx_json_get(json, "some-dbl")->dbl_value); printf("some-bool=%s\n", nx_json_get(json, "some-bool")->int_value? "true":"false"); printf("some-null=%s\n", nx_json_get(json, "some-null")->text_value); printf("hello=%s\n", nx_json_get(json, "hello")->text_value); printf("other=%s\n", nx_json_get(json, "other")->text_value); printf("KEY=%s\n", nx_json_get(nx_json_get(json, "obj"), "KEY")->text_value); const nx_json* arr=nx_json_get(json, "array"); int i; for (i=0; i<arr->length; i++) { const nx_json* item=nx_json_item(arr, i); printf("arr[%d]=(%d) %ld %lf %s\n", i, (int)item->type, item->int_value, item->dbl_value, item->text_value); } nx_json_free(json); } ##License LGPL v3 ##Copyright Copyright (c) 2013 Yaroslav Stavnichiy <yarosla@gmail.com>