Json.NET:反序列化JSON数组

7

我将使用Json.NET进行JSON结构处理,但遇到了一些问题:

当JSON包含一个未命名的数组时,我的类无法正常工作。

JSON示例:

{
    "graph_property" : [{
            "name" : "calculation_method",
            "value" : "Arithmetic"
        }, {
            "name" : "graph_type",
            "value" : "TIME"
        }
    ],
    "measurement" : [{
            "id" : "9997666",
            "alias" : "Measurement (TxP)[IE]-Home Page - Total Time (seconds)",
            "bucket_data" : [{
                    "name" : "2013-MAR-18 12:00 AM",
                    "id" : 1,
                    "perf_data" : {
                        "value" : "2.244",
                        "unit" : "seconds"
                    },
                    "avail_data" : {
                        "value" : "99.67",
                        "unit" : "percent"
                    },
                    "data_count" : {
                        "value" : "299",
                        "unit" : "#"
                    }
                }
            ],
            "graph_option" : [{
                    "name" : "perfwarning",
                    "value" : "-",
                    "unit" : "seconds"
                }, {
                    "name" : "perfcritical",
                    "value" : "-",
                    "unit" : "seconds"
                }, {
                    "name" : "availwarning",
                    "value" : "-",
                    "unit" : "percent"
                }, {
                    "name" : "availcritical",
                    "value" : "-",
                    "unit" : "percent"
                }, {
                    "name" : "bucketsize",
                    "value" : "86400",
                    "unit" : "seconds"
                }, {
                    "name" : "rows",
                    "value" : "1",
                    "unit" : "#"
                }, {
                    "name" : "pagecomponent",
                    "value" : "Total Time",
                    "unit" : "seconds"
                }, {
                    "name" : "avg_perf",
                    "value" : "2.244",
                    "unit" : "seconds"
                }, {
                    "name" : "avg_avail",
                    "value" : "99.67",
                    "unit" : "percent"
                }, {
                    "name" : "total_datapoint_count",
                    "value" : "300",
                    "unit" : "#"
                }, {}

            ]
        }, {
            "id" : "9997666",
            "alias" : "Measurement (TxP)[IE]-Women - Total Time (seconds)",
            "bucket_data" : [{
                    "name" : "2013-MAR-18 12:00 AM",
                    "id" : 1,
                    "perf_data" : {
                        "value" : "0.979",
                        "unit" : "seconds"
                    },
                    "avail_data" : {
                        "value" : "100.00",
                        "unit" : "percent"
                    },
                    "data_count" : {
                        "value" : "299",
                        "unit" : "#"
                    }
                }
            ],
            "graph_option" : [{
                    "name" : "perfwarning",
                    "value" : "-",
                    "unit" : "seconds"
                }, {
                    "name" : "perfcritical",
                    "value" : "-",
                    "unit" : "seconds"
                }, {
                    "name" : "availwarning",
                    "value" : "-",
                    "unit" : "percent"
                }, {
                    "name" : "availcritical",
                    "value" : "-",
                    "unit" : "percent"
                }, {
                    "name" : "bucketsize",
                    "value" : "86400",
                    "unit" : "seconds"
                }, {
                    "name" : "rows",
                    "value" : "1",
                    "unit" : "#"
                }, {
                    "name" : "pagecomponent",
                    "value" : "Total Time",
                    "unit" : "seconds"
                }, {
                    "name" : "avg_perf",
                    "value" : "0.979",
                    "unit" : "seconds"
                }, {
                    "name" : "avg_avail",
                    "value" : "100.00",
                    "unit" : "percent"
                }, {
                    "name" : "total_datapoint_count",
                    "value" : "299",
                    "unit" : "#"
                }, {}

            ]
        }
    ],
    "link" : {
        "type" : "application/json",
        "href" : "http://api.website.tld?format=json",
        "rel" : "slotmetadata"
    }
}

Json.NET 类:

using System;
using System.Collections.Generic;

namespace CAKR.Graph
{
    /// <summary>
    /// Description of KN_Graph.
    /// </summary>
    public class GraphProperty
    {
        public string name { get; set; }
        public string value { get; set; }
    }

    public class PerfData
    {
        public string value { get; set; }
        public string unit { get; set; }
    }

    public class AvailData
    {
        public string value { get; set; }
        public string unit { get; set; }
    }

    public class DataCount
    {
        public string value { get; set; }
        public string unit { get; set; }
    }

    public class BucketData
    {
        public string name { get; set; }
        public int id { get; set; }
        public PerfData perf_data { get; set; }
        public AvailData avail_data { get; set; }
        public DataCount data_count { get; set; }
    }

    public class GraphOption
    {
        public string name { get; set; }
        public string value { get; set; }
        public string unit { get; set; }
    }

    public class Measurement
    {
        public string id { get; set; }
        public string alias { get; set; }
        public List<BucketData> bucket_data { get; set; }
        public List<GraphOption> graph_option { get; set; }
    }

    public class Link
    {
        public string type { get; set; }
        public string href { get; set; }
        public string rel { get; set; }
    }

    public class RootObject
    {
        public List<GraphProperty> graph_property { get; set; }
        public List<Measurement> measurement { get; set; }
        public Link link { get; set; }
    }
}

我的代码:

var myObject = JsonConvert.DeserializeObject<CAKR.Graph.Measurement>(MyJsonString);

我不确定为什么没有得到包含“Measurment”子数组数据的对象。 如果插入命名值,它可以工作...


这是一个不错的链接,可用于验证您的 JSON 是否有效JSON Lint - MethodMan
你不应该针对一个namespace工作,而是应该针对一个ClassCAKR.Graph.Measurement不是一个类。 - MethodMan
可能是重复的问题:无法将 JSON 数组反序列化为类型 - Json.NET - MethodMan
@DJ KRaze:JSON格式正确,没有重复项,“Measurement”是命名空间“CAKR.Graph”中的一个类。无论如何,感谢您的评论 =) - t313
4个回答

9

我曾经花费很长时间努力让它正常工作。但最终的解决方案并不难。希望我的回答能帮到一些人。

在我的情况下,解决方案如下:

  1. 通过nu.get将JSON.net安装到您的项目中
  2. 制作您的JSON对象,包括数组的嵌套等。务必确保对象格式正确!示例...

{"ProductDetail":[

  {
      "ProjectImg"    : "http://placehold.it/400x300",
      "Category"      : "Cars",
      "ProjectTitle"  : "Cars of the future",
      "ProjectDesc"   : "Test project",
      "GenSpecList"   : ["Specs1", "Specs2", "Specs3", "Specs4"],
      "OptionList"    : [{    "OptionNr"  : "1",
                              "Options"   : ["Opt1", "Opt2", "Opt3"]
                          },
                          {   "OptionNr"  : "2",
                              "Options"   : ["Opt1", "Opt2", "Opt3"]
                          },
                          {   "OptionNr"  : "3",
                              "Options"   : ["Opt1", "Opt2", "Opt3"]
                          },
                          {   "OptionNr"  : "4",
                              "Options"   : ["Opt1", "Opt2", "Opt3"]
                          },
                          {   "OptionNr"  : "5",
                              "Options"   : ["Opt1", "Opt2", "Opt3"]
                          },
                          {   "OptionNr"  : "6",
                              "Options"   : ["Opt1", "Opt2", "Opt3"]
                          }
                        ],
      "Articles"      : [{    "tileImg" : "'Images/Project/1.jpg'",
                              "tileTit" : "Title1",
                              "tileArt" : "Article text here..."
                          },
                          {
                              "tileImg" : "'Images/Project/2.jpg'",
                              "tileTit" : "Title2",
                              "tileArt" : "Article text here..."
                          },
                          {
                              "tileImg" : "'Images/Project/3.jpg'",
                              "tileTit" : "Title3",
                              "tileArt" : "Article text here..."
                          },
                          {
                              "tileImg" : "'Images/Project/4.jpg'",
                              "tileTit"   : "Title4",
                              "tileArt"   : "Article text here..."
                          }
                         ]
  }
]
}
  1. Go to json2csharp.com and copy your JSON object into the input box and click on the generate button. Copy the csharp model (this was actually the key to solve my struggle!) generated into your ViewModel.
  2. In my case the primary class of all generated classes by json2csharp.com was the RootObject and looked like below

    public class Article
    {
        public string tileImg { get; set; }
        public string tileTit { get; set; }
        public string tileArt { get; set; }
    }
    
    public class OptionList
    {
        public string OptionNr { get; set; }
        public List<string> Options { get; set; }
    }
    
    public class ProductDetail
    {
        public string ProjectImg { get; set; }
        public string Category { get; set; }
        public string ProjectTitle { get; set; }
        public string ProjectDesc { get; set; }
        public List<string> GenSpecList { get; set; }
        public List<OptionList> OptionList { get; set; }
        public List<Article> Articles { get; set; }
    }
    
    public class RootObject
    {
        public List<ProductDetail> ProductDetail { get; set; }
    }
    
  3. Then use the following code in the controller (just copied the complete file here)

    using Project.Details; //<-- this is my ViewModel namespace name
    using Newtonsoft.Json;
    using System.IO;
    using System.Threading.Tasks;
    
    namespace WebApplication.Controllers
    {
        public class JSONController : Controller
        {
            //
            // GET: /JSON/
            public async Task<ActionResult> Index()
            {
                StreamReader file = new StreamReader("C:\\Users\\YourName\\etc\\File.json");
                String json = await file.ReadToEndAsync();
    
                var Project = JsonConvert.DeserializeObject<RootObject>(json);
    
                return View();
            }
        }
    }
    
现在一切都应该正常工作,包括数组中的数组等。希望您会发现我的解决方案有帮助。请注意,我不是一个死板的程序员,如果我在效率方面遗漏了什么,希望能从您那里得到一些提示来改进这段代码...
最好的问候, 雷蒙德

我想获取KEY值和VALUE值...它可以做到吗?谢谢。 - Si8

4
你已经接近成功了。只需使用以下代码:
var myObject = JsonConvert.DeserializeObject<CAKR.Graph.RootObject>(MyJsonString);

替代

var myObject = JsonConvert.DeserializeObject<CAKR.Graph.Measurement>(MyJsonString);

这是我一开始想的。但是由于某些原因,测量对象始终是“NULL”。 - t313

2
首先,您不必将Measurement类的所有属性名称与MyJsonString中呈现的完全相同。您可以使用JsonProperty属性并装饰您的类属性。
另一件事是,如果您想反序列化MyJsonString的一部分,并仅提取Measurement数组,则应为Deserialize方法提供正确的T类型(在您的情况下为IEnumerable<Measurement>)。
以下代码应该有所帮助:
    dynamic context = JObject.Parse(MyJsonString);
    var myObject = JsonConvert.DeserializeObject<IEnumerable<Measurement>>(context.measurement.ToString());

谢谢Jevgenij!这真的让我有了启发。 - t313

0

我使用一种非常简单的方法来反序列化Json数组。而不是使用大量带有众多公共变量的公共类。我只是使用一个动态对象,并将json作为对象传递给JSONConvert.DeserializeObject。

这就是它的工作原理。假设我有以下JSON:

string json = { 'Name': 'John Doe', 
  'Address': { 'City': 'Atlanta', 'State': 'GA' }, 
  'Age': 30}

我可以将字符串 JSON 传递给 JSONConvert.DeserializeObject。
dynamic outputArray = JsonConvert.DeserializeObject(json);

然后,使用刚创建的动态项,我可以像这样收集Json数据。

string getName = outputArray.Name //This will return "John Doe"

如果您的Json中有一个数组,您可以使用以下方法:
string getCity = outputArray.Address.City; //This will return "Atlanta".

很容易更改数据来源,而不需要一堆公共变量的集群... 如果您想要,仍然可以将值保存到公共变量中。

以下是我使用完整方法的方式:

using (var client = new WebClient())
        {
            string json = client.DownloadString(url);
            string output = json.ToString();

            dynamic outputArray = JsonConvert.DeserializeObject(output);

            string _age = outputArray.age;
            string appID = outputArray.data.app_id;

            Debug.Write(outputArray.Something); //Just match value of json        
        }

只要您的JSON不是一个数组,而是一个对象,就会出现错误示例。 - Konstantin Chernov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接