【问题标题】:Serialize flat Dictionary into multi-sub-object JSON将平面字典序列化为多子对象 JSON
【发布时间】:2020-03-15 12:13:35
【问题描述】:

在 C# 中,我有一个平面 Dictionary<string, string>,其中键的形式为 obj1/obj2/obj3,值是直接字符串。现在我想将其序列化为子对象,因此示例值:

var dict = new Dictionary<string, string> { {"foo/bar/baz1", "123" }, {"foo/baz", "456" }, { "foo/abc", "def" } };

结果应该是:

{
     "foo": {
         "bar": {
             "baz1": "123"
         },
         "baz": "456",
         "abc": "def"
     }
}

如果输出中“123”和“456”周围的引号可以解释为数字或布尔值,我可以选择删除它们。

我正在使用 Newtonsoft.JSON

【问题讨论】:

  • @PavelAnikhouski 使用 JsonConverter 作为基础,但要找到有关操作键而不是操作值的文档要困难得多...
  • 你可以把foo/bar/baz1这样的属性拆分成部分递归处理,请看我的回答

标签: c# json serialization json.net


【解决方案1】:

您可以使用JObject.FromObject 方法将源字典解析为JObject。然后遍历所有属性,使用string.Split 拆分它们并递归解析为新的JObject,表示属性树。最后使用JObject.Add将此对象添加到目标对象,或者如果给定键已经存在则更新它

var dict = new Dictionary<string, string> { { "foo/bar/baz1", "123" }, { "foo/baz", "456" }, { "foo/abc", "def" } };
var source = JObject.FromObject(dict);
var dest = new JObject();

foreach (var property in source.Properties())
{
    //split the name into parts
    var items = property.Name.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
    var item = items.FirstOrDefault();
    if (string.IsNullOrEmpty(item))
        continue;

    //get JObject representing a properties tree
    var result = WriteItems(items.Skip(1).ToList(), property.Value);

    //check that destination already contains top property name (e.g. 'foo')
    if (dest.ContainsKey(item))
    {
        (dest[item] as JObject)?.Add(result.First);
    }
    else
    {
        dest.Add(item, result);
    }
}

Console.WriteLine(dest.ToString());

//local function to recursively go through all properties and create a result JObject
JObject WriteItems(IList<string> items, JToken value)
{
    var item = items.FirstOrDefault();
    items.RemoveAt(0);

    if (!items.Any()) //no more items in keys, add the value
        return new JObject(new JProperty(item, value));

    return new JObject(new JProperty(item, WriteItems(items, value)));
}

它产生以下输出

{
  "foo": {
    "bar": {
      "baz1": "123"
    },
    "baz": "456",
    "abc": "def"
  }
}

此外,上面的代码允许您处理任意深度的属性树。我不认为有一种内置的方法可以将foo/bar/baz1 之类的结构序列化为Json.NET 中的子对象

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多