Does C# have a library for parsing multi-level cas

2019-01-26 07:39发布

Is there a library (C# preferred) to resolve what I would call multi-level cascading JSON?

Here is an example of what I mean: (Pseudocode/C#)

var json1 = @"{
    ""firstName"": ""John"",
    ""lastName"": ""Smith""
    }";

var json2 = @"{
    ""firstName"": ""Albert""
    }";

var json3 = @"{
    ""phone"": ""12345""
    }";

var cascadingJSON = JSON.Cascade(json1, json2, json3);

Result (Same behavior as CSS)

{
    "firstName"": "Albert", /*Overridden*/
    "lastName"": "Smith", /*Inherited*/
    "phone"": "12345"   }"; /*Added*/
}

Edit 1 - More complex example

const string json1 =
                @"{
                     ""firstName"": ""John"",
                     ""lastName"": ""Smith"",
                     ""age"": 25,
                     ""address"": 
                     {
                         ""streetAddress"": ""21 2nd Street"",
                         ""city"": ""New York"",
                         ""state"": ""NY"",
                         ""postalCode"": ""10021""
                     },
                     ""phoneNumber"": 
                     [
                         {
                           ""type"": ""home"",
                           ""number"": ""212 555-1234""
                         },
                         {
                           ""type"": ""fax"",
                           ""number"": ""646 555-4567""
                         }
                     ]
                 }";

            const string json2 =
                @"{
                     ""firstName"": ""John2"",
                     ""lastName"": ""robert"",
                     ""age"": 25,
                     ""address"": 
                     {
                         ""state"": ""FL"",
                     },
                     ""phoneNumber"": 
                     [
                         {
                           ""type"": ""fax"",
                           ""number"": ""222 222-2222""
                         },
                         {
                           ""type"": ""iphone"",
                           ""number"": ""111 111-1111""
                         }
                     ]
                 }";

            const string json3 =
                @"{
                     ""firstName"": ""John3"",
                     ""father"": ""guy""
                 }";

            const string expectedResult =
                @"{
                     ""firstName"": ""John3"",
                     ""lastName"": ""robert"",
                     ""age"": 25,
                     ""father"": ""guy"",
                     ""address"": 
                     {
                         ""streetAddress"": ""21 2nd Street"",
                         ""city"": ""New York"",
                         ""state"": ""FL"",
                         ""postalCode"": ""10021""
                     },
                     ""phoneNumber"": 
                     [
                         {
                           ""type"": ""home"",
                           ""number"": ""212 555-1234""
                         },
                         {
                           ""type"": ""fax"",
                           ""number"": ""222 222-2222""
                         },
                         {
                           ""type"": ""iphone"",
                           ""number"": ""111 111-1111""
                         }
                     ]
                 }";

Edit 2

After thinking a bit more about the requirements I see that the more complex example could never work as is. The Cascading function would not be able to know if, by example, a certain phone number has been modified or if it is new one. To make it work, each sub-entity should have a unique identifier.

2条回答
太酷不给撩
2楼-- · 2019-01-26 07:57

This is super easy using the excellent JSON.NET library. This method combines objects with properties that are are strings, numbers, or objects.

public static string Cascade(params string[] jsonArray)
{
    JObject result = new JObject();
    foreach (string json in jsonArray)
    {
        JObject parsed = JObject.Parse(json);
        foreach (var property in parsed)
            result[property.Key] = property.Value;
    }
    return result.ToString();
}

Result, given your example:

{
  "firstName": "Albert",
  "lastName": "Smith",
  "phone": "12345"
}

Edit in response to your updated question:

By adjusting this solution to work recursively, you can merge child objects. The following example will match your expected results (except for the array). You will be able to easily extend this solution to merge arrays (JArray) in a manner similar to how it merges objects (JObject).

public static string Cascade(params string[] jsonArray)
{
    JObject result = new JObject();
    foreach (string json in jsonArray)
    {
        JObject parsed = JObject.Parse(json);
        Merge(result, parsed);
    }
    return result.ToString();
}

private static void Merge(JObject receiver, JObject donor)
{
    foreach (var property in donor)
    {
        JObject receiverValue = receiver[property.Key] as JObject;
        JObject donorValue = property.Value as JObject;
        if (receiverValue != null && donorValue != null)
            Merge(receiverValue, donorValue);
        else
            receiver[property.Key] = property.Value;
    }
}
查看更多
太酷不给撩
3楼-- · 2019-01-26 08:03

Not that I know of. For the simple case, you can use any JSON library, then merge the dictionaries with a solution like this one. E.g. using Newtonsoft/Json.NET:

Dictionary<String, String> dict1, dict2, dict3, merged;
dict1 = JsonConvert.DeserializeObject<Dictionary<string,string>>(json1);
dict2 = JsonConvert.DeserializeObject<Dictionary<string,string>>(json2);
dict3 = JsonConvert.DeserializeObject<Dictionary<string,string>>(json3);
merged = Merge(new[]{dict1, dict2, dict3});

Obviously, in production code you'd factor out the redundant lines.

查看更多
登录 后发表回答