9

I have two JToken's that represent JSON arrays of objects and I would like to merge them. JToken has a method Concat but it produces null as result when I try to use it.

Action<JToken> Ok = (x) =>
{
    Debug.WriteLine(x);
    /* outputs
    [
      {
        "id": 1,
      },
      {
        "id": 2,
      }
    ]
    */

    x = (x).Concat<JToken>(x) as JToken;
    Debug.WriteLine(x); // null
};

How can I make it work?

4
  • Can you please show how you use the Concat method by providing your code + sample data? Commented Jan 2, 2013 at 11:25
  • @GameScripting well the code is right here in question, specifically the line x = (x).Concat<JToken>(x) as JToken. UPD: can you see the code block I've provided? Commented Jan 2, 2013 at 11:27
  • Oh I'm sorry, you're absolutly right. Commented Jan 2, 2013 at 11:29
  • I don't know Json.Net, but concat is usually for joining two strings. I would expect a merge or union function would be more applicable. Does such a thing exist? Commented Jan 2, 2013 at 11:53

3 Answers 3

34

Use JContainer.Merge() with MergeArrayHandling.Concat.

This is available starting with Json.NET 6 Release 4. So if your arrays are in a JContainer (e.g. a JObject), this is a simple and robust solution.

Example:

JObject o1 = JObject.Parse(@"{
  'FirstName': 'John',
  'LastName': 'Smith',
  'Enabled': false,
  'Roles': [ 'User' ]
}");
JObject o2 = JObject.Parse(@"{
  'Enabled': true,
  'Roles': [ 'Operator', 'Admin' ]
}");

o1.Merge(o2, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Concat });

string json = o1.ToString();
// {
//   "FirstName": "John",
//   "LastName": "Smith",
//   "Enabled": true,
//   "Roles": [
//     "User",
//     "Operator",
//     "Admin"
//   ]
// }
Sign up to request clarification or add additional context in comments.

Comments

9
JToken.FromObject(x.Concat(x))

Comments

2

I needed same, here's what I came up with

https://github.com/MrAntix/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Linq/MergeExtensions.cs

public static void MergeInto(
    this JContainer left, JToken right, MergeOptions options)
{
    foreach (var rightChild in right.Children<JProperty>())
    {
        var rightChildProperty = rightChild;
        var leftPropertyValue = left.SelectToken(rightChildProperty.Name);

        if (leftPropertyValue == null)
        {
            // no matching property, just add 
            left.Add(rightChild);
        }
        else
        {
            var leftProperty = (JProperty) leftPropertyValue.Parent;

            var leftArray = leftPropertyValue as JArray;
            var rightArray = rightChildProperty.Value as JArray;
            if (leftArray != null && rightArray != null)
            {
                switch (options.ArrayHandling)
                {
                    case MergeOptionArrayHandling.Concat:

                        foreach (var rightValue in rightArray)
                        {
                            leftArray.Add(rightValue);
                        }

                        break;
                    case MergeOptionArrayHandling.Overwrite:

                        leftProperty.Value = rightChildProperty.Value;
                        break;
                }
            }

            else
            {
                var leftObject = leftPropertyValue as JObject;
                if (leftObject == null)
                {
                    // replace value
                    leftProperty.Value = rightChildProperty.Value;
                }

                else
                    // recurse object
                    MergeInto(leftObject, rightChildProperty.Value, options);
            }
        }
    }
}

1 Comment

left.SelectToken(rightChildProperty.Name); should be left[rightChildProperty.Name]; ... at least in my case (4.0 R8)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.