通过 JSON.NET 解析动态 JSON 数据

Parse dynamic JSON data via JSON.NET

我有一套格式有趣的 JSON,我需要使用 C# 阅读,在我的例子中特别使用 JSON.NET,尽管这可能使用 System.Text.Json 来完成还有。

数据的结构类似于:

[
    {
        "Name": "Name A",
        "Value": "Apples"
    },
    {
        "Name": "Name B",
        "Value": {
            "key1": "value1",
            "key2": "value2"
        }
    }
]

简而言之,数组对象的形状有些不同,具体来说'Value' 属性是变化的。我只对具有 key/value (Dictionary<string, string>) 类型值数据的记录感兴趣,如果有帮助的话。

将此数据读入某种类型表示的最佳(在本例中是最简单的)方法是什么?我说打字是因为这是我想要使用的,但这不是 严格 的要求。

类似“嘿JSON.NET,请给我所有 'Value' 类型为 key/value 的记录,如果可能的话,作为一个对象结构,其中值被具体化作为类型化的 Dictionary 对象。如果有帮助,其他记录可能会被丢弃。谢谢!".

如果能以某种方式使用 POCO 对象来实现,那就太好了。

试试这个

    var jsonParsed = JArray.Parse(json); 

    var items = new List<Item>();

    foreach (JObject item in jsonParsed)
    {
        var name = string.Empty;
        foreach (var prop in item.Properties())
        {
            if (prop.Value.Type.ToString() != "Object")
            {
                if (prop.Name == "Name") name = (string)prop.Value;
                continue;
            }
            items.Add(new Item
            {
                Name = name,
                Value = prop.Value.ToObject<Dictionary<string, string>>()
            });
        }
    }

结果

[
  {
    "Name": "Name B",
    "Value": {
      "key1": "value1",
      "key2": "value2"
    }
  }
]

class

public class Item
{
    public string Name { get; set; }
    public Dictionary<string, string> Value { get; set; }
}

一种可能的方法是使用 JsonConverter 子类。

这可能例如如果找到 JTokenType.Object,则包含 Dictionary<string, string> 和 key-value 对,而 return 在任何其他情况下都是空字典。当然可以根据需要定制。

DictionaryValueConverter

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public class DictionaryValueConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Dictionary<string, string>));
    }

    public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue,
        JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        return token.Type == JTokenType.Object 
            ? token.ToObject<Dictionary<string, string>>() 
            : new Dictionary<string, string>();
    }

    public override bool CanWrite => false;

    public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

项目

你的数组的 Item 看起来像这样:

using Newtonsoft.Json;

public class Item
{
    public string Name { get; set; }

    [JsonConverter(typeof(DictionaryValueConverter))]
    public Dictionary<string, string> Value { get; set; }
}

测试

你可以这样称呼它:

using Newtonsoft.Json;

public static class Program
{
    static void Main()
    {
        string json = @"
        [
            {
                ""Name"": ""Name A"",
                ""Value"": ""Apples""
            },
            {
                ""Name"": ""Name B"",
                ""Value"": {
                    ""key1"": ""value1"",
                    ""key2"": ""value2""
                }
            }
            ]
        ";

        var list = JsonConvert.DeserializeObject<List<Item>>(json);

        if (list == null) return;
        foreach (var item in list)
        {
            Console.WriteLine($"name: {item.Name}");
            if (item.Value.Count == 0)
            {
                Console.WriteLine("no value");
            }
            foreach (var (key, value) in item.Value)
            {
                Console.WriteLine($" -> Key = {key}, Value = {value}");
            }
            Console.WriteLine();
        }
    }
}

以上示例代码的输出为:

name: Name A
no value

name: Name B
 -> Key = key1, Value = value1
 -> Key = key2, Value = value2

如上所述,可以根据需要自定义方法。