Skip to content

JSON Skill

JSON5/JSON6 parsing, path queries, tree manipulation, iteration, and serialization.

Invoke with: /json

Key APIs

c
/* Parsing */
Json *jsonParse(cchar *text, int flags);
Json *jsonParseFile(cchar *path, char **errorMsg, int flags);
Json *jsonAlloc(void);

/* Querying -- nid is parent node ID, use 0 for root */
cchar *jsonGet(Json *json, int nid, cchar *key, cchar *defaultValue);
bool jsonGetBool(Json *json, int nid, cchar *key, bool defaultValue);
ssize jsonGetLength(Json *json, int nid, cchar *key);

/* Modification */
int jsonSet(Json *json, int nid, cchar *key, cchar *value, int type);
int jsonSetString(Json *json, int nid, cchar *key, cchar *value);
int jsonSetNum(Json *json, int nid, cchar *key, int64 value);
int jsonSetBool(Json *json, int nid, cchar *key, bool value);
int jsonSetJsonFmt(Json *json, int nid, cchar *key, cchar *fmt, ...);

/* Serialization */
char *jsonToString(const Json *json, int nid, cchar *key, int flags);
cchar *jsonString(const Json *json, int flags);

/* Lifecycle */
void jsonFree(Json *json);

Parse and Query

c
Json  *json;
cchar *name;

json = jsonParse(text, 0);
name = jsonGet(json, 0, "users.0.name", NULL);
if (name) {
    rInfo("app", "Name: %s", name);
}
jsonFree(json);

Dot-notation paths index into nested objects and arrays: "config.database.path", "items.0.name".

Building JSON Objects

c
Json *request = jsonAlloc();
jsonSetString(request, 0, "model", "gpt-4o-mini");
jsonSetString(request, 0, "input", userInput);
jsonSetNum(request, 0, "max_tokens", 1000);
jsonSetBool(request, 0, "stream", 0);
jsonFree(request);

SDEF and SFMT Macros

SDEF(...) concatenates literal strings at compile time for multi-line JSON5 templates:

c
cchar *template = SDEF({
    model: 'gpt-4o',
    input: 'Hello',
});

SFMT(buf, fmt, ...) formats a string into a stack buffer:

c
char buf[1024];
Json *json = jsonParse(SFMT(buf, SDEF({
    model: '%s',
    input: '%s',
}), model, input), 0);

Iterating Arrays

c
/* By index */
ssize count = jsonGetLength(json, 0, "items");
for (int i = 0; i < count; i++) {
    cchar *name = jsonGet(json, 0, sfmt("items.%d.name", i), NULL);
}

/* With ITERATE_JSON_KEY (preferred) */
JsonNode *child;
int       nid;
for (ITERATE_JSON_KEY(json, 0, "items", child, nid)) {
    cchar *name = jsonGet(json, nid, "name", NULL);
}

Memory Ownership Rules

  • jsonGet() returns a pointer into the tree — invalid after jsonFree() or tree modification.
  • jsonToString() allocates a new string — caller must rFree().
  • jsonAlloc() and jsonParse() allocate trees — caller must jsonFree().
  • Do NOT modify the tree during iteration.