【问题标题】:Get a specific part of my JSON data in C#在 C# 中获取我的 JSON 数据的特定部分
【发布时间】:2018-10-17 18:36:32
【问题描述】:

我有这个 JSON:

{
    "response":
    {
        "data":
        [
            {
                "start":1,
                "subjects":["A"]
            },
            {
                "start":3,
                "subjects":["B"]
            },
            {
                "start":2,
                "subjects":["C"]
            }
        ]
    }
}

我只想从对象中获取“主题”数据,它的“开始”值是大于 1.3 的最小数据,在这种情况下是 C。有人会碰巧知道这样的可以用C#实现吗?

【问题讨论】:

标签: c# json


【解决方案1】:

我想对其他答案进行一些扩展,并对主题进行更多说明。

JSON - JavaScript 对象 Notation - 只是一种“在线”移动数据的方式。在 .NET 中,您不应该真正将您的对象视为 JSON,尽管您可以通俗地指代这样的数据结构。

话虽如此,.NET“内部”的 JSON 是什么?这是你的电话。例如,您可以将其视为string,但您将很难根据某些参数/规则执行此查找特定节点的操作。

由于 JSON 是一种树状结构,您可以构建自己的数据结构或使用网络上的许多可用数据结构。如果您正在学习语言的工作原理和一般的编程,这很好,如果您专业地这样做,那就不好了,因为您可能会重新发明轮子。并且解析 JSON 并不是一件容易的事(同样,很好的练习)。

那么,最省时的做法是什么?你有两个选择:

  1. 使用 dynamic 对象来表示您的 JSON 数据。动态是 .NET 的“扩展”(实际上是 CLR 的扩展,称为 DLR),它允许您创建没有类的对象(它们可以被认为是“无类型的”,或者更好的是,使用 duck 打字)。

  2. 使用您定义的类型化结构来保存数据。这是规范的、面向对象的 .NET 方式,但在声明类和键入所有内容方面存在折衷,这在时间方面是昂贵的。回报是您可以获得更好的智能感知、性能(DLR 对象比传统对象慢)和更安全的代码。


要采用第一种方法,您可以参考@YouneS 的答案。您需要在项目中添加一个依赖项 Newtonsoft.Json(一个 nuget),并调用反序列化将 JSON 字符串转换为动态对象。正如您从他的回答中看到的那样,您可以像访问 JavaScript 语言一样访问此对象中的属性。但是您也会意识到您没有智能感知,并且将允许使用诸如 myObj.unexistentField = "asd" 之类的内容。这就是动态类型对象的本质。

第二种方法是声明所有类型。同样,这很耗时,而且在许多情况下,您宁愿不这样做。请参阅Microsoft Docs 了解更多信息。

您应该首先创建您的数据合同,如下所示(请原谅我的任何拼写错误,我没有编译代码)。

[DataContract]
class DataItem 
{
    [DataMember]
    public string Start { get; set; }

    [DataMember]
    public string[] Subjects { get; set; } 
}

[DataContract]
class ResponseItem
{
    [DataMember]
    public DateItem[] Data { get; set; }
}

[DataContract]
class ResponseContract 
{
    [DataMember]
    public ResponseItem Response { get; set; }
}

一旦你声明了所有这些数据结构,将你的 json 反序列化为它:

 using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
 {
     var deserializer = new DataContractJsonSerializer(typeof(ResponseContract));
     return (T)deserializer.ReadObject(ms);
 }

上面的代码可能看起来有点复杂,但遵循一点 .NET / BCL 标准。 DataContractJsonSerializer 仅适用于流,因此您需要打开一个包含您的字符串的流。因此,您使用 json 字符串中的所有字节创建了一个内存流。

您也可以使用 Newtonsoft 来执行此操作,这要简单得多,但当然仍然需要额外的依赖:

DataContract contract = JsonConvert.DeserializeObject<DataContract>(output);

如果您使用这种方法,您就不需要在您的类上添加注释(所有这些 DataMemberDataContract),从而使代码更加简洁。我非常喜欢使用这种方法而不是 DataContractJsonSerializer,但这是你的决定。


我已经谈了很多关于序列化和反序列化对象的问题,但您的问题是,“我如何找到某个节点?”。上面的所有讨论只是一个先决条件。

和往常一样,有几种方法可以实现您想要的:

  1. @YouneS 回答。它非常简单,可以满足您的需求。

  2. 使用上面的第二种方法,然后使用您的类型对象来获得您想要的。例如:

    var contract = JsonConvert.DeserializeObject<DataContract>(output);
    var query = from dataItem in contract.Response.Data
                where dataItem.Start > 1.3
                order by dataItem.Start;
    var item = query.FirstOrNull();
    

这将返回第一个项目,因为它是有序的,应该是最小的。记得测试结果是否为 null。

  1. 您可以使用 Newtonsoft 的一项功能,直接找到您想要的节点。请参阅the documentation。警告,对于简单的情况,它有点高级,可能有点矫枉过正。

【讨论】:

    【解决方案2】:

    您可以使用以下代码使其工作:

    // Dynamic object that will hold your Deserialized json string    
    dynamic myObj = JsonConvert.DeserializeObject<dynamic>(YOUR-JSON-STRING);
    
    // Will hold the value you are looking for
    string[] mySubjectValue = "";
    
    // Looking for your subject value    
    foreach(var o in myObj.response.data) {
        if(o.start > 1.3)
            mySubjectValue = o.subjects;
    }
    

    【讨论】:

    • 这也给了B,有没有办法只输出最接近1.3的那个
    猜你喜欢
    • 1970-01-01
    • 2020-06-10
    • 2016-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-10
    相关资源
    最近更新 更多