【问题标题】:What is the most effective way to parse JSON objects that are dynamically named?解析动态命名的 JSON 对象的最有效方法是什么?
【发布时间】:2017-05-24 03:55:06
【问题描述】:

我正在尝试解析一个 JSON 响应,其中包含我不太熟悉的内容,而且我在野外也没有经常看到。

在其中一个 JSON 对象中,有一个动态命名的 JSON 对象。

在此示例中,"bugs" 中有一个名为 "12345" 的 JSON 对象,它与错误编号相关。

{
   "bugs" : {
      "12345" : {
         "comments" : [
            {
               "id" : 1,
               "text" : "Description 1"
            },
            {
               "id" : 2,
               "text" : "Description 2"
            }
         ]
      }
   }
}

我很好奇的是:解析像这样动态命名的 JSON 对象最有效的方法是什么?

鉴于一些 JSON 实用工具,例如

他们会接受一个像上面这样的 JSON 响应,并将其转换为如下所示的类:

jsonutils

public class Comment
{
    public int id { get; set; }
    public string text { get; set; }
}

public class 12345
{
    public IList<Comment> comments { get; set; }
}

public class Bugs
{
    public 12345 12345 { get; set; }
}

public class Root
{
    public Bugs bugs { get; set; }
}

json2charp

public class Comment
{
    public int id { get; set; }
    public string text { get; set; }
}

public class __invalid_type__12345
{
    public List<Comment> comments { get; set; }
}

public class Bugs
{
    public __invalid_type__12345 __invalid_name__12345 { get; set; }
}

public class RootObject
{
    public Bugs bugs { get; set; }
}

问题在于它会生成一个动态名称的class。因此,使用此 API 的其他标识符的后续查询将导致失败,因为名称不匹配,生成的 [JsonProperty("")] 也不匹配,因为它包含上面生成的示例中的动态类名称。

虽然 JSON 是有效的,但这似乎是这种格式的 JSON 的限制。不幸的是,我无法控制这个 JSON API,所以我很好奇解决这个问题的最佳方法是什么?

【问题讨论】:

  • 12345 不是一个有效的类名,如果你不能控制属性名,这可能是这个方法的一个主要问题。
  • @DanWilson 对,这就是为什么我想知道动态 json 对象可以做什么,因为我无法控制后备存储。这似乎是不良 JSON 做法的边缘案例?
  • 是的,保持属性名称静态并赋予它们动态值很有帮助。 @michael-gunter 的答案可能就是这里的解决方案。
  • Firebase 以这种格式输出数组。有关故事,请参阅此Firebase blog。他们甚至说数组是邪恶的。真的。

标签: c# json


【解决方案1】:

Newtonsoft.Json JsonConvert 可以 parse 它作为 Dictionary&lt;String, Comments&gt; 提供适当的模型类:

public class Comment
{
    public int id { get; set; }
    public string text { get; set; }
}

public class Comments
{
    public List<Comment> comments { get; set; }
}

public class RootObject
{
    public Dictionary<String, Comments> bugs { get; set; }
}

可以通过以下方式检查:

var json = "{\r\n   \"bugs\" : {\r\n      \"12345\" : {\r\n         \"comments\" : [\r\n            {\r\n               \"id\" : 1,\r\n               \"text\" : \"Description 1\"\r\n            },\r\n            {\r\n               \"id\" : 2,\r\n               \"text\" : \"Description 2\"\r\n            }\r\n         ]\r\n      }\r\n   }\r\n}";

Console.WriteLine(json);

var obj = JsonConvert.DeserializeObject<RootObject>(json);

Console.WriteLine(obj.bugs["12345"].comments.First().text);

【讨论】:

  • 我将此标记为答案,因为这是无需手动解压缩 json 的最直接的方法。感谢您的时间和回答!
  • 字典也适用于JavaScriptSerializer,也适用于DataContractJsonSerializerUseSimpleDictionaryFormat = true
【解决方案2】:

试试 Json.NET,它以 Nuget 包 (Newtonsoft.Json) 或来自 http://www.newtonsoft.com/json 的形式提供。

Json.NET 可以执行基于类的序列化/反序列化,如您所展示的。它还为 Json 的格式在开发时未知或不固定的情况提供了通用 JObject 和 JToken 类。

这是一个从文件加载 json 对象的示例。

// load file into a JObject
JObject document;
using (var fileStream = File.OpenRead(someFilePath))
using (var streamReader = new StreamReader(fileStream))
using (var jsonReader = new JsonTextReader(streamReader))
    document = JObject.Load(jsonReader);

// read the JObject
var bugs = (JObject) document["bugs"];
foreach (var bugEntry in bugs)
{
    var bugID = bugEntry.Key;
    var bugData = (JObject) bugEntry.Value;
    var comments = (JArray) bugData["comments"];
    foreach (JObject comment in comments)
        Debug.Print(comment["text"]);
}

【讨论】:

  • 如果有正确的支持模型,这不能用JsonConvert.DeserializeObject&lt;T&gt; 完成吗?这似乎是一种非常手动的方法,而不是允许支持模型定义约束。感谢您的快速回答!
  • 我很困惑,@JonDouglas。拥有支持模型似乎与拥有动态属性名称不一致。您要么提前知道属性名称,要么不知道。
  • 我在想也许 Converter 可以解析像这样的动态命名对象并将其添加到支持模型中。为此,我还尝试使用ExpandoObject,但这似乎只是我必须手动考虑的一个限制。
  • 乍一看,似乎有问题的对象实际上并不是一个具有属性的对象,而是一个键-项对的字典。 JSON 没有区分它们,但正如@JonDouglas 发现的那样,您使用它们的方式是不同的。我倾向于认为 .NET 的大多数 JSON 库都支持字典属性(根据 Eugene 的回答),所以如果你想要严格的类定义,试试这个。如果它更糊涂,请尝试使用 JObject 之类的通用对象。
  • 感谢您的回答迈克尔,我发现尤金的更新答案与我所追求的最接近。
猜你喜欢
  • 2018-07-23
  • 1970-01-01
  • 2022-01-06
  • 2021-08-20
  • 2019-09-16
  • 1970-01-01
  • 2020-06-22
  • 2017-07-19
  • 1970-01-01
相关资源
最近更新 更多