首页 > 解决方案 > 使用 C# 解析嵌套的 Json 数据。无法访问内部元素消耗

问题描述

我最多可以解析一个嵌套级别,但我无法弄清楚如何读取consumption_history. 我一直在尝试不同的方法来做到这一点,但无法获得消费价值。

我可以访问miu_idandmeter_number但不能访问consumption_list.

模型:

class JsonModel
{
    public class Rootobject
    {
        public string site_id { get; set; }
        public Endpoint[] endpoints { get; set; }
        public Paging paging { get; set; }
    }

    public class Paging
    {
        public int page { get; set; }
        public int limit { get; set; }
        public int total { get; set; }
        public string next { get; set; }
        public object prev { get; set; }
        public string self { get; set; }
    }

    public class Endpoint
    {
        public string miu_id { get; set; }
        public string meter_number { get; set; }
        public Consumption_History[] consumption_hist { get; set; }
    }

    public class Consumption_History
    {
        public DateTime reading_date { get; set; }
        public float consumption { get; set; }
        public float consumption_with_multiplier { get; set; }
    }
}

程序:

static void Main(string[] args)
{
    string json = File.ReadAllText(@"C:\Users\ConsoleApp3\apidataone.json");
    var results = JsonConvert.DeserializeObject<JsonModel.Rootobject>(json);

    JsonModel.Rootobject rootobject = JsonConvert.DeserializeObject<JsonModel.Rootobject>(json);
    rootobject.endpoints = JsonConvert.DeserializeObject<JsonModel.Rootobject>(json).endpoints;

    foreach (JsonModel.Consumption_History ch in rootobject.endpoints)
    {
        Console.WriteLine(ch.consumption);

    }
}

json数据:

{
    "site_id":"1",
    "endpoints":
    [{
          "miu_id":"111",
          "meter_number":"88",
          "consumption_history":
          [{
              "reading_date":"2010-02-17T00:00:00", 
              "consumption":1.0, 
              "consumption_with_multiplier":1.0
          }]
    }]
}

标签: c#.netjsonjson.net

解决方案


我已经稍微简化了代码,而不是从文件中读取,我只是将 JSON 内容放在适当的位置。此代码使用Newtonsoft.Json(可通过 NUGET 包获得),但它的工作方式与其他序列化程序相同。

// using Newtonsoft.Json;
void Main()
{
    string json = @"{
        'site_id':'1',
        'endpoints':
        [{
              'miu_id':'111',
              'meter_number':'88',
              'consumption_history':        
              [{
                  'reading_date':'2010-02-17T00:00:00',
                  'consumption':1.0,
                  'consumption_with_multiplier':1.0
              }]
        }]
    }";

    dynamic j = JsonConvert.DeserializeObject<dynamic>(json);
    string site_id = j["site_id"].ToString();
    var endpoints = j["endpoints"];
    foreach (var endpoint in endpoints)
    {
        string miu_id = endpoint["miu_id"];
        miu_id.Dump();
        // ...
        var consumption_histories = endpoint["consumption_history"];
        foreach(var consumption in consumption_histories)
        {
            string reading_date = consumption["reading_date"];
            reading_date.Dump();
            // ...
        } // foreach
    } // foreach
}

在 .NET 小提琴中运行它

关于JSON:只要[ ... ]JSON 结构中有一个,这意味着有一个数组({ ... }代表一个对象) - 并且[{ ... }]是一个数组内的对象;属性和数组元素都用逗号 ( ,) 分隔;字符串属性名称需要用单引号 ( '...') 括起来。赋值是用冒号 ( :) 完成的。在 JSON 中,您有对象、字符串或数字数据——这些是唯一存在的类型。如果您需要类型,则必须自己将属性转换为正确的类型。

您可以通过索引器(如循环endpoints[i]内部for)访问数组,或者 - 正如我假设的那样 - 您想要遍历每个元素,在这种情况下foreach循环更容易。

注意:for要在循环中使用它(例如for (int i = 0; i < endpointsLength; i++) { ... }),您必须将其endpoints转换consumption_histories为数组类型(例如 via var endpoints = (object[])j["endpoints"];)并失去提供的简单性dynamic(例如,您需要一个索引器来访问一个像(endpoints[i])["miu_id"]能够得到miu_id) 的值。

在这种情况下,关键字dynamic简化了很多事情,这样您就可以保持 C# 代码的“JavaScript 风格”(记住 JSON 来自 JavaScript 世界)。

如果你想引入你在 C# 中声明的类,这也是可以的。例如:

foreach (Consumption_History consumption in consumption_histories)
{
    string reading_date = consumption.reading_date.ToString();
    reading_date.Dump();
    // ...
} // foreach

您可以看到,reading_date现在作为 C# 属性访问,并且因为它是 type DateTime,所以您需要先将其转换为字符串。这种转换需要在foreach循环之前完成,因此您可以将类中的数据类型更改为字符串以避免这种情况,或者您可以使用上面显示的原始代码并将数据复制 + 转换为对象的类型化版本(例如将字符串转换为日期时间,您可以检查一下)。

如果您依赖 NewtonSoft.JSON 提供的内置转换,您可以简单地使用JsonConvert.DeserializeObject<Rootobject>(json)而不是JsonConvert.DeserializeObject<dynamic>(json). 请注意,隐式转换可能会引发异常。

此外,请确保 C# 和 JSON 文件中的属性名称完全匹配 - 如果不是,您可以在 C# 中使用属性来装饰它们(有关如何执行此操作的说明,请参见此处) - xdtTransform发现它与consumption_hist, 和在评论中提到了它。


推荐阅读