basic/json_parser/parse_example3.c

See examples/basic/json-parser

/*
* ZentriOS SDK LICENSE AGREEMENT | Zentri.com, 2015.
*
* Use of source code and/or libraries contained in the ZentriOS SDK is
* subject to the Zentri Operating System SDK license agreement and
* applicable open source license agreements.
*
*/
#include "zos.h"
typedef struct
{
uint32_t handle;
zos_bool_t keep_next_token;
zos_bool_t in_from_object;
} parse_context_t;
static zos_result_t json_token_callback(void *user, json_parse_context_t *json_context, json_tok_t *tok);
static zos_result_t file_reader(void *user, void *data, uint32_t max_length, uint32_t *bytes_read);
/*************************************************************************************************
* Demonstrates how to read a JSON file in chunks only keeping certain tokens
*/
zos_result_t parse_example3(const char *filename)
{
zos_result_t result;
json_parse_context_t *json_context = NULL;
char buffer[128];
parse_context_t parse_context;
const json_parse_config_t config =
{
.buffer = buffer,
.buffer_len = sizeof(buffer),
.reader = file_reader,
.token_callback = json_token_callback
};
memset(&parse_context, 0, sizeof(parse_context));
ZOS_LOG("\r\n\r\nParsing: %s", filename);
if(ZOS_FAILED(result, zn_file_open(filename, &parse_context.handle)))
{
ZOS_LOG("Failed to open: %s", filename);
}
else if(ZOS_FAILED(result, json_parse_context_init(&json_context, &config)))
{
ZOS_LOG("Failed to initialize json parsing context");
}
else if(ZOS_FAILED(result, json_parse_chunked(json_context, (void*)&parse_context)))
{
ZOS_LOG("Failed to parse json file");
}
else
{
ZOS_LOG("Name/messages:");
for(const json_tok_t *tok = json_context_get_token(json_context, NULL, NULL); tok != NULL; )
{
if(tok->next == NULL)
{
ZOS_LOG("Malformed JSON");
break;
}
const char *name = tok->data.str;
const char *message = tok->next->data.str;
tok = tok->next->next; // skip ahead two tokens
ZOS_LOG(" %s : %s", name, message);
}
}
zn_file_close(parse_context.handle);
ZOS_LOG("Finished");
return result;
}
/*************************************************************************************************
* This is called before a token is allocated. If this return ZOS_SUCCESS the token is allocated,
* if it returns ZOS_ABORT the token is not allocated, returning anything else will cause the
* parsing to fail.
*/
static zos_result_t json_token_callback(void *user, json_parse_context_t *json_context, json_tok_t *tok)
{
parse_context_t *context = (parse_context_t*)user;
// we want to only keep the 'name' and 'message' VALUES.
if(context->keep_next_token)
{
// the previous token was a 'name' or 'message' key, so keep its value by returning ZOS_SUCCESS
context->keep_next_token = ZOS_FALSE;
return ZOS_SUCCESS;
}
// is this a string token?
else if(tok->type == JSON_TYPE_STRING)
{
// are we entering the 'from' object?
if(!context->in_from_object && strcmp(tok->data.str, "from") == 0)
{
context->in_from_object = ZOS_TRUE;
}
// if we're in the 'from' object and
// this is a key 'named' then we want to keep the NEXT token
else if(context->in_from_object && strcmp(tok->data.str, "name") == 0)
{
context->in_from_object = ZOS_FALSE;
context->keep_next_token = ZOS_TRUE;
}
// else if this is a 'message' token then we want to keep the next token
else if(strcmp(tok->data.str, "message") == 0)
{
context->keep_next_token = ZOS_TRUE;
}
}
return ZOS_ABORTED; // returning ZOS_ABORTED discards this token
}
/*************************************************************************************************
* The parser will call this until it returns an error or
* the 'bytes_read' parameter is return with a 0 value.
*/
static zos_result_t file_reader(void *user, void *data, uint32_t max_length, uint32_t *bytes_read)
{
parse_context_t *context = (parse_context_t*)user;
uint32_t has_more_data;
zn_file_poll(context->handle, &has_more_data);
if(has_more_data == 0)
{
// no more data so set this to 0 to tell the parser to stop calling this reader
*bytes_read = 0;
}
else if(ZOS_FAILED(result, zn_file_read(context->handle, data, max_length, bytes_read)))
{
}
return result;
}