How to parse a small JSON file with jsmn on an embedded system?
jsmn will give you a set of tokens referring to the tokens in your JSON reading left to right.
In your case:
token[0]: (outer) object, 2 childrentoken[1]: string token ("data1")token[2]: array, 9 childrentoken[3]: primitive token (1)etc...
The basic code to do the parsing is:
int resultCode;jsmn_parser p;jsmntok_t tokens[128]; // a number >= total number of tokensjsmn_init(&p);resultCode = jsmn_parse(&p, yourJson, tokens, 256);
The other trick is getting the value of a token. The token contains the start and end points of the data on your original string.
jsmntok_t key = tokens[1];unsigned int length = key.end - key.start;char keyString[length + 1]; memcpy(keyString, &yourJson[key.start], length);keyString[length] = '\0';printf("Key: %s\n", keyString);
With that you should be able to figure you how to iterate through your data.
I was curious as about this as well, so I made a small program to show the structure of the tokens array:
This program:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include "jsmn.h"jsmntok_t t[512];char jsonStr[512*1024];int main(){ size_t pos = 0; int c; while ((c = getchar()) != EOF) { jsonStr[pos] = c; ++pos; if (pos == sizeof(jsonStr)) break; } jsonStr[pos] = 0; jsmn_parser p; jsmn_init(&p); int tCount = jsmn_parse(&p, jsonStr, strlen(jsonStr), t, sizeof(t)/sizeof(*t)); for (int i = 0; i != tCount; ++i) { jsmntok_t *token = t + i; char * type = 0; switch (token->type) { case JSMN_PRIMITIVE: type = "PRIMITIVE"; break; case JSMN_OBJECT: type = "OBJECT"; break; case JSMN_ARRAY: type = "ARRAY"; break; case JSMN_STRING: type = "STRING"; break; default: type = "UNDEF"; }#ifdef JSMN_PARENT_LINKS printf("node: %4d, %9s, parent: %4d, children: %5d, data:\n%.*s, \n", i, type, token->parent, token->size, token->end-token->start, jsonStr+token->start);#else printf("node: %4d, %9s, children: %5d, data:\n%.*s, \n", i, type, token->size, token->end-token->start, jsonStr+token->start);#endif }}
prints this json (taken from: https://en.wikipedia.org/wiki/JSON):
{ "firstName": "John", "lastName": "Smith", "isAlive": true, "age": 25, "address": { "streetAddress": "21 2nd Street", "city": "New York", "state": "NY", "postalCode": "10021-3100" }, "phoneNumbers": [ { "type": "home", "number": "212 555-1234" }, { "type": "office", "number": "646 555-4567" }, { "type": "mobile", "number": "123 456-7890" } ], "children": [], "spouse": null}
as:
node: 0, OBJECT, parent: -1, children: 8, data:{ "firstName": "John", "lastName": "Smith", "isAlive": true, "age": 25, "address": { "streetAddress": "21 2nd Street", "city": "New York", "state": "NY", "postalCode": "10021-3100" }, "phoneNumbers": [ { "type": "home", "number": "212 555-1234" }, { "type": "office", "number": "646 555-4567" }, { "type": "mobile", "number": "123 456-7890" } ], "children": [], "spouse": null},node: 1, STRING, parent: 0, children: 1, data:firstName,node: 2, STRING, parent: 1, children: 0, data:John,node: 3, STRING, parent: 0, children: 1, data:lastName,node: 4, STRING, parent: 3, children: 0, data:Smith,node: 5, STRING, parent: 0, children: 1, data:isAlive,node: 6, PRIMITIVE, parent: 5, children: 0, data:true,node: 7, STRING, parent: 0, children: 1, data:age,node: 8, PRIMITIVE, parent: 7, children: 0, data:25,node: 9, STRING, parent: 0, children: 1, data:address,node: 10, OBJECT, parent: 9, children: 4, data:{ "streetAddress": "21 2nd Street", "city": "New York", "state": "NY", "postalCode": "10021-3100" },node: 11, STRING, parent: 10, children: 1, data:streetAddress,node: 12, STRING, parent: 11, children: 0, data:21 2nd Street,node: 13, STRING, parent: 10, children: 1, data:city,node: 14, STRING, parent: 13, children: 0, data:New York,node: 15, STRING, parent: 10, children: 1, data:state,node: 16, STRING, parent: 15, children: 0, data:NY,node: 17, STRING, parent: 10, children: 1, data:postalCode,node: 18, STRING, parent: 17, children: 0, data:10021-3100,node: 19, STRING, parent: 0, children: 1, data:phoneNumbers,node: 20, ARRAY, parent: 19, children: 3, data:[ { "type": "home", "number": "212 555-1234" }, { "type": "office", "number": "646 555-4567" }, { "type": "mobile", "number": "123 456-7890" } ],node: 21, OBJECT, parent: 20, children: 2, data:{ "type": "home", "number": "212 555-1234" },node: 22, STRING, parent: 21, children: 1, data:type,node: 23, STRING, parent: 22, children: 0, data:home,node: 24, STRING, parent: 21, children: 1, data:number,node: 25, STRING, parent: 24, children: 0, data:212 555-1234,node: 26, OBJECT, parent: 20, children: 2, data:{ "type": "office", "number": "646 555-4567" },node: 27, STRING, parent: 26, children: 1, data:type,node: 28, STRING, parent: 27, children: 0, data:office,node: 29, STRING, parent: 26, children: 1, data:number,node: 30, STRING, parent: 29, children: 0, data:646 555-4567,node: 31, OBJECT, parent: 20, children: 2, data:{ "type": "mobile", "number": "123 456-7890" },node: 32, STRING, parent: 31, children: 1, data:type,node: 33, STRING, parent: 32, children: 0, data:mobile,node: 34, STRING, parent: 31, children: 1, data:number,node: 35, STRING, parent: 34, children: 0, data:123 456-7890,node: 36, STRING, parent: 0, children: 1, data:children,node: 37, ARRAY, parent: 36, children: 0, data:[],node: 38, STRING, parent: 0, children: 1, data:spouse,node: 39, PRIMITIVE, parent: 38, children: 0, data:null,
You can use tiny-json. It gives you more than tokens. I have used with microcontrollers of 16-bits and 32-bits and it works fine.
char str[] = "{" "\"data1\":[1,2,3,4,5,6,7,8,9]," "\"data2\":[" "[3,4,5,6,1]," "[8,4,5,6,1]," "[10,4,5,3,61]," "[3,4,5,6,1]," "[3,4,5,6,1]," "[3,4,5,6,1]" "]" "}";puts( str );json_t pool[64];json_t const* root = json_create( str, pool, 64 );json_t const* data1 = json_getProperty( root, "data1" );if ( data1 && JSON_ARRAY == json_getType( data1 ) ) { json_t const* field = json_getChild( data1 ); while( field ) { if ( JSON_INTEGER == json_getType( field ) ) { long long int data = json_getInteger( field ); printf("Integer from data1: %lld\n", data ); } field = json_getSibling( field ); }}json_t const* data2 = json_getProperty( root, "data2" );if ( data2 && JSON_ARRAY == json_getType( data2 ) ) { json_t const* array = json_getChild( data2 ); while( array ) { if ( JSON_ARRAY == json_getType( array ) ) { puts("Array in data2"); json_t const* field = json_getChild( array ); while( field ) { if ( JSON_INTEGER == json_getType( field ) ) { long long int data = json_getInteger( field ); printf("Integer from array of data2: %lld\n", data ); } field = json_getSibling( field ); } } array = json_getSibling( array ); }}