diff --git a/lib/cJSON.c b/lib/cJSON.c index 6428703e51f..416fc979c73 100644 --- a/lib/cJSON.c +++ b/lib/cJSON.c @@ -2528,3 +2528,73 @@ void cJSON_Minify(char *json) /* and null-terminate. */ *into = '\0'; } + +cjbool cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +cjbool cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + + +static cJSON *merge_patch(cJSON *target, const cJSON * const patch) +{ + cJSON *patch_child = NULL; + + if (!cJSON_IsObject(patch)) + { + /* scalar value, array or NULL, just duplicate */ + cJSON_Delete(target); + return cJSON_Duplicate(patch, 1); + } + + if (!cJSON_IsObject(target)) + { + cJSON_Delete(target); + target = cJSON_CreateObject(); + } + + patch_child = patch->child; + while (patch_child != NULL) + { + if (cJSON_IsNull(patch_child)) + { + cJSON_DeleteItemFromObject(target, patch_child->string); + } + else + { + cJSON *replace_me = NULL; + cJSON *replacement = NULL; + + replace_me = cJSON_DetachItemFromObject(target, patch_child->string); + + replacement = merge_patch(replace_me, patch_child); + if (replacement == NULL) + { + return NULL; + } + + cJSON_AddItemToObject(target, patch_child->string, replacement); + } + patch_child = patch_child->next; + } + return target; +} + +cJSON * cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch) +{ + return merge_patch(target, patch); +} diff --git a/lib/cJSON.h b/lib/cJSON.h index 627bc794d7b..700cf1847ff 100644 --- a/lib/cJSON.h +++ b/lib/cJSON.h @@ -258,6 +258,8 @@ int cJSON_NumberIsInt(cJSON *item); /* Macro for iterating over an array */ #define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next) +cJSON * cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch); + #ifdef __cplusplus } #endif diff --git a/modules/json/README b/modules/json/README index 29cd6ec2f1c..0f0bc5499bd 100644 --- a/modules/json/README +++ b/modules/json/README @@ -24,6 +24,9 @@ JSON Module 1.5. Exported Functions 1.5.1. json_link($json(dest_id), $json(source_id)) + 1.5.2. + json_merge(main_json_var,patch_json_var,output + _var)) 2. Contributors @@ -57,6 +60,7 @@ JSON Module 1.12. Adding a json to another json 1.13. Creating a reference 1.14. [LOGICAL ERROR] Creating a circular reference + 1.15. Using json_merge Chapter 1. Admin Guide @@ -406,6 +410,29 @@ xlog("\nTest link :\n$json(stub)\n$json(b)\n\n"); ... +1.5.2. json_merge(main_json_var,patch_json_var,output_var)) + + The function can be used to patch merge patch_json_var into + main_json_var and the output will be populated into the + output_var + + Example 1.15. Using json_merge +... + +$json(val1) := "{}"; +$json(val1/test1) = "test_val1"; +$json(val1/common_val) = "val_from1"; + +$json(val2) := "{}"; +$json(val2/test2) = "test_val2"; +$json(val1/common_val) = "val_from2"; + +json_merge($json(val1),$json(val2),$var(merged_json)); +xlog("we merged and got $var(merged_json) \n"); +# will print : +# we merged and got {"test1":"test_val1","common_val":"val_from2","test2 +":"test_val2"} + Chapter 2. Contributors 2.1. By Commit Statistics diff --git a/modules/json/doc/json_admin.xml b/modules/json/doc/json_admin.xml index ea4b2b7d817..b73d7159436 100644 --- a/modules/json/doc/json_admin.xml +++ b/modules/json/doc/json_admin.xml @@ -539,12 +539,36 @@ xlog("\nTest link :\n$json(stub)\n$json(b)\n\n"); - - +
+ + <function moreinfo="none"> + json_merge(main_json_var,patch_json_var,output_var)) + </function> + + + The function can be used to patch merge patch_json_var into main_json_var and the output will be populated into the output_var + - + + Using json_merge + +... +$json(val1) := "{}"; +$json(val1/test1) = "test_val1"; +$json(val1/common_val) = "val_from1"; +$json(val2) := "{}"; +$json(val2/test2) = "test_val2"; +$json(val1/common_val) = "val_from2"; +json_merge($json(val1),$json(val2),$var(merged_json)); +xlog("we merged and got $var(merged_json) \n"); +# will print : +# we merged and got {"test1":"test_val1","common_val":"val_from2","test2":"test_val2"} + + +
+ diff --git a/modules/json/json.c b/modules/json/json.c index 0e257819c31..1eae8735c1b 100644 --- a/modules/json/json.c +++ b/modules/json/json.c @@ -118,7 +118,7 @@ static int pv_parse_json_index(pv_spec_p sp, const str *in); static pv_json_t * get_pv_json (pv_param_t* ); static int pv_add_json ( pv_param_t* , json_t * ); static int expand_tag_list( struct sip_msg*, json_tag *); - +static int w_merge_json(struct sip_msg *msg, str *j1, str* j2, pv_spec_t *res); static const cmd_export_t cmds[]={ {"json_link", (cmd_function)json_bind, { @@ -126,6 +126,12 @@ static const cmd_export_t cmds[]={ {CMD_PARAM_VAR, fixup_json_bind, 0}, {0,0,0}}, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE| LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, + {"json_merge",(cmd_function)w_merge_json, { + {CMD_PARAM_STR, 0, 0}, + {CMD_PARAM_STR, 0, 0}, + {CMD_PARAM_VAR, 0, 0}, + {0,0,0}}, + ALL_ROUTES}, {0,0,{{0,0,0}},0} }; @@ -1068,3 +1074,60 @@ void mod_destroy(void) { } + +int w_merge_json(struct sip_msg *msg, str *j1, str* j2, pv_spec_t *res) +{ + cJSON *in1, *in2, *out; + char *p; + pv_value_t pv_val; + + in1 = cJSON_Parse(j1->s); + if (!in1) { + LM_ERR("Failed to parse first param \n"); + return -1; + } + + in2 = cJSON_Parse(j2->s); + if (!in2) { + LM_ERR("Failed to parse second param \n"); + cJSON_Delete(in1); + return -1; + } + + out = cJSONUtils_MergePatch(in1,in2); + if (!out) { + LM_ERR("Failed to merge the two jsons \n"); + cJSON_Delete(in1); + cJSON_Delete(in2); + return -1; + } + + p = cJSON_Print(out); + if (!p) { + LM_ERR("Failed to merge the two jsons \n"); + cJSON_Delete(in1); + cJSON_Delete(in2); + return -1; + } + + cJSON_Minify(p); + + pv_val.flags = PV_VAL_STR; + pv_val.rs.s = p; + pv_val.rs.len = strlen(p); + + + if (pv_set_value( msg, res, 0, &pv_val) != 0) { + LM_ERR("SET output value failed \n"); + pkg_free(p); + cJSON_Delete(in1); + cJSON_Delete(in2); + return -1; + } + + pkg_free(p); + cJSON_Delete(in1); + cJSON_Delete(in2); + + return 1; +}