csonpath 0.14.0__tar.gz → 0.15.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. {csonpath-0.14.0 → csonpath-0.15.0}/Makefile +15 -3
  2. csonpath-0.15.0/PKG-INFO +309 -0
  3. csonpath-0.15.0/README.md +300 -0
  4. csonpath-0.15.0/csonpath.egg-info/PKG-INFO +309 -0
  5. {csonpath-0.14.0 → csonpath-0.15.0}/csonpath.h +229 -80
  6. {csonpath-0.14.0 → csonpath-0.15.0}/csonpath_do.h +60 -10
  7. {csonpath-0.14.0 → csonpath-0.15.0}/csonpath_python.c +7 -3
  8. {csonpath-0.14.0 → csonpath-0.15.0}/csonpath_yyjson.h +17 -14
  9. {csonpath-0.14.0 → csonpath-0.15.0}/pyproject.toml +2 -2
  10. csonpath-0.15.0/setup.py +64 -0
  11. csonpath-0.14.0/PKG-INFO +0 -183
  12. csonpath-0.14.0/README.md +0 -174
  13. csonpath-0.14.0/csonpath.egg-info/PKG-INFO +0 -183
  14. csonpath-0.14.0/setup.py +0 -35
  15. {csonpath-0.14.0 → csonpath-0.15.0}/LICENSE +0 -0
  16. {csonpath-0.14.0 → csonpath-0.15.0}/MANIFEST.in +0 -0
  17. {csonpath-0.14.0 → csonpath-0.15.0}/configure +0 -0
  18. {csonpath-0.14.0 → csonpath-0.15.0}/csonpath.egg-info/SOURCES.txt +0 -0
  19. {csonpath-0.14.0 → csonpath-0.15.0}/csonpath.egg-info/dependency_links.txt +0 -0
  20. {csonpath-0.14.0 → csonpath-0.15.0}/csonpath.egg-info/requires.txt +0 -0
  21. {csonpath-0.14.0 → csonpath-0.15.0}/csonpath.egg-info/top_level.txt +0 -0
  22. {csonpath-0.14.0 → csonpath-0.15.0}/csonpath_json-c.h +0 -0
  23. {csonpath-0.14.0 → csonpath-0.15.0}/setup.cfg +0 -0
  24. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/.git +0 -0
  25. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/.github/workflows/c-cpp.yml +0 -0
  26. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/.gitignore +0 -0
  27. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/LICENSE +0 -0
  28. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/Makefile +0 -0
  29. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/README.md +0 -0
  30. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/clib.json +0 -0
  31. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/formal_verification.md +0 -0
  32. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/re.c +0 -0
  33. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/re.h +0 -0
  34. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/scripts/exrex.py +0 -0
  35. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/scripts/regex_test.py +0 -0
  36. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/scripts/regex_test_neg.py +0 -0
  37. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/tests/test1.c +0 -0
  38. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/tests/test2.c +0 -0
  39. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/tests/test3.c +0 -0
  40. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/tests/test_compile.c +0 -0
  41. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/tests/test_print.c +0 -0
  42. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/tests/test_rand.c +0 -0
  43. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/tests/test_rand_neg.c +0 -0
  44. {csonpath-0.14.0 → csonpath-0.15.0}/tiny-regex-c/tests/test_thread.c +0 -0
@@ -1,9 +1,13 @@
1
1
  JSON_C_CFLAGS=$(shell pkg-config --cflags json-c)
2
2
  JSON_C_LDFLAGS=$(shell pkg-config --libs json-c)
3
+ YYJSON_CFLAGS=$(shell pkg-config --cflags yyjson)
4
+ YYJSON_LDFLAGS=$(shell pkg-config --libs yyjson)
3
5
 
4
6
  include config.mk
5
7
 
6
- all: test-json-c-get-a test-json-update test-json-filter test-json-subpath test-json-c-array-root test-json-filter-and-missing-key test-json-get-array-big-index
8
+ all: test-json-c-get-a test-json-update test-json-filter test-json-subpath test-json-c-array-root test-json-filter-and-missing-key test-json-get-array-big-index test-json-union
9
+
10
+ YYJSON_TESTS=test-yyjson
7
11
 
8
12
  bench:
9
13
  make -C bench
@@ -36,7 +40,13 @@ test-json-filter-and-missing-key: tests/json-c/filter-and-missing-key.c csonpath
36
40
  test-json-get-array-big-index: tests/json-c/get-array-big-index.c csonpath_json-c.h csonpath.h csonpath_do.h
37
41
  $(CC) tests/json-c/get-array-big-index.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-json-get-array-big-index $(JSON_C_LDFLAGS) $(LDFLAGS)
38
42
 
39
- tests-c: test-json-c-get-a test-json-update test-json-filter test-json-subpath test-json-c-array-root test-json-filter-and-missing-key test-json-get-array-big-index
43
+ test-json-union: tests/json-c/union.c csonpath_json-c.h csonpath.h csonpath_do.h
44
+ $(CC) tests/json-c/union.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-json-union $(JSON_C_LDFLAGS) $(LDFLAGS)
45
+
46
+ test-yyjson: tests/yyjson/test-yyjson.c csonpath_yyjson.h csonpath.h csonpath_do.h
47
+ $(CC) tests/yyjson/test-yyjson.c $(EXTRA_FILES) $(YYJSON_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-yyjson $(YYJSON_LDFLAGS) $(LDFLAGS)
48
+
49
+ tests-c: test-json-c-get-a test-json-update test-json-filter test-json-subpath test-json-c-array-root test-json-filter-and-missing-key test-json-get-array-big-index test-json-union test-yyjson
40
50
  ./test-json-c-get-a
41
51
  ./test-json-update
42
52
  ./test-json-filter
@@ -44,6 +54,8 @@ tests-c: test-json-c-get-a test-json-update test-json-filter test-json-subpath t
44
54
  ./test-json-c-array-root
45
55
  ./test-json-filter-and-missing-key
46
56
  ./test-json-get-array-big-index
57
+ ./test-json-union
58
+ ./test-yyjson
47
59
 
48
60
  pip-dev:
49
61
  pip install -e .[dev] --force-reinstall
@@ -54,5 +66,5 @@ tests-py: pip-dev
54
66
  tests: tests-py tests-c
55
67
 
56
68
  clean:
57
- rm -rvf test-json-c-get-a test-json-update test-json-filter test-json-subpath test-json-c-array-root test-json-filter-and-missing-key test-json-get-array-big-index
69
+ rm -rvf test-json-c-get-a test-json-update test-json-filter test-json-subpath test-json-c-array-root test-json-filter-and-missing-key test-json-get-array-big-index test-json-union test-yyjson
58
70
 
@@ -0,0 +1,309 @@
1
+ Metadata-Version: 2.4
2
+ Name: csonpath
3
+ Version: 0.15.0
4
+ Description-Content-Type: text/markdown
5
+ License-File: LICENSE
6
+ Provides-Extra: dev
7
+ Requires-Dist: pytest>=8.3.5; extra == "dev"
8
+ Dynamic: license-file
9
+
10
+ # csonpath
11
+
12
+ > That's not my path, that's not your path, but **csonpath**.
13
+
14
+ [![Project Sandbox](https://docs.outscale.com/fr/userguide/_images/Project-Sandbox-yellow.svg)](https://docs.outscale.com/en/userguide/Open-Source-Projects.html)
15
+
16
+ **csonpath** is a partial [JSONPath](https://goessner.net/articles/JsonPath/) implementation in C, with Python bindings. It allows you to query, update, and remove data from JSON objects using path expressions.
17
+
18
+ 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](https://github.com/json-c/json-c) and Python are provided.
19
+
20
+ ---
21
+
22
+ ## 🚀 Features
23
+
24
+ ### JSONPath Syntax
25
+
26
+ | Feature | Example | Description |
27
+ |---|---|---|
28
+ | Dot notation | `$.a.b` | Access nested object fields |
29
+ | Bracket notation | `$['a']['b']` | Alternative object/array access |
30
+ | Array index | `$.array[0]` | Access by zero-based index |
31
+ | Wildcard `[*]` | `$.array[*].field` | Iterate all array elements |
32
+ | Recursive descent `..` | `$..name` | Search recursively for a key |
33
+ | Union `\|` / `,` | `$.a \| $.b` or `$['a','b']` | Match multiple paths at once |
34
+ | Filters | `$.items[?price > 10]` | Filter array elements |
35
+ | Regex filters | `$.items[?name =~ "foo"]` | POSIX regex-based filtering |
36
+ | Multiple filters (`&`) | `$.items[?a=1 & b=2]` | Combine conditions |
37
+ | Subpath expressions | `$.obj[$.key]` | Use JSON values as dynamic path keys |
38
+ | `@` current object | `$.items[?@.price > 10]` | Reference the current element in filters |
39
+
40
+ ### Operations
41
+ - **Find First** — retrieve the first match.
42
+ - **Find All** — retrieve all matches (returns an array).
43
+ - **Update or Create** — modify existing values or create missing ones.
44
+ - **Remove** — delete matching elements.
45
+ - **Callback** — execute a custom callback on each match.
46
+ - **Update or Create Callback** — traverse the path, creating missing intermediate objects and arrays, then invoke the callback on each leaf node.
47
+
48
+ ---
49
+
50
+ ## 🌐 Links
51
+
52
+ - Project website: https://github.com/outscale/csonpath
53
+ - Join our community on [Discord](https://discord.gg/HUVtY5gT6s)
54
+
55
+ ---
56
+
57
+ ## 📄 Table of Contents
58
+
59
+ - [Features](#-features)
60
+ - [Installation](#-installation)
61
+ - [Usage](#-usage)
62
+ - [C API Reference](#-c-api-reference)
63
+ - [Python API Reference](#-python-api-reference)
64
+ - [Custom Backends](#-custom-backends)
65
+ - [Running Tests](#-running-tests)
66
+ - [Directory Structure](#-directory-structure)
67
+ - [Contributing](#-contributing)
68
+ - [License](#-license)
69
+
70
+ ---
71
+
72
+ ## 📦 Installation
73
+
74
+ ### Prerequisites
75
+ - C compiler (`gcc` or `clang`)
76
+ - [json-c](https://github.com/json-c/json-c) library (for C usage)
77
+ - Python 3.x (for Python bindings)
78
+
79
+ ### C (json-c)
80
+ Just include the header in your project. There is no separate install step required:
81
+ ```c
82
+ #include "csonpath_json-c.h"
83
+ ```
84
+ Make sure to link against `json-c` when compiling:
85
+ ```sh
86
+ gcc myapp.c -o myapp $(pkg-config --cflags --libs json-c)
87
+ ```
88
+
89
+ ### Python
90
+ Install from PyPI:
91
+ ```sh
92
+ pip install csonpath
93
+ ```
94
+
95
+ To install from source (development):
96
+ ```sh
97
+ pip install .
98
+ # or
99
+ make pip-dev
100
+ ```
101
+
102
+ ---
103
+
104
+ ## 🛠️ Usage
105
+
106
+ ### C (json-c)
107
+
108
+ ```c
109
+ #include "csonpath_json-c.h"
110
+
111
+ static void my_cb(json_object *parent, struct csonpath_child_info *info,
112
+ json_object *current, void *ud)
113
+ {
114
+ json_object_set_string(current, "modified");
115
+ }
116
+
117
+ int main(void)
118
+ {
119
+ struct json_object *jobj = json_tokener_parse(json_str);
120
+ struct csonpath *p = csonpath_new("$.a");
121
+
122
+ /* Find First: return the first match, or NULL */
123
+ struct json_object *ret = csonpath_find_first(p, jobj);
124
+
125
+ /* Find All: return a NEW json_object array. Caller must free it. */
126
+ ret = csonpath_find_all(p, jobj);
127
+ json_object_put(ret);
128
+
129
+ /* Remove: delete matching keys (or set array slots to null). Returns count. */
130
+ int removed = csonpath_remove(p, jobj);
131
+
132
+ /* Update or Create: replace matches, or create the full path if missing. */
133
+ csonpath_update_or_create(p, jobj, json_object_new_string("new_value"));
134
+
135
+ /* Callback: call a user function for every match. */
136
+ csonpath_callback(p, jobj, my_cb, NULL);
137
+
138
+ /* Update or Create Callback: like callback, but creates missing parents first,
139
+ then invokes the callback on every leaf (existing or newly created). */
140
+ csonpath_update_or_create_callback(p, jobj, my_cb, NULL);
141
+
142
+ csonpath_destroy(p);
143
+ json_object_put(jobj);
144
+ return 0;
145
+ }
146
+ ```
147
+
148
+ ### Python
149
+
150
+ ```python
151
+ import csonpath
152
+
153
+ data = {"a": "value", "array": [1, 2, 3]}
154
+ p = csonpath.CsonPath("$.a")
155
+
156
+ # Find First / Find All
157
+ p.find_first(data) # -> "value"
158
+ p.find_all(data) # -> ["value"]
159
+
160
+ # Remove: returns number of removed items
161
+ p.set_path("$.array[*]")
162
+ p.remove(data)
163
+
164
+ # Update or Create: builds missing objects/arrays automatically
165
+ p.set_path("$.x.y.z")
166
+ p.update_or_create(data, [])
167
+ # data is now {"a": "value", "array": [1, 2, 3], "x": {"y": {"z": []}}}
168
+
169
+ # Callback
170
+ p.set_path("$.a")
171
+ p.callback(data, lambda parent, idx, cur, _: parent.__setitem__(idx, cur.upper()))
172
+
173
+ # Update or Create Callback: creates parents, then calls cb on each leaf
174
+ p.set_path("$[*].a")
175
+ p.update_or_create_callback(dst, my_sync_fn, userdata)
176
+ ```
177
+
178
+ ---
179
+
180
+ ## 📘 C API Reference
181
+
182
+ ```c
183
+ struct csonpath *csonpath_new(const char *path);
184
+ ```
185
+ Create and initialize a new csonpath object.
186
+
187
+ ```c
188
+ int csonpath_set_path(struct csonpath *p, const char *path);
189
+ ```
190
+ Change the path of an existing object.
191
+
192
+ ```c
193
+ int csonpath_compile(struct csonpath *p);
194
+ ```
195
+ Compile the path expression. This is optional—paths are compiled automatically on first use—but explicit compilation can help catch syntax errors earlier.
196
+
197
+ ```c
198
+ void csonpath_print_instruction(struct csonpath *p);
199
+ ```
200
+ Print the compiled bytecode instructions (useful for debugging).
201
+
202
+ ```c
203
+ struct json_object *csonpath_find_first(struct csonpath *p, struct json_object *json);
204
+ ```
205
+ Return the first matching value, or `NULL` if none is found.
206
+
207
+ ```c
208
+ struct json_object *csonpath_find_all(struct csonpath *p, struct json_object *json);
209
+ ```
210
+ Return a new `json_object` array containing all matches. **Must be freed with `json_object_put()`.**
211
+
212
+ ```c
213
+ int csonpath_remove(struct csonpath *p, struct json_object *json);
214
+ ```
215
+ Remove all matching elements. Returns the number of elements removed.
216
+
217
+ ```c
218
+ int csonpath_update_or_create(struct csonpath *p, struct json_object *json, struct json_object *new_val);
219
+ ```
220
+ Replace matching values with `new_val`, or create the path if it does not exist.
221
+
222
+ ```c
223
+ int csonpath_callback(struct csonpath *p, struct json_object *json,
224
+ json_c_callback callback, void *userdata);
225
+ ```
226
+ Invoke `callback` for every match.
227
+
228
+ ```c
229
+ int csonpath_update_or_create_callback(struct csonpath *p, struct json_object *json,
230
+ json_c_callback callback, void *userdata);
231
+ ```
232
+ Like `callback`, but traverses the path while updating/creating missing intermediate objects.
233
+
234
+ ```c
235
+ void csonpath_destroy(struct csonpath *p);
236
+ ```
237
+ Free the csonpath object.
238
+
239
+ ---
240
+
241
+ ## 📗 Python API Reference
242
+
243
+ - **`CsonPath(path, return_empty_array=False, jq_like=False)`** — Create a new csonpath object. Optional flags: `return_empty_array` returns `[]` instead of `None` when `find_all()` finds nothing; `jq_like` allows jq-style paths without a leading `$`.
244
+ - **`set_path(path)`** — Change the path expression.
245
+ - **`find_first(json)`** — Return the first match, or `None`.
246
+ - **`find_all(json)`** — Return a list of all matches, or `None` (or `[]` if configured).
247
+ - **`remove(json)`** — Remove all matches. Returns the number of removed items.
248
+ - **`update_or_create(json, value)`** — Replace matches with `value`, or create the path.
249
+ - **`callback(json, callback, callback_data=None)`** — Call `callback(parent, idx, current, callback_data)` for every match.
250
+ - **`update_or_create_callback(json, callback, callback_data=None)`** — Same as `callback`, but creates missing parent objects along the path.
251
+
252
+ ---
253
+
254
+ ## 🔌 Custom Backends
255
+
256
+ csonpath is designed to be backend-agnostic. It can work with any data structure that supports array, object, and scalar semantics.
257
+
258
+ 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.
259
+
260
+ For more details, see the existing backend implementations:
261
+ - `csonpath_json-c.h` — json-c backend
262
+ - `csonpath_python.c` — Python backend
263
+
264
+ ---
265
+
266
+ ## 🧪 Running Tests
267
+
268
+ ### C Tests
269
+ ```sh
270
+ make tests-c
271
+ ```
272
+
273
+ ### Python Tests
274
+ ```sh
275
+ make tests-py
276
+ ```
277
+
278
+ ### All Tests
279
+ ```sh
280
+ make tests
281
+ ```
282
+
283
+ ---
284
+
285
+ ## 📁 Directory Structure
286
+
287
+ | File / Directory | Description |
288
+ |---|---|
289
+ | `csonpath.h`, `csonpath_do.h` | Core implementation (header-only style) |
290
+ | `csonpath_json-c.h` | json-c backend |
291
+ | `csonpath_python.c` | Python C extension backend |
292
+ | `tests/` | C and Python test suites |
293
+ | `bench/` | Performance benchmarks |
294
+
295
+ ---
296
+
297
+ ## 🤝 Contributing
298
+
299
+ We welcome contributions!
300
+
301
+ Please read our [Contributing Guidelines](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md) before submitting a pull request.
302
+
303
+ Feel free to open issues or pull requests!
304
+
305
+ ---
306
+
307
+ ## 📜 License
308
+
309
+ BSD 3-Clause. See [LICENSE](LICENSE).
@@ -0,0 +1,300 @@
1
+ # csonpath
2
+
3
+ > That's not my path, that's not your path, but **csonpath**.
4
+
5
+ [![Project Sandbox](https://docs.outscale.com/fr/userguide/_images/Project-Sandbox-yellow.svg)](https://docs.outscale.com/en/userguide/Open-Source-Projects.html)
6
+
7
+ **csonpath** is a partial [JSONPath](https://goessner.net/articles/JsonPath/) implementation in C, with Python bindings. It allows you to query, update, and remove data from JSON objects using path expressions.
8
+
9
+ 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](https://github.com/json-c/json-c) and Python are provided.
10
+
11
+ ---
12
+
13
+ ## 🚀 Features
14
+
15
+ ### JSONPath Syntax
16
+
17
+ | Feature | Example | Description |
18
+ |---|---|---|
19
+ | Dot notation | `$.a.b` | Access nested object fields |
20
+ | Bracket notation | `$['a']['b']` | Alternative object/array access |
21
+ | Array index | `$.array[0]` | Access by zero-based index |
22
+ | Wildcard `[*]` | `$.array[*].field` | Iterate all array elements |
23
+ | Recursive descent `..` | `$..name` | Search recursively for a key |
24
+ | Union `\|` / `,` | `$.a \| $.b` or `$['a','b']` | Match multiple paths at once |
25
+ | Filters | `$.items[?price > 10]` | Filter array elements |
26
+ | Regex filters | `$.items[?name =~ "foo"]` | POSIX regex-based filtering |
27
+ | Multiple filters (`&`) | `$.items[?a=1 & b=2]` | Combine conditions |
28
+ | Subpath expressions | `$.obj[$.key]` | Use JSON values as dynamic path keys |
29
+ | `@` current object | `$.items[?@.price > 10]` | Reference the current element in filters |
30
+
31
+ ### Operations
32
+ - **Find First** — retrieve the first match.
33
+ - **Find All** — retrieve all matches (returns an array).
34
+ - **Update or Create** — modify existing values or create missing ones.
35
+ - **Remove** — delete matching elements.
36
+ - **Callback** — execute a custom callback on each match.
37
+ - **Update or Create Callback** — traverse the path, creating missing intermediate objects and arrays, then invoke the callback on each leaf node.
38
+
39
+ ---
40
+
41
+ ## 🌐 Links
42
+
43
+ - Project website: https://github.com/outscale/csonpath
44
+ - Join our community on [Discord](https://discord.gg/HUVtY5gT6s)
45
+
46
+ ---
47
+
48
+ ## 📄 Table of Contents
49
+
50
+ - [Features](#-features)
51
+ - [Installation](#-installation)
52
+ - [Usage](#-usage)
53
+ - [C API Reference](#-c-api-reference)
54
+ - [Python API Reference](#-python-api-reference)
55
+ - [Custom Backends](#-custom-backends)
56
+ - [Running Tests](#-running-tests)
57
+ - [Directory Structure](#-directory-structure)
58
+ - [Contributing](#-contributing)
59
+ - [License](#-license)
60
+
61
+ ---
62
+
63
+ ## 📦 Installation
64
+
65
+ ### Prerequisites
66
+ - C compiler (`gcc` or `clang`)
67
+ - [json-c](https://github.com/json-c/json-c) library (for C usage)
68
+ - Python 3.x (for Python bindings)
69
+
70
+ ### C (json-c)
71
+ Just include the header in your project. There is no separate install step required:
72
+ ```c
73
+ #include "csonpath_json-c.h"
74
+ ```
75
+ Make sure to link against `json-c` when compiling:
76
+ ```sh
77
+ gcc myapp.c -o myapp $(pkg-config --cflags --libs json-c)
78
+ ```
79
+
80
+ ### Python
81
+ Install from PyPI:
82
+ ```sh
83
+ pip install csonpath
84
+ ```
85
+
86
+ To install from source (development):
87
+ ```sh
88
+ pip install .
89
+ # or
90
+ make pip-dev
91
+ ```
92
+
93
+ ---
94
+
95
+ ## 🛠️ Usage
96
+
97
+ ### C (json-c)
98
+
99
+ ```c
100
+ #include "csonpath_json-c.h"
101
+
102
+ static void my_cb(json_object *parent, struct csonpath_child_info *info,
103
+ json_object *current, void *ud)
104
+ {
105
+ json_object_set_string(current, "modified");
106
+ }
107
+
108
+ int main(void)
109
+ {
110
+ struct json_object *jobj = json_tokener_parse(json_str);
111
+ struct csonpath *p = csonpath_new("$.a");
112
+
113
+ /* Find First: return the first match, or NULL */
114
+ struct json_object *ret = csonpath_find_first(p, jobj);
115
+
116
+ /* Find All: return a NEW json_object array. Caller must free it. */
117
+ ret = csonpath_find_all(p, jobj);
118
+ json_object_put(ret);
119
+
120
+ /* Remove: delete matching keys (or set array slots to null). Returns count. */
121
+ int removed = csonpath_remove(p, jobj);
122
+
123
+ /* Update or Create: replace matches, or create the full path if missing. */
124
+ csonpath_update_or_create(p, jobj, json_object_new_string("new_value"));
125
+
126
+ /* Callback: call a user function for every match. */
127
+ csonpath_callback(p, jobj, my_cb, NULL);
128
+
129
+ /* Update or Create Callback: like callback, but creates missing parents first,
130
+ then invokes the callback on every leaf (existing or newly created). */
131
+ csonpath_update_or_create_callback(p, jobj, my_cb, NULL);
132
+
133
+ csonpath_destroy(p);
134
+ json_object_put(jobj);
135
+ return 0;
136
+ }
137
+ ```
138
+
139
+ ### Python
140
+
141
+ ```python
142
+ import csonpath
143
+
144
+ data = {"a": "value", "array": [1, 2, 3]}
145
+ p = csonpath.CsonPath("$.a")
146
+
147
+ # Find First / Find All
148
+ p.find_first(data) # -> "value"
149
+ p.find_all(data) # -> ["value"]
150
+
151
+ # Remove: returns number of removed items
152
+ p.set_path("$.array[*]")
153
+ p.remove(data)
154
+
155
+ # Update or Create: builds missing objects/arrays automatically
156
+ p.set_path("$.x.y.z")
157
+ p.update_or_create(data, [])
158
+ # data is now {"a": "value", "array": [1, 2, 3], "x": {"y": {"z": []}}}
159
+
160
+ # Callback
161
+ p.set_path("$.a")
162
+ p.callback(data, lambda parent, idx, cur, _: parent.__setitem__(idx, cur.upper()))
163
+
164
+ # Update or Create Callback: creates parents, then calls cb on each leaf
165
+ p.set_path("$[*].a")
166
+ p.update_or_create_callback(dst, my_sync_fn, userdata)
167
+ ```
168
+
169
+ ---
170
+
171
+ ## 📘 C API Reference
172
+
173
+ ```c
174
+ struct csonpath *csonpath_new(const char *path);
175
+ ```
176
+ Create and initialize a new csonpath object.
177
+
178
+ ```c
179
+ int csonpath_set_path(struct csonpath *p, const char *path);
180
+ ```
181
+ Change the path of an existing object.
182
+
183
+ ```c
184
+ int csonpath_compile(struct csonpath *p);
185
+ ```
186
+ Compile the path expression. This is optional—paths are compiled automatically on first use—but explicit compilation can help catch syntax errors earlier.
187
+
188
+ ```c
189
+ void csonpath_print_instruction(struct csonpath *p);
190
+ ```
191
+ Print the compiled bytecode instructions (useful for debugging).
192
+
193
+ ```c
194
+ struct json_object *csonpath_find_first(struct csonpath *p, struct json_object *json);
195
+ ```
196
+ Return the first matching value, or `NULL` if none is found.
197
+
198
+ ```c
199
+ struct json_object *csonpath_find_all(struct csonpath *p, struct json_object *json);
200
+ ```
201
+ Return a new `json_object` array containing all matches. **Must be freed with `json_object_put()`.**
202
+
203
+ ```c
204
+ int csonpath_remove(struct csonpath *p, struct json_object *json);
205
+ ```
206
+ Remove all matching elements. Returns the number of elements removed.
207
+
208
+ ```c
209
+ int csonpath_update_or_create(struct csonpath *p, struct json_object *json, struct json_object *new_val);
210
+ ```
211
+ Replace matching values with `new_val`, or create the path if it does not exist.
212
+
213
+ ```c
214
+ int csonpath_callback(struct csonpath *p, struct json_object *json,
215
+ json_c_callback callback, void *userdata);
216
+ ```
217
+ Invoke `callback` for every match.
218
+
219
+ ```c
220
+ int csonpath_update_or_create_callback(struct csonpath *p, struct json_object *json,
221
+ json_c_callback callback, void *userdata);
222
+ ```
223
+ Like `callback`, but traverses the path while updating/creating missing intermediate objects.
224
+
225
+ ```c
226
+ void csonpath_destroy(struct csonpath *p);
227
+ ```
228
+ Free the csonpath object.
229
+
230
+ ---
231
+
232
+ ## 📗 Python API Reference
233
+
234
+ - **`CsonPath(path, return_empty_array=False, jq_like=False)`** — Create a new csonpath object. Optional flags: `return_empty_array` returns `[]` instead of `None` when `find_all()` finds nothing; `jq_like` allows jq-style paths without a leading `$`.
235
+ - **`set_path(path)`** — Change the path expression.
236
+ - **`find_first(json)`** — Return the first match, or `None`.
237
+ - **`find_all(json)`** — Return a list of all matches, or `None` (or `[]` if configured).
238
+ - **`remove(json)`** — Remove all matches. Returns the number of removed items.
239
+ - **`update_or_create(json, value)`** — Replace matches with `value`, or create the path.
240
+ - **`callback(json, callback, callback_data=None)`** — Call `callback(parent, idx, current, callback_data)` for every match.
241
+ - **`update_or_create_callback(json, callback, callback_data=None)`** — Same as `callback`, but creates missing parent objects along the path.
242
+
243
+ ---
244
+
245
+ ## 🔌 Custom Backends
246
+
247
+ csonpath is designed to be backend-agnostic. It can work with any data structure that supports array, object, and scalar semantics.
248
+
249
+ 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.
250
+
251
+ For more details, see the existing backend implementations:
252
+ - `csonpath_json-c.h` — json-c backend
253
+ - `csonpath_python.c` — Python backend
254
+
255
+ ---
256
+
257
+ ## 🧪 Running Tests
258
+
259
+ ### C Tests
260
+ ```sh
261
+ make tests-c
262
+ ```
263
+
264
+ ### Python Tests
265
+ ```sh
266
+ make tests-py
267
+ ```
268
+
269
+ ### All Tests
270
+ ```sh
271
+ make tests
272
+ ```
273
+
274
+ ---
275
+
276
+ ## 📁 Directory Structure
277
+
278
+ | File / Directory | Description |
279
+ |---|---|
280
+ | `csonpath.h`, `csonpath_do.h` | Core implementation (header-only style) |
281
+ | `csonpath_json-c.h` | json-c backend |
282
+ | `csonpath_python.c` | Python C extension backend |
283
+ | `tests/` | C and Python test suites |
284
+ | `bench/` | Performance benchmarks |
285
+
286
+ ---
287
+
288
+ ## 🤝 Contributing
289
+
290
+ We welcome contributions!
291
+
292
+ Please read our [Contributing Guidelines](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md) before submitting a pull request.
293
+
294
+ Feel free to open issues or pull requests!
295
+
296
+ ---
297
+
298
+ ## 📜 License
299
+
300
+ BSD 3-Clause. See [LICENSE](LICENSE).