aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/apiref.rst6
-rw-r--r--src/jansson.def1
-rw-r--r--src/jansson.h1
-rw-r--r--src/value.c20
-rw-r--r--test/suites/api/test_object.c52
5 files changed, 80 insertions, 0 deletions
diff --git a/doc/apiref.rst b/doc/apiref.rst
index 3c4fa47..07962d1 100644
--- a/doc/apiref.rst
+++ b/doc/apiref.rst
@@ -708,6 +708,12 @@ allowed in object keys.
.. versionadded:: 2.3
+.. function:: int json_object_update_recursive(json_t *object, json_t *other)
+
+ Like :func:`json_object_update()`, but object values in *other* are
+ recursively merged with the corresponding values in *object* if they are also
+ objects, instead of overwriting them. Returns 0 on success or -1 on error.
+
.. function:: json_object_foreach(object, key, value)
Iterate over every key-value pair of ``object``, running the block
diff --git a/src/jansson.def b/src/jansson.def
index ed72829..55b39c8 100644
--- a/src/jansson.def
+++ b/src/jansson.def
@@ -41,6 +41,7 @@ EXPORTS
json_object_update
json_object_update_existing
json_object_update_missing
+ json_object_update_recursive
json_object_iter
json_object_iter_at
json_object_iter_next
diff --git a/src/jansson.h b/src/jansson.h
index b2b980b..337ddac 100644
--- a/src/jansson.h
+++ b/src/jansson.h
@@ -199,6 +199,7 @@ int json_object_clear(json_t *object);
int json_object_update(json_t *object, json_t *other);
int json_object_update_existing(json_t *object, json_t *other);
int json_object_update_missing(json_t *object, json_t *other);
+int json_object_update_recursive(json_t *object, json_t *other);
void *json_object_iter(json_t *object);
void *json_object_iter_at(json_t *object, const char *key);
void *json_object_key_to_iter(const char *key);
diff --git a/src/value.c b/src/value.c
index 7a000f8..1996232 100644
--- a/src/value.c
+++ b/src/value.c
@@ -214,6 +214,26 @@ int json_object_update_missing(json_t *object, json_t *other)
return 0;
}
+int json_object_update_recursive(json_t *object, json_t *other)
+{
+ const char *key;
+ json_t *value;
+
+ if(!json_is_object(object) || !json_is_object(other))
+ return -1;
+
+ json_object_foreach(other, key, value) {
+ json_t *v = json_object_get(object, key);
+
+ if(json_is_object(v) && json_is_object(value))
+ json_object_update_recursive(v, value);
+ else
+ json_object_set_nocheck(object, key, value);
+ }
+
+ return 0;
+}
+
void *json_object_iter(json_t *json)
{
json_object_t *object;
diff --git a/test/suites/api/test_object.c b/test/suites/api/test_object.c
index 521ca81..ac10936 100644
--- a/test/suites/api/test_object.c
+++ b/test/suites/api/test_object.c
@@ -207,6 +207,57 @@ static void test_conditional_updates()
json_decref(other);
}
+static void test_recursive_updates()
+{
+ json_t *invalid, *object, *other;
+
+ invalid = json_integer(42);
+
+ object = json_pack("{sis{si}}", "foo", 1, "bar", "baz", 2);
+ other = json_pack("{sisisi}", "foo", 3, "bar", 4, "baz", 5);
+
+ if(!json_object_update_recursive(invalid, other))
+ fail("json_object_update_recursive accepted non-object argument");
+
+ json_decref(invalid);
+
+ if(json_object_update_recursive(object, other))
+ fail("json_object_update_recursive failed");
+
+ if(json_object_size(object) != 3)
+ fail("invalid size after update");
+
+ if(json_integer_value(json_object_get(object, "foo")) != 3)
+ fail("json_object_update_recursive failed to update existing key");
+
+ if(json_integer_value(json_object_get(object, "bar")) != 4)
+ fail("json_object_update_recursive failed to overwrite object");
+
+ if(json_integer_value(json_object_get(object, "baz")) != 5)
+ fail("json_object_update_recursive didn't add new item");
+
+ json_decref(object);
+ json_decref(other);
+
+ object = json_pack("{sis{si}}", "foo", 1, "bar", "baz", 2);
+ other = json_pack("{s{si}}", "bar", "baz", 3);
+
+ if(json_object_update_recursive(object, other))
+ fail("json_object_update_recursive failed");
+
+ if(json_object_size(object) != 2)
+ fail("invalid size after update");
+
+ if(!json_object_get(object, "foo"))
+ fail("json_object_update_recursive removed existing key");
+
+ if(json_integer_value(json_object_get(json_object_get(object, "bar"), "baz")) != 3)
+ fail("json_object_update_recursive failed to update nested value");
+
+ json_decref(object);
+ json_decref(other);
+}
+
static void test_circular()
{
json_t *object1, *object2;
@@ -667,6 +718,7 @@ static void run_tests()
test_update();
test_set_many_keys();
test_conditional_updates();
+ test_recursive_updates();
test_circular();
test_set_nocheck();
test_iterators();