Created
December 27, 2018 18:24
-
-
Save pt300/17441e85594428f7e2cb2a58cef2540d to your computer and use it in GitHub Desktop.
JSMN parse example using parent links feature
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#define JSMN_PARENT_LINKS | |
#include "jsmn.h" | |
#define MAX_TOK 50 | |
struct obj { | |
struct { | |
char *architecture; | |
size_t sqm; | |
} house; | |
struct { | |
char *brand; | |
size_t horsepower; | |
} car; | |
}; | |
void fill_object(char *str, jsmntok_t *tokens, struct obj *parsed, int toknum) { | |
int i, parent; | |
char *tmp; | |
/* | |
* Iterate over tokens to find the keys of root object. | |
* Iteration is started from 1st object as 0th is root object. | |
* We know that key is the key of root object if it's `parent` value | |
* is set to 0. | |
*/ | |
for(i = 1; i < toknum; i++) { | |
if(tokens[i].parent != 0 || | |
tokens[i].type != JSMN_STRING) | |
continue; | |
/* | |
* compare key name and also check if there's a value attached to the key | |
* and also whether that value is an object and whether that object is empty | |
*/ | |
if(strncmp("house", &str[tokens[i].start], tokens[i].end - tokens[i].start) == 0 | |
&& tokens[i].size == 1) { | |
if(tokens[i + 1].size == 0 || | |
tokens[i + 1].type != JSMN_OBJECT) | |
continue; | |
parent = i + 1; | |
/* | |
* Go over tokens untill we either hit end of them or arrive back at | |
* root object | |
*/ | |
for(i++; i < toknum && tokens[i].parent != 0; i++) { | |
if(strncmp("architecture", &str[tokens[i].start], tokens[i].end - tokens[i].start) == 0) { | |
/* | |
* we check parent to make sure that we are not about to | |
* work on value of key that is part of unhandled key/value | |
*/ | |
if(tokens[i].parent != parent || | |
tokens[i].size != 1 || | |
tokens[i + 1].type != JSMN_STRING) | |
continue; | |
i++; //now points at the value | |
/* | |
* Using calloc will zero out memory and with that also add | |
* null at the end of the string in an inefficient way, heh | |
*/ | |
parsed->house.architecture = calloc(1, tokens[i].end - tokens[i].start + 1); | |
memcpy(parsed->house.architecture, &str[tokens[i].start], tokens[i].end - tokens[i].start); | |
} | |
else if(strncmp("sqm", &str[tokens[i].start], tokens[i].end - tokens[i].start) == 0) { | |
if(tokens[i].parent != parent || | |
tokens[i].size != 1 || | |
tokens[i + 1].type != JSMN_PRIMITIVE) | |
continue; | |
i++; | |
tmp = calloc(1, tokens[i].end - tokens[i].start + 1); | |
memcpy(tmp, &str[tokens[i].start], tokens[i].end - tokens[i].start); | |
parsed->house.sqm = atoi(tmp); | |
free(tmp); | |
} | |
} | |
i--; //without this the upper loop with increase the index by one and miss the key | |
} | |
else if(strncmp("car", &str[tokens[i].start], tokens[i].end - tokens[i].start) == 0) { | |
if(tokens[i + 1].size == 0 || | |
tokens[i + 1].type != JSMN_OBJECT) | |
continue; | |
parent = i + 1; | |
for(i++; i < toknum && tokens[i].parent != 0; i++) { | |
if(strncmp("brand", &str[tokens[i].start], tokens[i].end - tokens[i].start) == 0) { | |
if(tokens[i].parent != parent || | |
tokens[i].size != 1 || | |
tokens[i + 1].type != JSMN_STRING) | |
continue; | |
i++; | |
parsed->car.brand = calloc(1, tokens[i].end - tokens[i].start + 1); | |
memcpy(parsed->car.brand, &str[tokens[i].start], tokens[i].end - tokens[i].start); | |
} | |
else if(strncmp("horsepower", &str[tokens[i].start], tokens[i].end - tokens[i].start) == 0) { | |
if(tokens[i].parent != parent || | |
tokens[i].size != 1 || | |
tokens[i + 1].type != JSMN_PRIMITIVE) | |
continue; | |
i++; | |
tmp = calloc(1, tokens[i].end - tokens[i].start + 1); | |
memcpy(tmp, &str[tokens[i].start], tokens[i].end - tokens[i].start); | |
parsed->car.horsepower = atoi(tmp); | |
free(tmp); | |
} | |
} | |
i--; | |
} | |
} | |
} | |
int main(void) { | |
jsmn_parser parser; | |
jsmntok_t tok[MAX_TOK]; | |
int ret; | |
char *input = "{\n" | |
"\"house\": {\"architecture\": \"wood_frame\", \"sqm\": 100},\n" | |
"\"car\": {\"brand\": \"\", \"horsepower\": 40} \n" | |
"}"; | |
struct obj parsed; | |
/* | |
* Initialize parser and parse JSON string | |
*/ | |
jsmn_init(&parser); | |
ret = jsmn_parse(&parser, input, strlen(input), tok, sizeof tok / sizeof *tok); | |
if(ret < 0) { | |
fprintf(stderr, "Parsing failed (%i)\n", ret); | |
return ret; | |
} | |
/* | |
* Fill struct based on parsed data | |
*/ | |
fill_object(input, tok, &parsed, ret); | |
printf("House:\n\tArchitecture: %s\n\tSqm: %i\nCar:\n\tBrand: %s\n\tHorsepower: %i\n", | |
parsed.house.architecture, parsed.house.sqm, parsed.car.brand, parsed.car.horsepower); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment