在使用Newtonsoft JSON.Net进行反序列化之前合并源JSON

时间:2015-08-06 15:42:18

标签: c# json.net

我有JSON配置文件,我将其反序列化为c#类。但是,有时,我需要合并配置文件的某些节点。我不能简单地序列化对象1和对象2然后合并,因为null和默认值处理工作的方式(如果对象2具有默认值,它将不会序列化并覆盖对象1的不同属性值)。我宁愿保持我的默认值和空值处理不受影响。

是否有某种元数据反序列化方法与对象一起,我可以访问该特定节点的源json?我知道这是影响深远的,但我不太确定如何处理我的情况。

{
    "prop1": "value1",
    "prop2": "value2",
    "defaultProp4Options": {
        "subprop1": "subvalue1",
        "subprop2": "subvalue2",
        "subprop3": "subvalue3"
    },
    "prop4": [
        {
            "subprop4": "subvalue4"
        },
        {
            "subprop2": "diff2",
            "subprop3": "diff3",
        },
        {
            "subprop1": "diff1",
            "subprop5": "subvalue5",
        }
    ]
}

我认为这样做的唯一方法是在反序列化之前合并,但我有点卡住了。

var jfoo = JObject.Parse(myconfigjson);
var defaults = jfoo.Values("defaultProp4Options");
var bars = jfoo.Values("prop4");

// ***********
// How do I merge defaults with each bar (bar has precendence) and replace collection?
// ***********

// Use the new merged json to deserialize
var result = JsonConvert.DeserializeObject<Foo>(jfoo.ToString());

有人能让我走上正轨吗?

更新

这让我在那里,但如果你知道更好的方法,请告诉我。

var foo = JObject.Parse(s);
var defaults = jfoo.GetValue("defaultProp4Options");
var bars = jfoo.GetValue("prop4");

var j = new JArray();
foreach (var bar in bars)
{
    var baseDefaults = defaults.DeepClone() as JObject;
    baseDefaults.Merge(bar);
    j.Add(baseDefaults);
}

jfoo.Remove("defaultProp4Options");
jfoo.Property("bars").Value = j;

结果是:

{
    "prop1": "value1",
    "prop2": "value2",
    "prop4": [
        {
            "subprop1": "subvalue1",
            "subprop2": "subvalue2",
            "subprop3": "subvalue3",
            "subprop4": "subvalue4"
        },
        {
            "subprop1": "subvalue1",
            "subprop2": "diff2",
            "subprop3": "diff3",
        },
        {
            "subprop1": "diff1",
            "subprop2": "subvalue2",
            "subprop3": "subvalue3",
            "subprop5": "subvalue5"
        }
    ]
}

1 个答案:

答案 0 :(得分:1)

Json.Net第6版第4次发布后,它支持基于JContainer.Merge方法的合并操作。

但遗憾的是,在您的示例中,我们无法直接使用该方法,因为defaultProp4Options是一个对象而prop4是一个数组,但如果结构不会发生重大变化,我们可以迭代在prop4中并改为合并项目,这是一个示例

        var jsonObj = JObject.Parse(json);

        var def = (JObject)jsonObj["defaultProp4Options"];
        var prop4 = jsonObj["prop4"];

        for(int i=0;i<prop4.Count();i++)
        {
            var item = prop4.ElementAt(i);
            var cloneDef =(JObject) def.DeepClone();
            cloneDef.Merge(item);
            item.Replace(cloneDef);
        }

        var mergedJson = jsonObj.ToString(); //only used to show new json
        Console.WriteLine(mergedJson);

        var foo = jsonObj.ToObject<Foo>(); //deserializing to foo

这是输出结果

{
  "prop1": "value1",
  "prop2": "value2",
  "defaultProp4Options": {
    "subprop1": "subvalue1",
    "subprop2": "subvalue2",
    "subprop3": "subvalue3"
  },
  "prop4": [
    {
      "subprop1": "subvalue1",
      "subprop2": "subvalue2",
      "subprop3": "subvalue3",
      "subprop4": "subvalue4"
    },
    {
      "subprop1": "subvalue1",
      "subprop2": "diff2",
      "subprop3": "diff3"
    },
    {
      "subprop1": "diff1",
      "subprop2": "subvalue2",
      "subprop3": "subvalue3",
      "subprop5": "subvalue5"
    }
  ]
}