csonpath 0.16.0__tar.gz → 0.18.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.
- {csonpath-0.16.0 → csonpath-0.18.0}/Makefile +54 -6
- {csonpath-0.16.0/csonpath.egg-info → csonpath-0.18.0}/PKG-INFO +160 -12
- {csonpath-0.16.0 → csonpath-0.18.0}/README.md +159 -11
- {csonpath-0.16.0 → csonpath-0.18.0/csonpath.egg-info}/PKG-INFO +160 -12
- {csonpath-0.16.0 → csonpath-0.18.0}/csonpath.egg-info/SOURCES.txt +4 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/csonpath.h +335 -167
- {csonpath-0.16.0 → csonpath-0.18.0}/csonpath_do.h +28 -12
- {csonpath-0.16.0 → csonpath-0.18.0}/csonpath_json-c.h +22 -0
- csonpath-0.18.0/csonpath_my_fuzzing.h +440 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/csonpath_python.c +210 -24
- csonpath-0.18.0/csonpath_undef.h +44 -0
- csonpath-0.18.0/csonpath_yyjson.h +19 -0
- csonpath-0.16.0/csonpath_yyjson.h → csonpath-0.18.0/csonpath_yyjson_const.h +22 -4
- csonpath-0.18.0/csonpath_yyjson_mut.h +223 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/pyproject.toml +2 -2
- {csonpath-0.16.0 → csonpath-0.18.0}/LICENSE +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/MANIFEST.in +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/configure +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/csonpath.egg-info/dependency_links.txt +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/csonpath.egg-info/requires.txt +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/csonpath.egg-info/top_level.txt +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/setup.cfg +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/setup.py +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/.git +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/.github/workflows/c-cpp.yml +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/.gitignore +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/LICENSE +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/Makefile +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/README.md +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/clib.json +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/formal_verification.md +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/re.c +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/re.h +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/scripts/exrex.py +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/scripts/regex_test.py +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/scripts/regex_test_neg.py +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/tests/test1.c +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/tests/test2.c +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/tests/test3.c +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/tests/test_compile.c +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/tests/test_print.c +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/tests/test_rand.c +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/tests/test_rand_neg.c +0 -0
- {csonpath-0.16.0 → csonpath-0.18.0}/tiny-regex-c/tests/test_thread.c +0 -0
|
@@ -5,7 +5,7 @@ YYJSON_LDFLAGS=$(shell pkg-config --libs yyjson)
|
|
|
5
5
|
|
|
6
6
|
include config.mk
|
|
7
7
|
|
|
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 test-json-audit-bugs test-json-crash-vectors
|
|
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 test-json-audit-bugs test-json-crash-vectors test-json-my-fuzz test-json-regex-overflow
|
|
9
9
|
|
|
10
10
|
YYJSON_TESTS=test-yyjson
|
|
11
11
|
|
|
@@ -15,7 +15,7 @@ bench:
|
|
|
15
15
|
bench-clean:
|
|
16
16
|
make -C bench clean
|
|
17
17
|
|
|
18
|
-
.PHONY: all clean tests pip-dev pip-dev bench bench-clean
|
|
18
|
+
.PHONY: all clean tests pip-dev pip-dev bench bench-clean tests-cli tests-rust cov
|
|
19
19
|
|
|
20
20
|
CFLAGS+= -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -O0 -g
|
|
21
21
|
|
|
@@ -49,10 +49,22 @@ test-json-audit-bugs: tests/json-c/audit-bugs.c csonpath_json-c.h csonpath.h cso
|
|
|
49
49
|
test-json-crash-vectors: tests/json-c/crash-vectors.c csonpath_json-c.h csonpath.h csonpath_do.h
|
|
50
50
|
$(CC) tests/json-c/crash-vectors.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-json-crash-vectors $(JSON_C_LDFLAGS) $(LDFLAGS)
|
|
51
51
|
|
|
52
|
-
test-
|
|
52
|
+
test-json-my-fuzz: tests/json-c/my_fuzz.c csonpath_json-c.h csonpath_my_fuzzing.h csonpath.h csonpath_do.h
|
|
53
|
+
$(CC) tests/json-c/my_fuzz.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-json-my-fuzz $(JSON_C_LDFLAGS) $(LDFLAGS)
|
|
54
|
+
|
|
55
|
+
test-json-regex-overflow: tests/json-c/regex-overflow.c csonpath_json-c.h csonpath.h csonpath_do.h
|
|
56
|
+
$(CC) tests/json-c/regex-overflow.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-json-regex-overflow $(JSON_C_LDFLAGS) $(LDFLAGS)
|
|
57
|
+
|
|
58
|
+
test-yyjson: tests/yyjson/test-yyjson.c csonpath_yyjson_const.h csonpath.h csonpath_do.h
|
|
53
59
|
$(CC) tests/yyjson/test-yyjson.c $(EXTRA_FILES) $(YYJSON_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-yyjson $(YYJSON_LDFLAGS) $(LDFLAGS)
|
|
54
60
|
|
|
55
|
-
|
|
61
|
+
test-yyjson-mixed: tests/yyjson/test-yyjson-mixed.c csonpath_yyjson.h csonpath_yyjson_const.h csonpath_yyjson_mut.h csonpath.h csonpath_do.h
|
|
62
|
+
$(CC) tests/yyjson/test-yyjson-mixed.c $(EXTRA_FILES) $(YYJSON_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-yyjson-mixed $(YYJSON_LDFLAGS) $(LDFLAGS)
|
|
63
|
+
|
|
64
|
+
test-multi-backend-prefix: tests/multi-backend-prefix.c csonpath_json-c.h csonpath_yyjson.h csonpath_yyjson_const.h csonpath_yyjson_mut.h csonpath.h csonpath_do.h
|
|
65
|
+
$(CC) tests/multi-backend-prefix.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(YYJSON_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-multi-backend-prefix $(JSON_C_LDFLAGS) $(YYJSON_LDFLAGS) $(LDFLAGS)
|
|
66
|
+
|
|
67
|
+
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-json-audit-bugs test-json-crash-vectors test-yyjson test-yyjson-mixed test-json-my-fuzz test-multi-backend-prefix test-json-regex-overflow
|
|
56
68
|
./test-json-c-get-a
|
|
57
69
|
./test-json-update
|
|
58
70
|
./test-json-filter
|
|
@@ -64,6 +76,16 @@ test-yyjson: tests/yyjson/test-yyjson.c csonpath_yyjson.h csonpath.h csonpath_do
|
|
|
64
76
|
./test-json-audit-bugs
|
|
65
77
|
./test-json-crash-vectors
|
|
66
78
|
./test-yyjson
|
|
79
|
+
./test-yyjson-mixed
|
|
80
|
+
./test-json-my-fuzz
|
|
81
|
+
./test-multi-backend-prefix
|
|
82
|
+
./test-json-regex-overflow
|
|
83
|
+
|
|
84
|
+
csonpath: cli/csonpath_cli.c csonpath_json-c.h csonpath.h csonpath_do.h
|
|
85
|
+
$(CC) cli/csonpath_cli.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(CFLAGS) -I./ -o csonpath $(JSON_C_LDFLAGS) $(LDFLAGS)
|
|
86
|
+
|
|
87
|
+
tests-cli: csonpath
|
|
88
|
+
bash tests/cli/run.sh
|
|
67
89
|
|
|
68
90
|
pip-dev:
|
|
69
91
|
pip install -e .[dev] --force-reinstall
|
|
@@ -71,8 +93,34 @@ pip-dev:
|
|
|
71
93
|
tests-py: pip-dev
|
|
72
94
|
python -m pytest
|
|
73
95
|
|
|
74
|
-
tests:
|
|
96
|
+
tests-rust:
|
|
97
|
+
cargo test --manifest-path rust/Cargo.toml
|
|
98
|
+
|
|
99
|
+
cov:
|
|
100
|
+
$(MAKE) clean
|
|
101
|
+
rm -rf coverage-c coverage-c.html coverage-py coverage-rust build
|
|
102
|
+
find . -name '*.gcov' -delete
|
|
103
|
+
$(MAKE) CFLAGS='--coverage -O0 -g' LDFLAGS='--coverage' tests-c
|
|
104
|
+
CFLAGS='--coverage -O0' LDFLAGS='--coverage' python setup.py build_ext --inplace --force
|
|
105
|
+
python -m coverage run -m pytest
|
|
106
|
+
python -m coverage html -d coverage-py
|
|
107
|
+
python -m gcovr -r . \
|
|
108
|
+
--gcov-object-directory "$$(ls -d build/temp.* 2>/dev/null | head -1)" \
|
|
109
|
+
--filter 'csonpath\.h' --filter 'csonpath_do\.h' --filter 'csonpath_python\.c' \
|
|
110
|
+
--html-details coverage-c.html
|
|
111
|
+
PATH="$$HOME/.cargo/bin:$$PATH" \
|
|
112
|
+
LLVM_COV="$$(find $$HOME/.rustup/toolchains -name llvm-cov -print -quit)" \
|
|
113
|
+
LLVM_PROFDATA="$$(find $$HOME/.rustup/toolchains -name llvm-profdata -print -quit)" \
|
|
114
|
+
cargo llvm-cov --manifest-path rust/Cargo.toml --html --output-dir coverage-rust
|
|
115
|
+
@echo "Coverage reports:"
|
|
116
|
+
@echo " coverage-c.html"
|
|
117
|
+
@echo " coverage-py/index.html"
|
|
118
|
+
@echo " coverage-rust/html/index.html"
|
|
119
|
+
|
|
120
|
+
tests: tests-py tests-c tests-cli tests-rust
|
|
75
121
|
|
|
76
122
|
clean:
|
|
77
|
-
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-json-audit-bugs test-json-crash-vectors test-yyjson
|
|
123
|
+
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-json-audit-bugs test-json-crash-vectors test-yyjson test-yyjson-mixed test-json-my-fuzz test-multi-backend-prefix test-json-regex-overflow csonpath
|
|
124
|
+
find . -name '*.gcda' -delete
|
|
125
|
+
find . -name '*.gcno' -delete
|
|
78
126
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: csonpath
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.18.0
|
|
4
4
|
Description-Content-Type: text/markdown
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Provides-Extra: dev
|
|
@@ -13,9 +13,9 @@ Dynamic: license-file
|
|
|
13
13
|
|
|
14
14
|
[](https://docs.outscale.com/en/userguide/Open-Source-Projects.html)
|
|
15
15
|
|
|
16
|
-
**csonpath** is a partial [JSONPath](https://goessner.net/articles/JsonPath/) implementation in C
|
|
16
|
+
**csonpath** is a partial [JSONPath](https://goessner.net/articles/JsonPath/) implementation in C. It is **backend-agnostic**: the same core engine can query, update, and remove data from any value representation that supports array, object, and scalar semantics—not just JSON.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Out of the box it ships with C backends for [json-c](https://github.com/json-c/json-c) and [yyjson](https://github.com/ibireme/yyjson), plus language bindings for **Python** and **Rust**.
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
@@ -62,6 +62,8 @@ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work wi
|
|
|
62
62
|
- [Usage](#-usage)
|
|
63
63
|
- [C API Reference](#-c-api-reference)
|
|
64
64
|
- [Python API Reference](#-python-api-reference)
|
|
65
|
+
- [CLI](#%EF%B8%8F-cli)
|
|
66
|
+
- [Using Multiple Backends](#-using-multiple-backends)
|
|
65
67
|
- [Custom Backends](#-custom-backends)
|
|
66
68
|
- [Running Tests](#-running-tests)
|
|
67
69
|
- [Directory Structure](#-directory-structure)
|
|
@@ -72,12 +74,12 @@ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work wi
|
|
|
72
74
|
|
|
73
75
|
## 📦 Installation
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
- C compiler (`gcc` or `clang`)
|
|
77
|
-
- [json-c](https://github.com/json-c/json-c) library (for C usage)
|
|
78
|
-
- Python 3.x (for Python bindings)
|
|
77
|
+
csonpath is a C library at its core. Pick the instructions for the language you want to use it from.
|
|
79
78
|
|
|
80
79
|
### C (json-c)
|
|
80
|
+
|
|
81
|
+
**Prerequisites:** C compiler (`gcc`, `clang`, or `tcc`), [json-c](https://github.com/json-c/json-c).
|
|
82
|
+
|
|
81
83
|
Just include the header in your project. There is no separate install step required:
|
|
82
84
|
```c
|
|
83
85
|
#include "csonpath_json-c.h"
|
|
@@ -87,7 +89,23 @@ Make sure to link against `json-c` when compiling:
|
|
|
87
89
|
gcc myapp.c -o myapp $(pkg-config --cflags --libs json-c)
|
|
88
90
|
```
|
|
89
91
|
|
|
92
|
+
### C (yyjson)
|
|
93
|
+
|
|
94
|
+
**Prerequisites:** C compiler (`gcc`, `clang`, or `tcc`), [yyjson](https://github.com/ibireme/yyjson).
|
|
95
|
+
|
|
96
|
+
```c
|
|
97
|
+
#include "csonpath_yyjson.h"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Link against `yyjson` when compiling:
|
|
101
|
+
```sh
|
|
102
|
+
gcc myapp.c -o myapp $(pkg-config --cflags --libs yyjson)
|
|
103
|
+
```
|
|
104
|
+
|
|
90
105
|
### Python
|
|
106
|
+
|
|
107
|
+
**Prerequisites:** Python 3.x.
|
|
108
|
+
|
|
91
109
|
Install from PyPI:
|
|
92
110
|
```sh
|
|
93
111
|
pip install csonpath
|
|
@@ -100,6 +118,23 @@ pip install .
|
|
|
100
118
|
make pip-dev
|
|
101
119
|
```
|
|
102
120
|
|
|
121
|
+
### Rust
|
|
122
|
+
|
|
123
|
+
**Prerequisites:** Rust toolchain.
|
|
124
|
+
|
|
125
|
+
The Rust crate is located in `rust/`. Build and test it with:
|
|
126
|
+
```sh
|
|
127
|
+
cd rust
|
|
128
|
+
cargo build
|
|
129
|
+
cargo test
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
To depend on it from another Rust project:
|
|
133
|
+
```toml
|
|
134
|
+
[dependencies]
|
|
135
|
+
csonpath = { path = "rust" }
|
|
136
|
+
```
|
|
137
|
+
|
|
103
138
|
---
|
|
104
139
|
|
|
105
140
|
## 🛠️ Usage
|
|
@@ -180,6 +215,8 @@ p.update_or_create_callback(dst, my_sync_fn, userdata)
|
|
|
180
215
|
|
|
181
216
|
## 📘 C API Reference
|
|
182
217
|
|
|
218
|
+
The reference below uses the **json-c** backend as an example (`struct json_object *`). All backends expose the same functions with their own value type.
|
|
219
|
+
|
|
183
220
|
```c
|
|
184
221
|
struct csonpath *csonpath_new(const char *path);
|
|
185
222
|
```
|
|
@@ -252,15 +289,117 @@ Free the csonpath object.
|
|
|
252
289
|
|
|
253
290
|
---
|
|
254
291
|
|
|
292
|
+
## 🖥️ CLI
|
|
293
|
+
|
|
294
|
+
A standalone C CLI is available in `cli/csonpath_cli.c`. It links directly against `json-c` and the csonpath C core, so it works without Python.
|
|
295
|
+
|
|
296
|
+
```sh
|
|
297
|
+
make csonpath # build ./csonpath
|
|
298
|
+
make tests-cli # run shell tests
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
It reads JSON from stdin, a file (`-f`), or a string (`-s`) and exposes the library operations through action flags.
|
|
302
|
+
|
|
303
|
+
```sh
|
|
304
|
+
# Get the first match (default)
|
|
305
|
+
echo '{"a": "value", "array": [1, 2, 3]}' | ./csonpath '$.a'
|
|
306
|
+
# => "value"
|
|
307
|
+
|
|
308
|
+
# Find all matches
|
|
309
|
+
echo '{"items": [{"price": 5}, {"price": 15}]}' | ./csonpath -a '$.items[?price > 10]'
|
|
310
|
+
# => [{"price":15}]
|
|
311
|
+
|
|
312
|
+
# One match per line
|
|
313
|
+
echo '{"array": [1, 2, 3]}' | ./csonpath -a -o lines '$.array[*]'
|
|
314
|
+
# => 1
|
|
315
|
+
# => 2
|
|
316
|
+
# => 3
|
|
317
|
+
|
|
318
|
+
# Set or create a value
|
|
319
|
+
echo '{"a": 1}' | ./csonpath --set '42' '$.x.y.z'
|
|
320
|
+
# => {"a":1,"x":{"y":{"z":42}}}
|
|
321
|
+
|
|
322
|
+
# Or with a positional value
|
|
323
|
+
echo '{"a": 1}' | ./csonpath '$.x.y.z' '42'
|
|
324
|
+
|
|
325
|
+
# Remove matches
|
|
326
|
+
echo '{"a": 1, "b": 2}' | ./csonpath -d '$.b'
|
|
327
|
+
# => {"a":1}
|
|
328
|
+
|
|
329
|
+
# Edit a file in place
|
|
330
|
+
./csonpath -f data.json -p -i --set '"2.0"' '$.version'
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Options
|
|
334
|
+
|
|
335
|
+
| Option | Description |
|
|
336
|
+
|---|---|
|
|
337
|
+
| `-a`, `--all` | Return all matches instead of the first one. |
|
|
338
|
+
| `-d`, `--delete` | Remove matches and print the modified JSON. |
|
|
339
|
+
| `--set VALUE` | Set `PATH` to `VALUE` (JSON). |
|
|
340
|
+
| `VALUE` (positional) | Alternative to `--set`. |
|
|
341
|
+
| `-r`, `--raw` | Treat the value as a raw string. |
|
|
342
|
+
| `-i`, `--in-place` | Edit `FILE` in place (requires `--file`). |
|
|
343
|
+
| `--strict` | Exit with an error if `--delete` removes nothing. |
|
|
344
|
+
| `-f FILE`, `--file FILE` | Read JSON from `FILE` instead of stdin. |
|
|
345
|
+
| `-s JSON`, `--string JSON` | Read JSON from a string. |
|
|
346
|
+
| `-j`, `--jq-like` | Allow jq-style paths without a leading `$`. |
|
|
347
|
+
| `-p`, `--pretty` | Pretty-print JSON output. |
|
|
348
|
+
| `-o {json,pretty,raw,lines}` | Output format (default: `json`). |
|
|
349
|
+
| `-e`, `--empty-array` | Return `[]` instead of nothing when `-a` matches nothing. |
|
|
350
|
+
|
|
351
|
+
### Exit codes
|
|
352
|
+
|
|
353
|
+
| Code | Meaning |
|
|
354
|
+
|---|---|
|
|
355
|
+
| `0` | Success. |
|
|
356
|
+
| `1` | No match found, or `--strict` delete found nothing. |
|
|
357
|
+
| `EINVAL` | Usage error, JSON parse error, JSONPath compilation error, or invalid JSON value. |
|
|
358
|
+
| `errno` | I/O error (e.g. `ENOENT`, `EACCES`). |
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## 🧩 Using Multiple Backends
|
|
363
|
+
|
|
364
|
+
You can include more than one csonpath backend in the same translation unit, provided you prefix all but one of them to avoid symbol collisions. Define `CSONPATH_USE_PREFIX` before a backend header to prefix its API with the backend name.
|
|
365
|
+
|
|
366
|
+
For example, to use both json-c and the immutable yyjson backend in the same file:
|
|
367
|
+
|
|
368
|
+
```c
|
|
369
|
+
#define CSONPATH_USE_PREFIX
|
|
370
|
+
#include "csonpath_json-c.h"
|
|
371
|
+
|
|
372
|
+
#undef CSONPATH_USE_PREFIX
|
|
373
|
+
#include "csonpath_yyjson_const.h"
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
To use both yyjson backends (immutable and mutable) together, include the aggregator header:
|
|
377
|
+
|
|
378
|
+
```c
|
|
379
|
+
#include "csonpath_yyjson.h"
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
When using the mutable yyjson backend, assign the document pointer to `backend_ctx` before mutable operations:
|
|
383
|
+
|
|
384
|
+
```c
|
|
385
|
+
struct csonpath *mp = yyjson_mut_csonpath_new("$.a");
|
|
386
|
+
mp->backend_ctx = mdoc;
|
|
387
|
+
yyjson_mut_csonpath_update_or_create(mp, mroot, new_val);
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
255
392
|
## 🔌 Custom Backends
|
|
256
393
|
|
|
257
|
-
csonpath is designed to be backend-agnostic.
|
|
394
|
+
csonpath is designed to be backend-agnostic. The C core manipulates opaque value pointers through a small set of macros, so it can work with any data structure that supports array, object, and scalar semantics.
|
|
258
395
|
|
|
259
|
-
To create a custom backend, define the required macros and types in a header file (similar to `csonpath_json-c.h` or `
|
|
396
|
+
A backend is an adapter that implements those macros for a concrete value representation. To create a custom backend, define the required macros and types in a header file (similar to `csonpath_json-c.h` or `csonpath_yyjson.h`), then include your backend header before `csonpath.h`.
|
|
260
397
|
|
|
261
|
-
|
|
262
|
-
- `csonpath_json-c.h` — json-c
|
|
263
|
-
- `
|
|
398
|
+
Existing backend adapters:
|
|
399
|
+
- `csonpath_json-c.h` — json-c values
|
|
400
|
+
- `csonpath_yyjson.h` — yyjson values
|
|
401
|
+
- `csonpath_python.c` — Python C API values (used by the Python bindings)
|
|
402
|
+
- `rust/csonpath_rust_backend.h` — Rust `serde_json::Value` (used by the Rust crate)
|
|
264
403
|
|
|
265
404
|
---
|
|
266
405
|
|
|
@@ -271,6 +410,12 @@ For more details, see the existing backend implementations:
|
|
|
271
410
|
make tests-c
|
|
272
411
|
```
|
|
273
412
|
|
|
413
|
+
### Rust Tests
|
|
414
|
+
```sh
|
|
415
|
+
cd rust
|
|
416
|
+
cargo test
|
|
417
|
+
```
|
|
418
|
+
|
|
274
419
|
### Python Tests
|
|
275
420
|
```sh
|
|
276
421
|
make tests-py
|
|
@@ -289,7 +434,10 @@ make tests
|
|
|
289
434
|
|---|---|
|
|
290
435
|
| `csonpath.h`, `csonpath_do.h` | Core implementation (header-only style) |
|
|
291
436
|
| `csonpath_json-c.h` | json-c backend |
|
|
437
|
+
| `csonpath_yyjson.h` | yyjson backend |
|
|
292
438
|
| `csonpath_python.c` | Python C extension backend |
|
|
439
|
+
| `rust/` | Rust crate and its C backend adapter |
|
|
440
|
+
| `csonpath_my_fuzzing.h` | Fuzzer helpers (C) |
|
|
293
441
|
| `tests/` | C and Python test suites |
|
|
294
442
|
| `bench/` | Performance benchmarks |
|
|
295
443
|
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://docs.outscale.com/en/userguide/Open-Source-Projects.html)
|
|
6
6
|
|
|
7
|
-
**csonpath** is a partial [JSONPath](https://goessner.net/articles/JsonPath/) implementation in C
|
|
7
|
+
**csonpath** is a partial [JSONPath](https://goessner.net/articles/JsonPath/) implementation in C. It is **backend-agnostic**: the same core engine can query, update, and remove data from any value representation that supports array, object, and scalar semantics—not just JSON.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Out of the box it ships with C backends for [json-c](https://github.com/json-c/json-c) and [yyjson](https://github.com/ibireme/yyjson), plus language bindings for **Python** and **Rust**.
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -53,6 +53,8 @@ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work wi
|
|
|
53
53
|
- [Usage](#-usage)
|
|
54
54
|
- [C API Reference](#-c-api-reference)
|
|
55
55
|
- [Python API Reference](#-python-api-reference)
|
|
56
|
+
- [CLI](#%EF%B8%8F-cli)
|
|
57
|
+
- [Using Multiple Backends](#-using-multiple-backends)
|
|
56
58
|
- [Custom Backends](#-custom-backends)
|
|
57
59
|
- [Running Tests](#-running-tests)
|
|
58
60
|
- [Directory Structure](#-directory-structure)
|
|
@@ -63,12 +65,12 @@ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work wi
|
|
|
63
65
|
|
|
64
66
|
## 📦 Installation
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
- C compiler (`gcc` or `clang`)
|
|
68
|
-
- [json-c](https://github.com/json-c/json-c) library (for C usage)
|
|
69
|
-
- Python 3.x (for Python bindings)
|
|
68
|
+
csonpath is a C library at its core. Pick the instructions for the language you want to use it from.
|
|
70
69
|
|
|
71
70
|
### C (json-c)
|
|
71
|
+
|
|
72
|
+
**Prerequisites:** C compiler (`gcc`, `clang`, or `tcc`), [json-c](https://github.com/json-c/json-c).
|
|
73
|
+
|
|
72
74
|
Just include the header in your project. There is no separate install step required:
|
|
73
75
|
```c
|
|
74
76
|
#include "csonpath_json-c.h"
|
|
@@ -78,7 +80,23 @@ Make sure to link against `json-c` when compiling:
|
|
|
78
80
|
gcc myapp.c -o myapp $(pkg-config --cflags --libs json-c)
|
|
79
81
|
```
|
|
80
82
|
|
|
83
|
+
### C (yyjson)
|
|
84
|
+
|
|
85
|
+
**Prerequisites:** C compiler (`gcc`, `clang`, or `tcc`), [yyjson](https://github.com/ibireme/yyjson).
|
|
86
|
+
|
|
87
|
+
```c
|
|
88
|
+
#include "csonpath_yyjson.h"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Link against `yyjson` when compiling:
|
|
92
|
+
```sh
|
|
93
|
+
gcc myapp.c -o myapp $(pkg-config --cflags --libs yyjson)
|
|
94
|
+
```
|
|
95
|
+
|
|
81
96
|
### Python
|
|
97
|
+
|
|
98
|
+
**Prerequisites:** Python 3.x.
|
|
99
|
+
|
|
82
100
|
Install from PyPI:
|
|
83
101
|
```sh
|
|
84
102
|
pip install csonpath
|
|
@@ -91,6 +109,23 @@ pip install .
|
|
|
91
109
|
make pip-dev
|
|
92
110
|
```
|
|
93
111
|
|
|
112
|
+
### Rust
|
|
113
|
+
|
|
114
|
+
**Prerequisites:** Rust toolchain.
|
|
115
|
+
|
|
116
|
+
The Rust crate is located in `rust/`. Build and test it with:
|
|
117
|
+
```sh
|
|
118
|
+
cd rust
|
|
119
|
+
cargo build
|
|
120
|
+
cargo test
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
To depend on it from another Rust project:
|
|
124
|
+
```toml
|
|
125
|
+
[dependencies]
|
|
126
|
+
csonpath = { path = "rust" }
|
|
127
|
+
```
|
|
128
|
+
|
|
94
129
|
---
|
|
95
130
|
|
|
96
131
|
## 🛠️ Usage
|
|
@@ -171,6 +206,8 @@ p.update_or_create_callback(dst, my_sync_fn, userdata)
|
|
|
171
206
|
|
|
172
207
|
## 📘 C API Reference
|
|
173
208
|
|
|
209
|
+
The reference below uses the **json-c** backend as an example (`struct json_object *`). All backends expose the same functions with their own value type.
|
|
210
|
+
|
|
174
211
|
```c
|
|
175
212
|
struct csonpath *csonpath_new(const char *path);
|
|
176
213
|
```
|
|
@@ -243,15 +280,117 @@ Free the csonpath object.
|
|
|
243
280
|
|
|
244
281
|
---
|
|
245
282
|
|
|
283
|
+
## 🖥️ CLI
|
|
284
|
+
|
|
285
|
+
A standalone C CLI is available in `cli/csonpath_cli.c`. It links directly against `json-c` and the csonpath C core, so it works without Python.
|
|
286
|
+
|
|
287
|
+
```sh
|
|
288
|
+
make csonpath # build ./csonpath
|
|
289
|
+
make tests-cli # run shell tests
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
It reads JSON from stdin, a file (`-f`), or a string (`-s`) and exposes the library operations through action flags.
|
|
293
|
+
|
|
294
|
+
```sh
|
|
295
|
+
# Get the first match (default)
|
|
296
|
+
echo '{"a": "value", "array": [1, 2, 3]}' | ./csonpath '$.a'
|
|
297
|
+
# => "value"
|
|
298
|
+
|
|
299
|
+
# Find all matches
|
|
300
|
+
echo '{"items": [{"price": 5}, {"price": 15}]}' | ./csonpath -a '$.items[?price > 10]'
|
|
301
|
+
# => [{"price":15}]
|
|
302
|
+
|
|
303
|
+
# One match per line
|
|
304
|
+
echo '{"array": [1, 2, 3]}' | ./csonpath -a -o lines '$.array[*]'
|
|
305
|
+
# => 1
|
|
306
|
+
# => 2
|
|
307
|
+
# => 3
|
|
308
|
+
|
|
309
|
+
# Set or create a value
|
|
310
|
+
echo '{"a": 1}' | ./csonpath --set '42' '$.x.y.z'
|
|
311
|
+
# => {"a":1,"x":{"y":{"z":42}}}
|
|
312
|
+
|
|
313
|
+
# Or with a positional value
|
|
314
|
+
echo '{"a": 1}' | ./csonpath '$.x.y.z' '42'
|
|
315
|
+
|
|
316
|
+
# Remove matches
|
|
317
|
+
echo '{"a": 1, "b": 2}' | ./csonpath -d '$.b'
|
|
318
|
+
# => {"a":1}
|
|
319
|
+
|
|
320
|
+
# Edit a file in place
|
|
321
|
+
./csonpath -f data.json -p -i --set '"2.0"' '$.version'
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Options
|
|
325
|
+
|
|
326
|
+
| Option | Description |
|
|
327
|
+
|---|---|
|
|
328
|
+
| `-a`, `--all` | Return all matches instead of the first one. |
|
|
329
|
+
| `-d`, `--delete` | Remove matches and print the modified JSON. |
|
|
330
|
+
| `--set VALUE` | Set `PATH` to `VALUE` (JSON). |
|
|
331
|
+
| `VALUE` (positional) | Alternative to `--set`. |
|
|
332
|
+
| `-r`, `--raw` | Treat the value as a raw string. |
|
|
333
|
+
| `-i`, `--in-place` | Edit `FILE` in place (requires `--file`). |
|
|
334
|
+
| `--strict` | Exit with an error if `--delete` removes nothing. |
|
|
335
|
+
| `-f FILE`, `--file FILE` | Read JSON from `FILE` instead of stdin. |
|
|
336
|
+
| `-s JSON`, `--string JSON` | Read JSON from a string. |
|
|
337
|
+
| `-j`, `--jq-like` | Allow jq-style paths without a leading `$`. |
|
|
338
|
+
| `-p`, `--pretty` | Pretty-print JSON output. |
|
|
339
|
+
| `-o {json,pretty,raw,lines}` | Output format (default: `json`). |
|
|
340
|
+
| `-e`, `--empty-array` | Return `[]` instead of nothing when `-a` matches nothing. |
|
|
341
|
+
|
|
342
|
+
### Exit codes
|
|
343
|
+
|
|
344
|
+
| Code | Meaning |
|
|
345
|
+
|---|---|
|
|
346
|
+
| `0` | Success. |
|
|
347
|
+
| `1` | No match found, or `--strict` delete found nothing. |
|
|
348
|
+
| `EINVAL` | Usage error, JSON parse error, JSONPath compilation error, or invalid JSON value. |
|
|
349
|
+
| `errno` | I/O error (e.g. `ENOENT`, `EACCES`). |
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## 🧩 Using Multiple Backends
|
|
354
|
+
|
|
355
|
+
You can include more than one csonpath backend in the same translation unit, provided you prefix all but one of them to avoid symbol collisions. Define `CSONPATH_USE_PREFIX` before a backend header to prefix its API with the backend name.
|
|
356
|
+
|
|
357
|
+
For example, to use both json-c and the immutable yyjson backend in the same file:
|
|
358
|
+
|
|
359
|
+
```c
|
|
360
|
+
#define CSONPATH_USE_PREFIX
|
|
361
|
+
#include "csonpath_json-c.h"
|
|
362
|
+
|
|
363
|
+
#undef CSONPATH_USE_PREFIX
|
|
364
|
+
#include "csonpath_yyjson_const.h"
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
To use both yyjson backends (immutable and mutable) together, include the aggregator header:
|
|
368
|
+
|
|
369
|
+
```c
|
|
370
|
+
#include "csonpath_yyjson.h"
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
When using the mutable yyjson backend, assign the document pointer to `backend_ctx` before mutable operations:
|
|
374
|
+
|
|
375
|
+
```c
|
|
376
|
+
struct csonpath *mp = yyjson_mut_csonpath_new("$.a");
|
|
377
|
+
mp->backend_ctx = mdoc;
|
|
378
|
+
yyjson_mut_csonpath_update_or_create(mp, mroot, new_val);
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
246
383
|
## 🔌 Custom Backends
|
|
247
384
|
|
|
248
|
-
csonpath is designed to be backend-agnostic.
|
|
385
|
+
csonpath is designed to be backend-agnostic. The C core manipulates opaque value pointers through a small set of macros, so it can work with any data structure that supports array, object, and scalar semantics.
|
|
249
386
|
|
|
250
|
-
To create a custom backend, define the required macros and types in a header file (similar to `csonpath_json-c.h` or `
|
|
387
|
+
A backend is an adapter that implements those macros for a concrete value representation. To create a custom backend, define the required macros and types in a header file (similar to `csonpath_json-c.h` or `csonpath_yyjson.h`), then include your backend header before `csonpath.h`.
|
|
251
388
|
|
|
252
|
-
|
|
253
|
-
- `csonpath_json-c.h` — json-c
|
|
254
|
-
- `
|
|
389
|
+
Existing backend adapters:
|
|
390
|
+
- `csonpath_json-c.h` — json-c values
|
|
391
|
+
- `csonpath_yyjson.h` — yyjson values
|
|
392
|
+
- `csonpath_python.c` — Python C API values (used by the Python bindings)
|
|
393
|
+
- `rust/csonpath_rust_backend.h` — Rust `serde_json::Value` (used by the Rust crate)
|
|
255
394
|
|
|
256
395
|
---
|
|
257
396
|
|
|
@@ -262,6 +401,12 @@ For more details, see the existing backend implementations:
|
|
|
262
401
|
make tests-c
|
|
263
402
|
```
|
|
264
403
|
|
|
404
|
+
### Rust Tests
|
|
405
|
+
```sh
|
|
406
|
+
cd rust
|
|
407
|
+
cargo test
|
|
408
|
+
```
|
|
409
|
+
|
|
265
410
|
### Python Tests
|
|
266
411
|
```sh
|
|
267
412
|
make tests-py
|
|
@@ -280,7 +425,10 @@ make tests
|
|
|
280
425
|
|---|---|
|
|
281
426
|
| `csonpath.h`, `csonpath_do.h` | Core implementation (header-only style) |
|
|
282
427
|
| `csonpath_json-c.h` | json-c backend |
|
|
428
|
+
| `csonpath_yyjson.h` | yyjson backend |
|
|
283
429
|
| `csonpath_python.c` | Python C extension backend |
|
|
430
|
+
| `rust/` | Rust crate and its C backend adapter |
|
|
431
|
+
| `csonpath_my_fuzzing.h` | Fuzzer helpers (C) |
|
|
284
432
|
| `tests/` | C and Python test suites |
|
|
285
433
|
| `bench/` | Performance benchmarks |
|
|
286
434
|
|