AxlJson – JSON

JSON parser (JSMN-based) and builder (fixed buffer). Parse JSON strings into a token tree, query values by path, and build JSON documents incrementally.

Header: <axl/axl-json.h>

Overview

AXL provides two JSON APIs:

  • Parser – parse a JSON string, extract values by key or iterate arrays

  • Builder – construct JSON in a caller-provided buffer with no dynamic allocation

Parsing JSON

const char *json = "{\"name\":\"AXL\",\"version\":1,\"debug\":true}";
AxlJsonCtx ctx;

if (axl_json_parse(json, axl_strlen(json), &ctx)) {
    const char *name;
    size_t name_len;
    int64_t version;
    bool debug;

    axl_json_get_string(&ctx, "name", &name, &name_len);
    axl_json_get_int(&ctx, "version", &version);
    axl_json_get_bool(&ctx, "debug", &debug);

    axl_printf("name=%.*s version=%lld debug=%s\n",
               (int)name_len, name, version,
               debug ? "true" : "false");

    axl_json_free(&ctx);
}

Note: String values returned by axl_json_get_string point into the original JSON buffer (zero-copy). Do not free the original buffer while using extracted strings.

Building JSON

The builder writes into a caller-provided buffer with no heap allocation. Check overflow after building to detect truncation.

char buf[256];
AxlJsonBuilder j;

axl_json_init(&j, buf, sizeof(buf));
axl_json_object_start(&j);
axl_json_add_string(&j, "name", "AXL");
axl_json_add_uint(&j, "version", 1);
axl_json_add_bool(&j, "debug", true);
axl_json_object_end(&j);
axl_json_finish(&j);

if (!j.overflow) {
    axl_printf("%s\n", buf);
    // {"name":"AXL","version":1,"debug":true}
}

Iterating Arrays

// Parse: {"items":["a","b","c"]}
AxlJsonIter iter;
if (axl_json_array_begin(&ctx, "items", &iter)) {
    AxlJsonElement elem;
    while (axl_json_array_next(&iter, &elem)) {
        axl_printf("  %.*s\n", (int)elem.len, elem.value);
    }
}

API Reference

Functions

bool axl_json_parse(const char *json, size_t len, AxlJsonCtx *ctx)

Parse a JSON string.

Allocates a token array sized to fit the document. Call axl_json_free() when done to release the token memory.

Parameters:
  • json – JSON string (not NUL-terminated required)

  • len – length of @json in bytes

  • ctx – context to fill

Returns:

true on success, false on parse error or allocation failure.

void axl_json_free(AxlJsonCtx *ctx)

Free a parsed JSON context.

Releases the heap-allocated token array. Safe to call on contexts that don’t own their tokens (e.g. array elements). NULL-safe.

Parameters:
  • ctx – context to free (NULL-safe)

bool axl_json_get_string(const AxlJsonCtx *ctx, const char *key, char *value, size_t value_size)

Extract a string value from a parsed JSON object.

Parameters:
  • ctx – parsed context

  • key – key to look up

  • value – buffer for string value

  • value_size – size of @value buffer

Returns:

true if found, false if not found or not a string.

bool axl_json_get_int(const AxlJsonCtx *ctx, const char *key, int64_t *value)

Extract an integer value from a parsed JSON object.

Parameters:
  • ctx – parsed context

  • key – key to look up

  • value – receives the integer

Returns:

true if found, false if not found or not a number.

bool axl_json_get_uint(const AxlJsonCtx *ctx, const char *key, uint64_t *value)

Extract an unsigned integer value from a parsed JSON object.

Parameters:
  • ctx – parsed context

  • key – key to look up

  • value – receives the unsigned integer

Returns:

true if found, false if not found or not a number.

bool axl_json_get_bool(const AxlJsonCtx *ctx, const char *key, bool *value)

Extract a boolean value from a parsed JSON object.

Parameters:
  • ctx – parsed context

  • key – key to look up

  • value – receives the boolean

Returns:

true if found, false if not found or not a boolean.

bool axl_json_extract_string(const char *json, size_t len, const char *key, char *value, size_t value_size)

One-shot: parse + extract a string in one call.

Handles allocation and cleanup internally.

Parameters:
  • json – JSON string

  • len – length

  • key – key to extract

  • value – buffer for value

  • value_size – buffer size

Returns:

true on success.

bool axl_json_array_begin(const AxlJsonCtx *ctx, const char *key, AxlJsonArrayIter *iter)

Begin iterating a JSON array value by key name.

Parameters:
  • ctx – parsed context

  • key – key of the array field

  • iter – iterator to initialize

Returns:

true if array found, false if not found or not an array.

bool axl_json_root_array_begin(const AxlJsonCtx *ctx, AxlJsonArrayIter *iter)

Begin iterating a root-level JSON array.

Use when the JSON document is a bare array: [{...}, {...}, ...] rather than an object with a named array field.

Parameters:
  • ctx – parsed context

  • iter – iterator to initialize

Returns:

true if root is an array, false otherwise.

bool axl_json_array_next(AxlJsonArrayIter *iter, AxlJsonCtx *element)

Advance to the next array element.

The element context borrows the parent’s token array — do not call axl_json_free on it. It remains valid until the parent context is freed.

Parameters:
  • iter – iterator

  • element – context for the element

Returns:

true if element returned, false if no more elements.

int axl_json_escape_string(const char *src, char *out, size_t size)

Escape a string for safe embedding in JSON.

Writes the escaped string WITH surrounding double quotes into out. Escapes:

"</tt> <tt>\\\\</tt> <tt>\\n</tt> <tt>\\r</tt> <tt>\\t</tt> and control characters (< 0x20).

Example: axl_json_escape_string("hello "world"", out, 32)

produces: "hello "world""

Useful for building JSON with axl_snprintf:

@code

char esc[64];

axl_json_escape_string(name, esc, sizeof(esc));

axl_snprintf(buf, size, "{"name":s,"size":llu}", esc, sz);

Parameters:
  • src – input string (UTF-8)

  • out – output buffer

  • size – output buffer size

void axl_json_init(AxlJsonBuilder *j, char *buffer, size_t size)

Initialize a JSON builder with a caller-provided buffer.

Parameters:
  • j – builder to initialize

  • buffer – caller-provided buffer

  • size – buffer size

void axl_json_object_start(AxlJsonBuilder *j)

Open a top-level JSON object ({).

Parameters:
  • j – builder

void axl_json_object_end(AxlJsonBuilder *j)

Close the current JSON object (}).

Parameters:
  • j – builder

void axl_json_object_start_named(AxlJsonBuilder *j, const char *key)

Open a named nested object ("key": {).

Parameters:
  • j – builder

  • key – object key name

void axl_json_array_start(AxlJsonBuilder *j, const char *key)

Open a named JSON array ("key": [).

Parameters:
  • j – builder

  • key – array key name

void axl_json_array_end(AxlJsonBuilder *j)

Close the current JSON array (]).

Parameters:
  • j – builder

void axl_json_array_object_start(AxlJsonBuilder *j)

Open an object inside the current array.

Parameters:
  • j – builder

void axl_json_array_add_string(AxlJsonBuilder *j, const char *value)

Append a string value to the current array.

Parameters:
  • j – builder

  • value – string to add

void axl_json_add_string(AxlJsonBuilder *j, const char *key, const char *value)

Add a string key-value pair ("key": "value").

Parameters:
  • j – builder

  • key – key

  • value – string value

void axl_json_add_uint(AxlJsonBuilder *j, const char *key, uint64_t value)

Add an unsigned integer key-value pair ("key": 123).

Parameters:
  • j – builder

  • key – key

  • value – unsigned integer value

void axl_json_add_int(AxlJsonBuilder *j, const char *key, int64_t value)

Add a signed integer key-value pair ("key": -42).

Parameters:
  • j – builder

  • key – key

  • value – integer value

void axl_json_add_bool(AxlJsonBuilder *j, const char *key, bool value)

Add a boolean key-value pair ("key": true).

Parameters:
  • j – builder

  • key – key

  • value – boolean value

void axl_json_add_hex(AxlJsonBuilder *j, const char *key, uint64_t value)

Add a hex-formatted string key-value pair ("key": "0x1A2B").

Parameters:
  • j – builder

  • key – key

  • value – value (written as hex string)

void axl_json_add_null(AxlJsonBuilder *j, const char *key)

Add a null key-value pair ("key": null).

Parameters:
  • j – builder

  • key – key

size_t axl_json_finish(AxlJsonBuilder *j)

Finalize the builder and NUL-terminate the output.

Parameters:
  • j – builder

Returns:

number of characters written (excluding NUL). Check j->overflow to detect truncation.

void axl_json_pretty_print(const char *json, size_t len)

Pretty-print JSON to the console with colors and indentation.

Colors: cyan keys, green strings, yellow numbers, magenta booleans.

Parameters:
  • json – JSON string (ASCII)

  • len – length in bytes

void axl_json_print_raw(const char *json, size_t len)

Print JSON to the console without formatting.

Parameters:
  • json – JSON string (ASCII)

  • len – length in bytes

struct AxlJsonCtx
#include <axl-json.h>

AxlJsonCtx:

Parsed JSON context. The token array is heap-allocated by axl_json_parse and freed by axl_json_free. References the original JSON buffer (do not free it while using the context).

Public Members

const char *json
size_t json_len
int32_t *tokens
int32_t token_count
bool owns_tokens
struct AxlJsonArrayIter
#include <axl-json.h>

AxlJsonArrayIter:

Iterator for JSON arrays.

Public Members

const AxlJsonCtx *ctx
int32_t array_idx
int32_t pos
int32_t remaining
struct AxlJsonBuilder
#include <axl-json.h>

AxlJsonBuilder:

JSON builder with fixed caller-provided buffer. No dynamic allocation. Check overflow after building to detect truncation.

Public Members

char *buffer
size_t size
size_t pos
bool need_comma
bool overflow