Skip to content

Commit

Permalink
Merge pull request #3554 from vladpaiu/json_merge_func
Browse files Browse the repository at this point in the history
Add json_merge script function
  • Loading branch information
bogdan-iancu authored Jan 14, 2025
2 parents 6703f6d + aaebd05 commit 7a12c9b
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 4 deletions.
70 changes: 70 additions & 0 deletions lib/cJSON.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 2 additions & 0 deletions lib/cJSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions modules/json/README
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
30 changes: 27 additions & 3 deletions modules/json/doc/json_admin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -539,12 +539,36 @@ xlog("\nTest link :\n$json(stub)\n$json(b)\n\n");

</section>


</section>
<section id="func_json_merge" xreflabel="json_merge()">
<title>
<function moreinfo="none">
json_merge(main_json_var,patch_json_var,output_var))
</function>
</title>
<para>
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
</para>


<example>
<title>Using json_merge </title>
<programlisting format="linespecific">
...

$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"}
</programlisting>
</example>
</section>
</section>
</chapter>

65 changes: 64 additions & 1 deletion modules/json/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,20 @@ 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, {
{CMD_PARAM_VAR, fixup_json_bind, 0},
{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}
};

Expand Down Expand Up @@ -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;
}

0 comments on commit 7a12c9b

Please sign in to comment.