mirror of
https://github.com/DaveGamble/cJSON.git
synced 2023-08-10 21:13:26 +03:00
README: Reformat
This commit is contained in:
parent
778bcd1a62
commit
501be02690
250
README.md
250
README.md
@ -1,27 +1,40 @@
|
||||
# cJSON
|
||||
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
Ultralightweight JSON parser in ANSI C.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
## Table of contents
|
||||
* [License](#license)
|
||||
* [Usage](#usage)
|
||||
* [Welcome to cJSON](#welcome-to-cjson)
|
||||
* [Some JSON](#some-json)
|
||||
* [Here's the structure](#heres-the-structure)
|
||||
* [Enjoy cJSON!](#enjoy-cjson)
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
## License
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
> Copyright (c) 2009-2016 Dave Gamble
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files (the "Software"), to deal
|
||||
> in the Software without restriction, including without limitation the rights
|
||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
> copies of the Software, and to permit persons to whom the Software is
|
||||
> furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in
|
||||
> all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
> THE SOFTWARE.
|
||||
|
||||
## Usage
|
||||
|
||||
Welcome to cJSON.
|
||||
-----------------
|
||||
### Welcome to cJSON.
|
||||
|
||||
cJSON aims to be the dumbest possible parser that you can get your job done with.
|
||||
It's a single file of C, and a single header file.
|
||||
@ -34,8 +47,10 @@ First up, how do I build?
|
||||
Add cJSON.c to your project, and put cJSON.h somewhere in the header search path.
|
||||
For example, to build the test app:
|
||||
|
||||
gcc cJSON.c test.c -o test -lm
|
||||
./test
|
||||
```
|
||||
gcc cJSON.c test.c -o test -lm
|
||||
./test
|
||||
```
|
||||
|
||||
As a library, cJSON exists to take away as much legwork as it can, but not get in your way.
|
||||
As a point of pragmatism (i.e. ignoring the truth), I'm going to say that you can use it
|
||||
@ -45,56 +60,69 @@ I lifted some JSON from this page: http://www.json.org/fatfree.html
|
||||
That page inspired me to write cJSON, which is a parser that tries to share the same
|
||||
philosophy as JSON itself. Simple, dumb, out of the way.
|
||||
|
||||
Some JSON:
|
||||
----------
|
||||
### Some JSON:
|
||||
|
||||
{
|
||||
"name": "Jack (\"Bee\") Nimble",
|
||||
"format": {
|
||||
"type": "rect",
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"interlace": false,
|
||||
"frame rate": 24
|
||||
}
|
||||
```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:
|
||||
|
||||
cJSON * root = cJSON_Parse(my_json_string);
|
||||
```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?
|
||||
|
||||
cJSON * format = cJSON_GetObjectItem(root,"format");
|
||||
int framerate = cJSON_GetObjectItem(format,"frame rate")->valueint;
|
||||
```c
|
||||
cJSON * format = cJSON_GetObjectItem(root,"format");
|
||||
int framerate = cJSON_GetObjectItem(format,"frame rate")->valueint;
|
||||
```
|
||||
|
||||
Want to change the framerate?
|
||||
|
||||
cJSON_GetObjectItem(format,"frame rate")->valueint = 25;
|
||||
```c
|
||||
cJSON_GetObjectItem(format,"frame rate")->valueint = 25;
|
||||
```
|
||||
|
||||
Back to disk?
|
||||
|
||||
char * rendered = cJSON_Print(root);
|
||||
```c
|
||||
char * rendered = cJSON_Print(root);
|
||||
```
|
||||
|
||||
Finished? Delete the root (this takes care of everything else).
|
||||
|
||||
cJSON_Delete(root);
|
||||
```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?
|
||||
|
||||
cJSON *root,*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);
|
||||
```c
|
||||
cJSON *root,*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 site, and
|
||||
@ -114,21 +142,22 @@ 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:
|
||||
---------------------
|
||||
# Here's the structure:
|
||||
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next,*prev;
|
||||
struct cJSON *child;
|
||||
```c
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next,*prev;
|
||||
struct cJSON *child;
|
||||
|
||||
int type;
|
||||
int type;
|
||||
|
||||
char *valuestring;
|
||||
int valueint;
|
||||
double valuedouble;
|
||||
char *valuestring;
|
||||
int valueint;
|
||||
double valuedouble;
|
||||
|
||||
char *string;
|
||||
} cJSON;
|
||||
char *string;
|
||||
} cJSON;
|
||||
```
|
||||
|
||||
By default all values are 0 unless set by virtue of being meaningful.
|
||||
|
||||
@ -152,23 +181,26 @@ 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):
|
||||
|
||||
void parse_and_callback(cJSON *item,const char *prefix)
|
||||
{
|
||||
while (item)
|
||||
{
|
||||
char *newprefix = malloc(strlen(prefix) + strlen(item->name) + 2);
|
||||
sprintf(newprefix,"%s/%s",prefix,item->name);
|
||||
int dorecurse = callback(newprefix, item->type, item);
|
||||
if (item->child && dorecurse) parse_and_callback(item->child, newprefix);
|
||||
item = item->next;
|
||||
free(newprefix);
|
||||
}
|
||||
}
|
||||
```c
|
||||
void parse_and_callback(cJSON *item,const char *prefix)
|
||||
{
|
||||
while (item)
|
||||
{
|
||||
char *newprefix = malloc(strlen(prefix) + strlen(item->name) + 2);
|
||||
sprintf(newprefix,"%s/%s",prefix,item->name);
|
||||
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 */ }
|
||||
@ -179,33 +211,38 @@ let you invoke it per-item. For the item above, your callback might look like th
|
||||
else if (!strcmp(name,"format/frame rate") { /* 24 */ }
|
||||
return 1;
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, you might like to parse iteratively.
|
||||
You'd use:
|
||||
|
||||
void parse_object(cJSON *item)
|
||||
{
|
||||
int i;
|
||||
for (i = 0 ; i < cJSON_GetArraySize(item) ; i++)
|
||||
{
|
||||
cJSON * subitem = cJSON_GetArrayItem(item, i);
|
||||
// handle subitem.
|
||||
}
|
||||
}
|
||||
```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:
|
||||
|
||||
void parse_object(cJSON * item)
|
||||
{
|
||||
cJSON *subitem = item->child;
|
||||
while (subitem)
|
||||
{
|
||||
// handle subitem
|
||||
if (subitem->child) parse_object(subitem->child);
|
||||
|
||||
subitem = subitem->next;
|
||||
}
|
||||
}
|
||||
```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.
|
||||
@ -218,22 +255,24 @@ 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?
|
||||
|
||||
cJSON * objects[24];
|
||||
```c
|
||||
cJSON * objects[24];
|
||||
|
||||
cJSON * Create_array_of_anything(cJSON ** items, int num)
|
||||
{
|
||||
int i;
|
||||
cJSON * prev, * 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 * Create_array_of_anything(cJSON ** items, int num)
|
||||
{
|
||||
int i;
|
||||
cJSON * prev, * 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
|
||||
@ -245,7 +284,6 @@ 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,
|
||||
which are more complex than I'd care to try and stash into a const char array[].
|
||||
|
||||
Enjoy cJSON!
|
||||
-----------------------
|
||||
# Enjoy cJSON!
|
||||
|
||||
- Dave Gamble, Aug 2009
|
||||
|
Loading…
Reference in New Issue
Block a user