牛顿JSON将复杂的密钥集合序列化为JSON

时间:2019-06-06 11:12:10

标签: c# json.net

我有下面的字典,我需要将复杂的键值转换为正确的JSON。

static void Main(string[] args)
        {
            Dictionary<string, object> collectionProp = new Dictionary<string, object>();
            Dictionary<string, object> prop = new Dictionary<string, object>();
            prop.Add("content", "button");
            prop.Add("page.count", "10");
            prop.Add("columns.0.textAlign", "center");
            prop.Add("columns.1.textAlign", "left");
            var result = new Dictionary<string, object>();
            foreach (var pair in prop)
            {
                var key = pair.Key;                
                    var parts = key.Split('.');
                    var currentObj = result;
                    for (int i = 0; i < parts.Length - 1; i++)
                    {
                        var property = parts[i];
                        if (!currentObj.Keys.Contains(property))
                            currentObj[property] = new Dictionary<string, object>();
                        currentObj = (Dictionary<string, object>)currentObj[property];
                    }
                    currentObj[parts[parts.Length - 1]] = pair.Value;                
            }
            Console.WriteLine(JsonConvert.SerializeObject(result, Formatting.Indented));
            Console.ReadLine();
        }

并获得以下结果。

{
  "content": "button",
  "page": {
    "count": "10"
  },
  "columns": {
    "0": {
      "textAlign": "center"
    },
    "1": {
      "textAlign": "left"
    }
  }
}

期望列应分组为JSON数组。如何实现这一目标??

所需的输出:

{
  "content": "button",
  "page": {
    "count": "10"
  },
  "columns": [
    {
      "textAlign": "center"
    },
    {
      "textAlign": "left"
    }
  ]
}

1 个答案:

答案 0 :(得分:1)

JSON.NET默认将字典序列化为JSON对象,即使其键可转换为整数也是如此。代替从源头构建字典,您可以构建JObject层次结构。这些帮助器方法可以识别路径中的数组索引索引,从而自动围绕它们建立JArray容器:

public static class JsonExtensions
{
    public static void SetValue(this JContainer container, string path, object value)
    {
        JToken token = container;
        var keys = path.Split('.');
        foreach (var key in keys)
        {
            int index;
            if (int.TryParse(key, out index))
            {
                var jArray = token as JArray;
                if (jArray == null)
                {
                    jArray = new JArray();
                    token.Replace(jArray);
                    token = jArray;
                }
                while (index >= jArray.Count)
                {
                    jArray.Add(JValue.CreateNull());
                }
                token = jArray[index];
            }
            else
            {
                var jObject = token as JObject;
                if (jObject == null)
                {
                    jObject = new JObject();
                    token.Replace(jObject);
                    token = jObject;
                }
                token = token[key] ?? (token[key] = JValue.CreateNull());
            }
        }
        token.Replace(new JValue(value));
    }

    public static void SetValues(this JContainer container, IEnumerable<KeyValuePair<string, object>> pairs)
    {
        foreach (var pair in pairs)
        {
            container.SetValue(pair.Key, pair.Value);
        }
    }
}

这是您获得期望结果的方式:

var jObject = new JObject();
jObject.SetValues(new Dictionary<string, object>
{
    { "content", "button" },
    { "page.count", "10" },
    { "columns.0.textAlign", "center" },
    { "columns.1.textAlign", "left" }
});
Console.WriteLine(jObject.ToString(Formatting.Indented));

请注意,我提供的代码示例效率不高,应将其用作获得所需结果的灵感。

还要注意,在某些情况下,构建JObject的值顺序很重要,但enumerating items from dictionary is non-deterministic却很重要。因此,您可能会考虑为源保证更好的数据结构,以保证键值对在其中的顺序(例如数组)。