csonpath
June 11, 2026 Β· View on GitHub
That's not my path, that's not your path, but csonpath.
csonpath is a partial JSONPath implementation in C, with Python bindings. It allows you to query, update, and remove data from JSON objects using path expressions.
Unlike many JSONPath libraries, csonpath is backend-agnostic: it can work with any C library or environment that manipulates array, object, and scalar typesβnot just JSON. Out of the box, backends for json-c and Python are provided.
π Features
JSONPath Syntax
| Feature | Example | Description |
|---|---|---|
| Dot notation | $.a.b | Access nested object fields |
| Bracket notation | $['a']['b'] | Alternative object/array access |
| Array index | $.array[0] | Access by zero-based index |
Wildcard [*] | $.array[*].field | Iterate all array elements |
Recursive descent .. | $..name | Search recursively for a key |
Union | / , | $.a | $.b or $['a','b'] | Match multiple paths at once |
| Filters | $.items[?price > 10] | Filter array elements |
| Regex filters | $.items[?name =~ "foo"] | POSIX regex-based filtering |
Multiple filters (&) | $.items[?a=1 & b=2] | Combine conditions |
| Subpath expressions | $.obj[$.key] | Use JSON values as dynamic path keys |
@ current object | $.items[?@.price > 10] | Reference the current element in filters |
Operations
- Find First β retrieve the first match.
- Find All β retrieve all matches (returns an array).
- Update or Create β modify existing values or create missing ones.
- Remove β delete matching elements.
- Callback β execute a custom callback on each match.
- Update or Create Callback β traverse the path, creating missing intermediate objects and arrays, then invoke the callback on each leaf node.
π Links
- Project website: https://github.com/outscale/csonpath
- Join our community on Discord
π Table of Contents
- Features
- Installation
- Usage
- C API Reference
- Python API Reference
- Custom Backends
- Running Tests
- Directory Structure
- Contributing
- License
π¦ Installation
Prerequisites
- C compiler (
gccorclang) - json-c library (for C usage)
- Python 3.x (for Python bindings)
C (json-c)
Just include the header in your project. There is no separate install step required:
#include "csonpath_json-c.h"
Make sure to link against json-c when compiling:
gcc myapp.c -o myapp $(pkg-config --cflags --libs json-c)
Python
Install from PyPI:
pip install csonpath
To install from source (development):
pip install .
# or
make pip-dev
π οΈ Usage
C (json-c)
#include "csonpath_json-c.h"
static void my_cb(json_object *parent, struct csonpath_child_info *info,
json_object *current, void *ud)
{
json_object_set_string(current, "modified");
}
int main(void)
{
struct json_object *jobj = json_tokener_parse(json_str);
struct csonpath *p = csonpath_new("$.a");
/* Find First: return the first match, or NULL */
struct json_object *ret = csonpath_find_first(p, jobj);
/* Find All: return a NEW json_object array. Caller must free it. */
ret = csonpath_find_all(p, jobj);
json_object_put(ret);
/* Remove: delete matching keys (or set array slots to null). Returns count. */
int removed = csonpath_remove(p, jobj);
/* Update or Create: replace matches, or create the full path if missing. */
csonpath_update_or_create(p, jobj, json_object_new_string("new_value"));
/* Callback: call a user function for every match. */
csonpath_callback(p, jobj, my_cb, NULL);
/* Update or Create Callback: like callback, but creates missing parents first,
then invokes the callback on every leaf (existing or newly created). */
csonpath_update_or_create_callback(p, jobj, my_cb, NULL);
csonpath_destroy(p);
json_object_put(jobj);
return 0;
}
Python
import csonpath
data = {"a": "value", "array": [1, 2, 3]}
p = csonpath.CsonPath("$.a")
# Find First / Find All
p.find_first(data) # -> "value"
p.find_all(data) # -> ["value"]
# Remove: returns number of removed items
p.set_path("$.array[*]")
p.remove(data)
# Update or Create: builds missing objects/arrays automatically
p.set_path("$.x.y.z")
p.update_or_create(data, [])
# data is now {"a": "value", "array": [1, 2, 3], "x": {"y": {"z": []}}}
# Callback
p.set_path("$.a")
p.callback(data, lambda parent, idx, cur, _: parent.__setitem__(idx, cur.upper()))
# Update or Create Callback: creates parents, then calls cb on each leaf
p.set_path("$[*].a")
p.update_or_create_callback(dst, my_sync_fn, userdata)
π C API Reference
struct csonpath *csonpath_new(const char *path);
Create and initialize a new csonpath object.
int csonpath_set_path(struct csonpath *p, const char *path);
Change the path of an existing object.
int csonpath_compile(struct csonpath *p);
Compile the path expression. This is optionalβpaths are compiled automatically on first useβbut explicit compilation can help catch syntax errors earlier.
void csonpath_print_instruction(struct csonpath *p);
Print the compiled bytecode instructions (useful for debugging).
struct json_object *csonpath_find_first(struct csonpath *p, struct json_object *json);
Return the first matching value, or NULL if none is found.
struct json_object *csonpath_find_all(struct csonpath *p, struct json_object *json);
Return a new json_object array containing all matches. Must be freed with json_object_put().
int csonpath_remove(struct csonpath *p, struct json_object *json);
Remove all matching elements. Returns the number of elements removed.
int csonpath_update_or_create(struct csonpath *p, struct json_object *json, struct json_object *new_val);
Replace matching values with new_val, or create the path if it does not exist.
int csonpath_callback(struct csonpath *p, struct json_object *json,
json_c_callback callback, void *userdata);
Invoke callback for every match.
int csonpath_update_or_create_callback(struct csonpath *p, struct json_object *json,
json_c_callback callback, void *userdata);
Like callback, but traverses the path while updating/creating missing intermediate objects.
void csonpath_destroy(struct csonpath *p);
Free the csonpath object.
π Python API Reference
CsonPath(path, return_empty_array=False, jq_like=False)β Create a new csonpath object. Optional flags:return_empty_arrayreturns[]instead ofNonewhenfind_all()finds nothing;jq_likeallows jq-style paths without a leading$.set_path(path)β Change the path expression.find_first(json)β Return the first match, orNone.find_all(json)β Return a list of all matches, orNone(or[]if configured).remove(json)β Remove all matches. Returns the number of removed items.update_or_create(json, value)β Replace matches withvalue, or create the path.callback(json, callback, callback_data=None)β Callcallback(parent, idx, current, callback_data)for every match.update_or_create_callback(json, callback, callback_data=None)β Same ascallback, but creates missing parent objects along the path.
π Custom Backends
csonpath is designed to be backend-agnostic. It can work with any data structure that supports array, object, and scalar semantics.
To create a custom backend, define the required macros and types in a header file (similar to csonpath_json-c.h or csonpath_python.c), then include your backend header before csonpath.h. This allows you to adapt csonpath for manipulating data in any format that supports array/object semantics, giving you full flexibility beyond just JSON.
For more details, see the existing backend implementations:
csonpath_json-c.hβ json-c backendcsonpath_python.cβ Python backend
π§ͺ Running Tests
C Tests
make tests-c
Python Tests
make tests-py
All Tests
make tests
π Directory Structure
| File / Directory | Description |
|---|---|
csonpath.h, csonpath_do.h | Core implementation (header-only style) |
csonpath_json-c.h | json-c backend |
csonpath_python.c | Python C extension backend |
tests/ | C and Python test suites |
bench/ | Performance benchmarks |
π€ Contributing
We welcome contributions!
Please read our Contributing Guidelines and Code of Conduct before submitting a pull request.
Feel free to open issues or pull requests!
π License
BSD 3-Clause. See LICENSE.