【问题标题】:Does C# have a library for parsing multi-level cascading JSON?C# 是否有用于解析多级级联 JSON 的库?
【发布时间】:2010-10-23 04:40:17
【问题描述】:

是否有一个库(首选 C#)来解决我称之为多级级联 JSON 的问题?

这是我的意思的一个例子:(伪代码/C#)

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

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

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

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

结果(与 CSS 相同的行为)

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

编辑 1 - 更复杂的示例

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""
                         }
                     ]
                 }";

编辑 2

在对需求进行了更多思考之后,我发现更复杂的示例永远无法按原样工作。级联功能将无法知道某个电话号码是否已被修改或是否是新号码。为了使它工作,每个子实体都应该有一个唯一的标识符。

【问题讨论】:

  • 有趣。这不是一个典型的用例,所以如果存在任何库,我会感到非常惊讶。我现在正在写自己的。
  • 不确定它是否有助于您解决特定问题,但您可以查看 pietschsoft.com/post/2008/02/…json.codeplex.com
  • 不确定我是否正确理解了这个例子,但想知道结果应该是Albert Smith 还是'John Albert'(根据你所展示的)
  • 我更新了我的答案以响应您的更改。但是,我将合并数组作为练习留给读者。 :)

标签: c# json parsing serialization


【解决方案1】:

使用出色的JSON.NET library 非常容易。此方法将对象与字符串、数字或对象的属性相结合。

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();
}

结果,给出你的例子:

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

根据您更新的问题进行编辑:

通过将此解决方案调整为递归工作,您可以合并子对象。以下示例将匹配您的预期结果(数组除外)。您将能够以类似于合并对象 (JObject) 的方式轻松扩展此解决方案以合并数组 (JArray)。

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;
    }
}

【讨论】:

  • 感谢您的回答。此解决方案的问题在于它仅适用于简单的 JSON 对象。我的示例是 lite JSON,只是为了清楚问题。我编辑了我的示例以获得更复杂/详细的示例。
【解决方案2】:

我不知道。对于简单的情况,您可以使用任何 JSON 库,然后将字典与this one 之类的解决方案合并。例如。使用 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});

显然,在生产代码中,您会排除多余的行。

【讨论】:

  • 感谢您的回答。正如你所说,它可能适用于简单的情况,但我需要它适用于所有场景。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-18
  • 2013-02-02
相关资源
最近更新 更多