【问题标题】:Questioning received JSON structure质疑收到的 JSON 结构
【发布时间】:2014-01-31 17:49:00
【问题描述】:

我目前正在使用一个 beta API (http://developer.riotgames.com/api/methods),它为所有公开的方法返回 JSON。 到目前为止,我已经能够使用 JSON.NET 反序列化所有这些返回值。然而,今天我使用了他们的一个函数,它返回一个有效但在我看来不正确的 JSON。

您可能想知道,为什么不在测试版论坛上询问呢?我有,但到目前为止我还没有收到答案,总的来说这让我很感兴趣。

JSON 返回的一个 sn-p:

    "1001": {
     "name": "Boots of Speed",
     "plaintext": "Slightly increases Movement Speed",
     "group": "BootsNormal",
     "description": "<...
    }

我对这种结构的问题是 ID 被用作没有标识符的“组”。如果它有,我将能够体面地使用它

"ItemID" : "1001"

但它没有。我不介意手动解析它,但我首先想知道这个 JSON 是否正确(不仅仅是有效)。

您是否同意这不是一种创建包含元素列表的 JSON 块的干净方式,或者我在这里遗漏了什么?到目前为止,我还没有在这个 API 的 beta 论坛上看到任何 cmets,所以我真的很想知道为什么。

编辑“有效”与“正确/可用”: 我知道这是一个有效的 JSON 语句。我质疑这是否适用于 JSON.NET。

我有以下类定义(有两个子类):

public class JSONItem
{
    [JsonProperty("tags")]
    public string[] Tags { get; set; }

    [JsonProperty("plaintext")]
    public string Plaintext { get; set; }

    [JsonProperty("description")]
    public string Description { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("into")]
    public string[] Into { get; set; }

    [JsonProperty("image")]
    public JSONItemImage Image { get; set; }

    [JsonProperty("colloq")]
    public string Colloq { get; set; }

    [JsonProperty("gold")]
    public JSONItemGold Gold { get; set; }
}

将上述 JSON 块提供给 JSONConvert.DeserializeObject(json) 时会引发错误,因为 JSONItem 中未提及“1001”。 您如何处理这个问题以便可以使用 JSON.NET?

这样的类不会起作用,因为你没有名字可以赋予属性:

public class JSONItemWrapper
{
    [JsonProperty("")]
    public string ID { get; set; }
    [JsonProperty("")]
    public JSONItem MyProperty { get; set; }
}

编辑:“与其他方法一致” 其他方法返回每个属性都在 {} 内并具有标识符的块。最近添加的函数具有这种“{} 之外的主键”样式。

【问题讨论】:

  • "1001" 是对象中条目的键,假设它包含在{ ... }
  • 剩下的就是一个子对象,就是这个条目的值。
  • 这给了我一个语法错误:JSON.parse('"ItemID" : "1001"');
  • 这是有效的 JSON。我是否同意并不是真正的问题。更大的问题是这是否与他们的其他 API 结果一致......
  • 对我来说完全有效,key是“1001”,value是另一个json对象

标签: c# json parsing json.net


【解决方案1】:

它是一个有效的 json,你可以使用像 Dictionary&lt;string, SomeObject&gt; 这样的类型来反序列化你的 json。

string json = @"{
    ""1001"": {
            ""name"": ""Boots of Speed"",
            ""plaintext"": ""Slightly increases Movement Speed"",
            ""group"": ""BootsNormal"",
            ""description"": ""desc...""
        }
    }";


var dict = JsonConvert.DeserializeObject<Dictionary<string, MyObject>>(json); 

以后通过它的键访问一个项目也可以很快。


public class MyObject
{
    public string name { get; set; }
    public string plaintext { get; set; }
    public string group { get; set; }
    public string description { get; set; }
}

【讨论】:

  • 我需要访问“1001”字段,这是这个 Item 对象的主键。此主键在其 API 返回的其他对象中被引用。
  • @Starceaker 使用dict.Keys 获取所有密钥、dict.Values 获取所有项目列表和dict["1001"] 访问单个项目有什么问题?
  • 我错过了那部分,谢谢你的解释 L.B.这很可能是我一直在寻找的答案。我太专注于反序列化到一个对象,以至于我忘记了我可以反序列化到一个集合。我会在测试后标记为答案。
  • 非常感谢 L.B.今天你让我变得更聪明了:-)。
【解决方案2】:

当 API 做这样的事情(使用数字作为属性名称)时,这很烦人,但一切都不会丢失。只需使用 Json.NET 反序列化 JSON,然后使用父对象上的索引器运算符访问每个项目。

编辑:

在反序列化 JSON 时,我几乎从不创建 DTO。在大多数情况下,这是很多不必要的样板。我更喜欢反序列化为 dynamic 对象,但是在处理以数字开头的属性名称时,这不会那么有效。

这是我将如何反序列化您的示例消息:

using System;

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

namespace JsonExample
{
    internal class Program
    {
        private static void Main()
        {
            const string json = @"
                {
                    '1001': {
                        'name': 'Boots of Speed',
                        'plaintext': 'Slightly increases Movement Speed',
                        'group': 'BootsNormal',
                        'description': '<...'
                    }
                }";
            var jObject = JsonConvert.DeserializeObject<JObject>(json);
            var plaintext = jObject["1001"]["plaintext"].Value<string>();

            Console.WriteLine(plaintext);
        }
    }
}

【讨论】:

  • 您可以通过包含一些示例代码来展示您的想法,从而使这个答案变得更好。这个答案听起来很随意。
  • 我无意挥手,但您对示例代码是正确的。已添加。
【解决方案3】:

当放入http://JSONLint.com时,

{
    "1001": {
        "name": "Boots of Speed",
        "plaintext": "Slightly increases Movement Speed",
        "group": "BootsNormal",
        "description": "<..."
    }
}

验证为 JSON。

【讨论】:

  • 是的,它包含在 {} 中,与 OP 发布的不同。
  • 是的,我确实必须添加大括号,但 OP 确实说这是一个 sn-p,所以我假设那里有更多数据。我认为这个问题更适合 JSON 中的"1001":
  • 正确 Justin C。我需要能够反序列化块,包括“1001”。我们现在收到的结构使它变得比需要的更困难。
  • 查看 L.B. 回答中的评论。使用字典是我需要的技巧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-13
  • 2020-08-01
  • 2015-01-01
  • 1970-01-01
相关资源
最近更新 更多