Search code examples
c#linqjson.net

Create Newtonsoft.Json.Linq.JArray from another array with different structure


I have first Newtonsoft.Json.Linq.JArray with this structure:

[
  {
    "Fields": [
      {
        "Value": "child",
        "Key": "Relationship"
      },
      {
        "Value": "Alex",
        "Key": "FirstName"
      }
    ]
  }
]

And another Newtonsoft.Json.Linq.JArray:

[
  {
    "Relationship": "child",
    "FirstName": "Alex"
  }
]

Is it real to turn second one to the first one? Have not much experience in c# and Linq.


Solution

  • To transform your first JSON sample to your second, you may use LINQ to JSON as follows:

    // Parse (or load from a stream) the incoming JSON as a JArray
    var array = JArray.Parse(jsonString);
    
    // For each object in the array, query they Key/Value properties of each Fields[*] object and turn then into a single JPropery, 
    // then add those properties to a new JObject
    var query = array.Select(i => 
        new JObject(i.SelectTokens("Fields[*]").Select(o => new JProperty((string)o["Key"], o["Value"]))));
    
    // Create a new JArray from the query
    var newArray = new JArray(query);
    

    The trickest part is here:

    i => new JObject(i.SelectTokens("Fields[*]").Select(o => 
        new JProperty((string)o["Key"], o["Value"])))
    

    This expression:

    1. Uses SelectTokens() to query all Fields[*] objects in the root array item;
    2. then gets the "Key" and "Value" properties of each object;
    3. then turns them into a single JProperty;
    4. and finally combines the JProperty instances into a single JObject.

    Note that, if one of the [*].Fields[*].Key properties is missing, the code above will throw an exception, so you might want to check for that.

    Demo fiddle #1 here.

    Similarly, to transform your second sample to your first, you can do:

    var query = array
        .OfType<JObject>()
        .Select(o => 
               new JObject
               {
                   {"Fields", new JArray(o.Properties().Select(p => new JObject{{"Key", p.Name}, {"Value", p.Value}}))},
               });
    
    var newArray = new JArray(query);
    

    Here I am using C#'s dictionary collection initializer syntax to initialize my JObject instances, which I can do because JObject implements IDictionary<string, JToken>.

    Demo fiddle #2 here.