How to replace json from another json in C# using NewtonSoft?

Viewed 700

I have two JSON objects -

json1 = {
    "payload": {
        "firstName": "John",
        "lastName": "Doe",
        "code": "test1",
        "arrayProp1": [1, 2, 3],
        "arrayProp2": [{
                "prop1": "value1",
                "prop2": "value2"
            },
            {
                "prop1": "2_value1",
                "prop2": "2_value2"
            }
        ]
    }
}

json2 = {
    "payload": {
        "code": "newCode",
        "arrayProp1": [3,4],
        "arrayProp2": [{
                "prop1": "newValue1",
                "prop2": "newValue2"
            }
        ]
    }
}

If I use the built-in merge (json1.Merge(json2)) the result obtained is -

result : {
    "payload": {
        "firstName": "John",
        "lastName": "Doe",
        "code": "newCode",
        "arrayProp1": [1, 2, 3, 3, 4],
        "arrayProp2": [{
                "prop1": "value1",
                "prop2": "value2"
            },
            {
                "prop1": "newValue1",
                "prop2": "newValue2"
            },
            {
                "prop1": "2_value1",
                "prop2": "2_value2"
            }
        ]
    }
}

Expected result -

{
    "payload": {
        "firstName": "John",
        "lastName": "Doe",
        "code": "newCode",
        "arrayProp1": [3, 4],
        "arrayProp2": [{
            "prop1": "newValue1",
            "prop2": "newValue2"
        }]
    }
}

I want to replace the parent property values of json1 based on values provided in json2.

I tried to write a function and this is the current version I have -

string Merge(string req1, string req2) {
    try
                {
                    JObject json1 = JObject.Parse(req1);
                    JObject json2 = JObject.Parse(req2);                
    
                    foreach (var a in json2.DescendantsAndSelf())
                    {
                        if (a is JObject obj)
                        {
                            foreach (var prop in obj.Properties())
                            {
                                if(json1.SelectTokens(prop.Path).Any())
                                {
                                    json1[prop.Path] = prop.Value;
                                }
                            }
                        }
                        
                    }
                    req1 = json1.ToString();
                }
                catch(Exception ex)
                {
                    //do nothing
                }
return req1; }

There are 2 problems here -

  1. "payload" is identified as property and json1 is replaced fully by json2 because of which I lose some of its properties.
  2. After being replaced, when the loop continues to run, say property 'code' is to be updated, then the property path is payload.code, so on the line json1[prop.path] = prop.Value, instead of updating the existing code in the payload, it creates a new property called payload.code with value "newcode"

The final result of the code above is -

{
    "payload": {
        "code": "newCode",
        "arrayProp1": [3, 4],
        "arrayProp2": [{
            "prop1": "newValue1",
            "prop2": "newValue2"
        }],
        "payload.code": "newCode",
        "payload.arrayProp1": [3, 4],
        "payload.arrayProp2": [{
            "prop1": "newValue1",
            "prop2": "newValue2"
        }],
        "payload.arrayProp1[0].prop1": "newValue1",
        "payload.arrayProp1[0].prop2": "newValue2"
    }
}

Can someone please help me with this?

1 Answers

Your requirement is that array contents are replaced rather than concatenated when merging two JSON objects with JContainer.Merge(). You can achieve this via the JsonMergeSettings.MergeArrayHandling setting, which has the following values:

Concat   0   Concatenate arrays.
Union    1   Union arrays, skipping items that already exist.
Replace  2   Replace all array items.
Merge    3   Merge array items together, matched by index. 

Specifically MergeArrayHandling.Replace will work as required:

json1.Merge(json2, new JsonMergeSettings 
            { 
                MergeArrayHandling = MergeArrayHandling.Replace 
            });

Demo fiddle here.

Related