utility/json_parser/parse_example3.c
/*******************************************************************************
* # License
* Copyright 2019 Silicon Laboratories Inc. www.silabs.com
*******************************************************************************
*
* The licensor of this software is Silicon Laboratories Inc. Your use of this
* software is governed by the terms of Silicon Labs Master Software License
* Agreement (MSLA) available at
* www.silabs.com/about-us/legal/master-software-license-agreement. This
* software is distributed to you in Source Code format and is governed by the
* sections of the MSLA applicable to Source Code.
*
******************************************************************************/
#include "gos.h"
typedef struct
{
gos_handle_t handle;
bool keep_next_token;
bool in_from_object;
} parse_context_t;
static gos_result_t json_token_callback(void *user, gos_json_parse_context_t *json_context, gos_json_tok_t *tok);
/*************************************************************************************************
* Demonstrates how to read a JSON file in chunks only keeping certain tokens
*/
{
gos_result_t result;
gos_json_parse_context_t *json_context = NULL;
char buffer[128];
parse_context_t parse_context;
{
.buffer = buffer,
.buffer_len = sizeof(buffer),
.reader = file_reader,
.token_callback = json_token_callback
};
memset(&parse_context, 0, sizeof(parse_context));
if (GOS_FAILED(result, gos_file_open(filename, GOS_FILE_LOCATION_EXTENDED, false, &parse_context.handle)))
{
GOS_LOG("Failed to open: %s", filename);
}
{
GOS_LOG("Failed to initialize json parsing context");
}
{
GOS_LOG("Failed to parse json file");
}
else
{
GOS_LOG("Name/messages:");
for (const gos_json_tok_t *tok = gos_json_context_get_token(json_context, NULL, NULL); tok != NULL; )
{
if (tok->next == NULL)
{
GOS_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
GOS_LOG(" %s : %s", name, message);
}
}
gos_file_close(parse_context.handle);
gos_json_parse_context_deinit(json_context);
GOS_LOG("Finished");
return result;
}
/*************************************************************************************************
* This is called before a token is allocated. If this return GOS_SUCCESS the token is allocated,
* if it returns GOS_ABORT the token is not allocated, returning anything else will cause the
* parsing to fail.
*/
static gos_result_t json_token_callback(void *user, gos_json_parse_context_t *json_context, gos_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 GOS_SUCCESS
context->keep_next_token = false;
}
// Is this a string token?
{
// If entering the 'from' object?
{
context->in_from_object = true;
}
// If we're in the 'from' object and this is a key 'named' then we want to keep the NEXT token
{
context->in_from_object = false;
context->keep_next_token = true;
}
// If this is a 'message' token then we want to keep the next token
{
context->keep_next_token = true;
}
}
}
/*************************************************************************************************
* The parser will call this until it returns an error or the 'bytes_read' parameter is return with a 0 value.
*/
{
gos_result_t result = GOS_SUCCESS;
parse_context_t *context = (parse_context_t*)user;
uint32_t has_more_data;
gos_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;
}
{
}
return result;
}