From 5605fa4ad5d1a162e14fcb5bbab8a90b1b4803ce Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 30 Dec 2017 01:54:27 +0100 Subject: [PATCH] README: new doc: Remove old explanation. --- README.md | 271 +----------------------------------------------------- 1 file changed, 3 insertions(+), 268 deletions(-) diff --git a/README.md b/README.md index 8435e1e..aa345e7 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,6 @@ Ultralightweight JSON parser in ANSI C. * [Parsing JSON](#parsing-json) * [Printing JSON](#printing-json) * [Example](#example) - * [Some JSON](#some-json) - * [Here's the structure](#heres-the-structure) * [Caveats](#caveats) * [Enjoy cJSON!](#enjoy-cjson) @@ -463,270 +461,6 @@ end: Note that there are no NULL checks except for the result of `cJSON_Parse` because `cJSON_GetObjectItemCaseSensitive` checks for `NULL` inputs already, so a `NULL` value is just propagated and `cJSON_IsNumber` and `cJSON_IsString` return `0` if the input is `NULL`. -### Some JSON: - -```json -{ - "name": "Jack (\"Bee\") Nimble", - "format": { - "type": "rect", - "width": 1920, - "height": 1080, - "interlace": false, - "frame rate": 24 - } -} -``` - -Assume that you got this from a file, a webserver, or magic JSON elves, whatever, -you have a `char *` to it. Everything is a `cJSON` struct. -Get it parsed: - -```c -cJSON * root = cJSON_Parse(my_json_string); -``` - -This is an object. We're in C. We don't have objects. But we do have structs. -What's the framerate? - -```c -cJSON *format = cJSON_GetObjectItemCaseSensitive(root, "format"); -cJSON *framerate_item = cJSON_GetObjectItemCaseSensitive(format, "frame rate"); -double framerate = 0; -if (cJSON_IsNumber(framerate_item)) -{ - framerate = framerate_item->valuedouble; -} -``` - -Want to change the framerate? - -```c -cJSON *framerate_item = cJSON_GetObjectItemCaseSensitive(format, "frame rate"); -cJSON_SetNumberValue(framerate_item, 25); -``` - -Back to disk? - -```c -char *rendered = cJSON_Print(root); -``` - -Finished? Delete the root (this takes care of everything else). - -```c -cJSON_Delete(root); -``` - -That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers -before you dereference them. If you want to see how you'd build this struct in code? - -```c -cJSON *root; -cJSON *fmt; -root = cJSON_CreateObject(); -cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); -cJSON_AddItemToObject(root, "format", fmt = cJSON_CreateObject()); -cJSON_AddStringToObject(fmt, "type", "rect"); -cJSON_AddNumberToObject(fmt, "width", 1920); -cJSON_AddNumberToObject(fmt, "height", 1080); -cJSON_AddFalseToObject (fmt, "interlace"); -cJSON_AddNumberToObject(fmt, "frame rate", 24); -``` - -Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup. -Look at `test.c` for a bunch of nice examples, mostly all ripped off the [json.org](http://json.org) site, and -a few from elsewhere. - -What about manual mode? First up you need some detail. -Let's cover how the `cJSON` objects represent the JSON data. -cJSON doesn't distinguish arrays from objects in handling; just type. -Each `cJSON` has, potentially, a child, siblings, value, a name. - -* The `root` object has: *Object* Type and a Child -* The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling: -* Sibling has type *Object*, name "format", and a child. -* That child has type *String*, name "type", value "rect", and a sibling: -* Sibling has type *Number*, name "width", value 1920, and a sibling: -* Sibling has type *Number*, name "height", value 1080, and a sibling: -* Sibling has type *False*, name "interlace", and a sibling: -* Sibling has type *Number*, name "frame rate", value 24 - -### Here's the structure: - -```c -typedef struct cJSON { - struct cJSON *next,*prev; - struct cJSON *child; - - int type; - - char *valuestring; - int valueint; /* writing to valueint is DEPRECATED, please use cJSON_SetNumberValue instead */ - double valuedouble; - - char *string; -} cJSON; -``` - -By default all values are 0 unless set by virtue of being meaningful. - -`next`/`prev` is a doubly linked list of siblings. `next` takes you to your sibling, -`prev` takes you back from your sibling to you. -Only objects and arrays have a `child`, and it's the head of the doubly linked list. -A `child` entry will have `prev == 0`, but next potentially points on. The last sibling has `next == 0`. -The type expresses *Null*/*True*/*False*/*Number*/*String*/*Array*/*Object*, all of which are `#defined` in -`cJSON.h`. - -A *Number* has `valueint` and `valuedouble`. `valueint` is a relict of the past, so always use `valuedouble`. - -Any entry which is in the linked list which is the child of an object will have a `string` -which is the "name" of the entry. When I said "name" in the above example, that's `string`. -`string` is the JSON name for the 'variable name' if you will. - -Now you can trivially walk the lists, recursively, and parse as you please. -You can invoke `cJSON_Parse` to get cJSON to parse for you, and then you can take -the root object, and traverse the structure (which is, formally, an N-tree), -and tokenise as you please. If you wanted to build a callback style parser, this is how -you'd do it (just an example, since these things are very specific): - -```c -void parse_and_callback(cJSON *item, const char *prefix) -{ - while (item) - { - char *newprefix = malloc(strlen(prefix) + strlen(item->string) + 2); - sprintf(newprefix, "%s/%s", prefix, item->string); - int dorecurse = callback(newprefix, item->type, item); - if (item->child && dorecurse) - { - parse_and_callback(item->child, newprefix); - } - item = item->next; - free(newprefix); - } -} -``` - -The `prefix` process will build you a separated list, to simplify your callback handling. -The `dorecurse` flag would let the callback decide to handle sub-arrays on it's own, or -let you invoke it per-item. For the item above, your callback might look like this: - -```c -int callback(const char *name, int type, cJSON *item) -{ - if (!strcmp(name, "name")) - { - /* populate name */ - } - else if (!strcmp(name, "format/type")) - { - /* handle "rect" */ } - else if (!strcmp(name, "format/width")) - { - /* 800 */ - } - else if (!strcmp(name, "format/height")) - { - /* 600 */ - } - else if (!strcmp(name, "format/interlace")) - { - /* false */ - } - else if (!strcmp(name, "format/frame rate")) - { - /* 24 */ - } - - return 1; -} -``` - -Alternatively, you might like to parse iteratively. -You'd use: - -```c -void parse_object(cJSON *item) -{ - int i; - for (i = 0; i < cJSON_GetArraySize(item); i++) - { - cJSON *subitem = cJSON_GetArrayItem(item, i); - // handle subitem - } -} -``` - -Or, for PROPER manual mode: - -```c -void parse_object(cJSON *item) -{ - cJSON *subitem = item->child; - while (subitem) - { - // handle subitem - if (subitem->child) - { - parse_object(subitem->child); - } - - subitem = subitem->next; - } -} -``` - -Of course, this should look familiar, since this is just a stripped-down version -of the callback-parser. - -This should cover most uses you'll find for parsing. The rest should be possible -to infer.. and if in doubt, read the source! There's not a lot of it! ;) - -In terms of constructing JSON data, the example code above is the right way to do it. -You can, of course, hand your sub-objects to other functions to populate. -Also, if you find a use for it, you can manually build the objects. -For instance, suppose you wanted to build an array of objects? - -```c -cJSON *objects[24]; - -cJSON *Create_array_of_anything(cJSON **items, int num) -{ - int i; - cJSON *prev; - cJSON *root = cJSON_CreateArray(); - for (i = 0; i < 24; i++) - { - if (!i) - { - root->child = objects[i]; - } - else - { - prev->next = objects[i]; - objects[i]->prev = prev; - } - - prev = objects[i]; - } - - return root; -} -``` - -and simply: `Create_array_of_anything(objects, 24);` - -cJSON doesn't make any assumptions about what order you create things in. -You can attach the objects, as above, and later add children to each -of those objects. - -As soon as you call `cJSON_Print`, it renders the structure to text. - -The `test.c` code shows how to handle a bunch of typical cases. If you uncomment -the code, it'll load, parse and print a bunch of test files, also from [json.org](http://json.org), -which are more complex than I'd care to try and stash into a `const char array[]`. - ### Caveats #### Zero Character @@ -768,5 +502,6 @@ When cJSON was originally created, it didn't follow the JSON standard and didn't # Enjoy cJSON! -- Dave Gamble, Aug 2009 -- [cJSON contributors](CONTRIBUTORS.md) +- Dave Gamble (original author) +- Max Bruckner (current maintainer) +- and the other [cJSON contributors](CONTRIBUTORS.md)