Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ print(o.find_first(d)) # Output: "value"

#### Avaible methodes:
- `CsonPath(path)`: create a new csonpath object.
- `CsonPath(path, return_empty_array)`: Create a new csonpath object and return an empty list instead of None (like jsonpath-ng).
- `OBJ.find_first(self, json)`: take a json, return first found occurrence.
- `OBJ.find_all(self, json)`: take a json, return all found occurrence in a list.
- `OBJ.remove(self, json)`: take a json, remove all found occurrence from it.
Expand Down
7 changes: 5 additions & 2 deletions csonpath.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ struct csonpath {
int regex_cnt;
regex_t *regexs;
#endif
int return_empty_array;
};

struct csonpath_child_info {
Expand Down Expand Up @@ -204,6 +205,9 @@ static inline int csonpath_init(struct csonpath cjp[static 1],
if (!cjp->path || !cjp->inst_lst) {
return -ENOMEM;
}

cjp->return_empty_array = 0;

return 0;
}

Expand Down Expand Up @@ -845,15 +849,14 @@ need_reloop_in = 0;
#define CSONPATH_DO_FILTER_FIND CSONPATH_DO_FIND_ALL

#define CSONPATH_DO_FIND_ALL_OUT \
if (!nb_res) { \
if (!cjp->return_empty_array && !nb_res) { \
return CSONPATH_NONE_FOUND_RET; \
} \
return ret_ar;

#define CSONPATH_DO_EXTRA_ARGS_IN , ret_ar
#define CSONPATH_DO_EXTRA_DECLATION , CSONPATH_FIND_ALL_RET ret_ar


#include "csonpath_do.h"

/* Delete */
Expand Down
2 changes: 1 addition & 1 deletion csonpath_do.h
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ static CSONPATH_DO_RET_TYPE csonpath_do_(struct csonpath cjp[static 1],

CSONPATH_DO_POST_OPERATION;

return ret;
return ret;
}

#ifndef CSONPATH_NO_UNDEF
Expand Down
81 changes: 53 additions & 28 deletions csonpath_python.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <Python.h>
#include <stdio.h>

#define CSONPATH_JSON PyObject *

Expand Down Expand Up @@ -207,42 +208,64 @@ typedef struct {


static PyObject *PyCsonPath_new(PyTypeObject *subtype, PyObject* args,
PyObject* dont_care)
PyObject* kwargs)
{
PyCsonPathObject *self = (PyCsonPathObject *)subtype->tp_alloc(subtype, 0);
const char *s;

if (!self)
BAD_ARG();

if (!PyArg_ParseTuple(args, "s", &s))
BAD_ARG();

struct csonpath *ret = malloc(sizeof *ret);
if (!self)
return PyErr_NoMemory();

if (csonpath_init(ret, s) < 0)
return PyErr_NoMemory();

if (csonpath_compile(ret) < 0) {
char *error = ret->compile_error;
PyErr_Format(PyExc_ValueError, "compilation fail %s", error ? error : "(unknow error)");
csonpath_destroy(ret);
return NULL;
}
self->cp = ret;

return (PyObject *)self;
static char *kwlist[] = {"path", "return_empty_array", NULL};
PyCsonPathObject *self = (PyCsonPathObject *)subtype->tp_alloc(subtype, 0);
const char *s;
int return_empty_array = 0;
struct csonpath *ret = NULL;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PyObject *py_ret = NULL;

PyObject *py_ret = NULL;

if (!self)
BAD_ARG();

if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|p", kwlist,
&s, &return_empty_array)) {
goto error;
}

ret = malloc(sizeof *ret);
if (!ret) {
PyErr_NoMemory();
goto error;
}

if (csonpath_init(ret, s) < 0) {
py_ret = PyErr_NoMemory();
goto error_free_ret;
}

ret->return_empty_array = return_empty_array;

if (csonpath_compile(ret) < 0) {
char *err_str = ret->compile_error;
PyErr_Format(PyExc_ValueError, "compilation fail %s",
err_str ? err_str : "(unknow error)");
goto error_destroy_ret;
}

self->cp = ret;
return (PyObject *)self;

error_destroy_ret:
csonpath_destroy(ret);
error_free_ret:
free(ret);
error:
Py_DECREF(self);
return py_ret;
}

static PyObject *find_all(PyCsonPathObject *self, PyObject* args)
{
PyObject *json;

if (!PyArg_ParseTuple(args, "O", &json))
BAD_ARG();
BAD_ARG();

PyObject *ret = csonpath_find_all(self->cp, json);

return ret;
}

Expand All @@ -251,8 +274,10 @@ static PyObject *find_first(PyCsonPathObject *self, PyObject* args)
PyObject *json;

if (!PyArg_ParseTuple(args, "O", &json))
BAD_ARG();
BAD_ARG();

PyObject *ret = csonpath_find_first(self->cp, json);

Py_INCREF(ret);
return ret;
}
Expand Down
22 changes: 22 additions & 0 deletions tests/json-c/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ int main(void)
ret = csonpath_find_first(&p, jobj);
assert(ret);

assert(csonpath_set_path(&p, "$.array[?a==9999]") == 0);
p.return_empty_array = 0;
ret = csonpath_find_first(&p, jobj);
assert(ret == NULL);

p.return_empty_array = 1;
ret = csonpath_find_first(&p, jobj);
assert(ret == NULL);
p.return_empty_array = 0;

csonpath_set_path(&p, "$.array[?(@[\"a\"]==\"la\")]");
ret = csonpath_find_first(&p, jobj);
assert(ret);
Expand Down Expand Up @@ -138,6 +148,18 @@ int main(void)
assert(!csonpath_set_path(&p, "$.ha[?(@[\"i\"][\"h\"] =~ \"gan\")][\"i\"][\"h\"]"));
assert(csonpath_find_first(&p, jobj));

assert(!csonpath_set_path(&p, "$.ha[?i.h=~\"no_match_xyz\"]"));
p.return_empty_array = 1;
ret = csonpath_find_all(&p, jobj);
assert(ret != NULL);
assert(json_object_is_type(ret, json_type_array));
assert(json_object_array_length(ret) == 0);
json_object_put(ret);
p.return_empty_array = 0;
ret = csonpath_find_all(&p, jobj);
assert(ret == NULL);
json_object_put(ret);

json_object_put(jobj);

csonpath_destroy(&p);
Expand Down
27 changes: 27 additions & 0 deletions tests/python/test_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@ def test_simple_filter():

assert ret == ["Leodagan"], dict

dict = {"ha": [{"h": {"h1": "Leodagan"}}, {"h": "George"}]}
cp = csonpath.CsonPath('$.ha[?h.h1 =~ "Assim"].h.h1')
ret = cp.find_all(dict)

assert ret is None

dict = {"ha": [{"h": {"h1": "Leodagan"}}, {"h": "George"}]}
cp = csonpath.CsonPath('$.ha[?h.h1 =~ "Assim"].h.h1', return_empty_array=True)
ret = cp.find_all(dict)

assert ret == []

cp = csonpath.CsonPath('$.ha[?h.h1 =~ "Assim"].h.h1', True)
ret = cp.find_all(dict)

assert ret == []


def test_multiple_filters():
# cf. https://github.com/h2non/jsonpath-ng?tab=readme-ov-file#extensions, last example of filter
Expand All @@ -66,3 +83,13 @@ def test_multiple_filters():
cp = csonpath.CsonPath('$.knights[?laterality = "left" & sub.a = 10].sub')
ret = cp.find_first(dict)
assert ret == {"a": 10}

cp = csonpath.CsonPath('$.knights[?(@.name == "Assim")].laterality')
ret = cp.find_first(dict)

assert ret is None

cp = csonpath.CsonPath('$.knights[?(@.name == "Assim")].laterality', return_empty_array=True)
ret = cp.find_first(dict)

assert ret is None
5 changes: 5 additions & 0 deletions tests/python/test_needrefacto.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ def test_torefacto():

assert r is None

o = csonpath.CsonPath("$.C", True)
r = o.find_first(d)

assert r is None

o = csonpath.CsonPath("$[*]")
r = o.find_all(d)

Expand Down
Loading