简体   繁体   English

从嵌套在Json响应中的数组反序列化对象

[英]Deserialize objects from array nested inside Json response

I'm trying to deserialize some objects nested inside a Json response using Newtonsoft.Json. 我正在尝试使用Newtonsoft.Json反序列化嵌套在Json响应中的一些对象。 I want to deserialize the following Jsons Term objects into a list. 我想将以下Jsons Term对象反序列化为一个列表。 I have many Term objects in the Json response, so performance and compactness is important to me. 我在Json响应中有很多Term对象,因此性能和紧凑性对我来说很重要。 I also would only like to define the Term class as I do not care about the other data for the time being. 我也只想定义Term类,因为我暂时不关心其他数据。

I have a model defined for Term: 我有一个为Term定义的模型:

public class Term
{
    public string Known { get; set; }
    public string Word { get; set; }
}

My Json looks like this: 我的Json看起来像这样:

{
    "myName":"Chris",
    "mySpecies":"Cat",
    "myTerms":
    [
        {
            "Term":
            {
                "Known":"true",
                "Word":"Meow"
            }
        },
        {
            "Term":
            {
                "Known":"false",
                "Word":"Bark"
            }
        }
    ]
}

My C# deserializing code: 我的C#反序列化代码:

var response = await httpClient.GetAsync(uri);
string responseString = response.Content.ReadAsStringAsync().GetResults();
var searchTermList = JsonConvert.DeserializeObject<List<Term>>(responseString);

The problem/error I'm receiving is, not sure how I can get these terms from the json response: 我收到的问题/错误是,不知道如何从json响应中获取这些术语:

{Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current 
JSON object (e.g. {"name":"value"}) into type 
'System.Collections.Generic.List`1[CoreProject.Models.Term]' because 
the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or 
change the deserialized type so that it is a normal .NET type (e.g. not a 
primitive type like integer, not a collection type like an array or List<T>) 
that can be deserialized from a JSON object. JsonObjectAttribute can also be 
added to the type to force it to deserialize from a JSON object.

Any suggestions would be greatly appreciated :) 任何建议将不胜感激 :)

You are getting that error because you are trying to deserialize the JSON into a List<T> for some T (specifically Term ), but the root JSON container is not an array, it is an object -- an unordered set of key/value pairs surrounded by { and } -- that contains a fairly deeply embedded collection of objects corresponding to your Term . 您收到该错误是因为您尝试将JSON反序列化为某些T (特别是Term )的List<T> ,但根JSON容器不是数组,它是一个对象 - 一组无序的键/值由{}包围的对 - 包含与您的Term对应的相当深的嵌入对象集合。

Given that, you could use http://json2csharp.com/ or Paste JSON as Classes to auto-generate a complete data model corresponding to your JSON, then deserialize to that model and select out the interesting portions. 鉴于此,您可以使用http://json2csharp.com/粘贴JSON作为类来自动生成与您的JSON相对应的完整数据模型,然后反序列化到该模型并选择有趣的部分。

If, however, you don't want to define a complete data model, you can selectively deserialize only the relevant portions by loading your JSON into an intermediate JToken hierarchy and then using SelectTokens() : 但是,如果您不想定义完整的数据模型,则可以通过将JSON加载到中间JToken层次结构中然后使用SelectTokens()来选择性地反序列化相关部分:

var root = JToken.Parse(responseString);
var searchTermList = root.SelectTokens("myTerms[*].Term")
    .Select(t => t.ToObject<Term>())
    .ToList();

Notes: 笔记:

  • The query string "myTerms[*].Term" contains the JSONPath wildcard operator [*] . 查询字符串"myTerms[*].Term"包含JSONPath通配符运算符[*] This operator matches all array elements under the parent element "myTerms" . 此运算符匹配父元素"myTerms"下的所有数组元素。

    Json.NET supports JSONPath syntax as documented in Querying JSON with JSONPath . Json.NET支持JSONPath语法,如使用JSONPath查询JSON中所述

  • If the JSON is more complex than is shown in your question, you can use the JSONPath recursive descent operator ... instead to find Term objects at any level in the JSON object hierarchy, eg: 如果JSON比您的问题中显示的更复杂,则可以使用JSONPath递归下降运算符...而不是在JSON对象层次结构中的任何级别查找Term对象,例如:

     var searchTermList = root.SelectTokens("..Term") .Select(t => t.ToObject<Term>()) .ToList(); 
  • Once the relevant JSON objects have been selected you can use Jtoken.ToObject<Term>() to deserialize each one to your final c# model. 一旦选择了相关的JSON对象,就可以使用Jtoken.ToObject<Term>()将每个对象反序列化为最终的c#模型。

Sample fiddle . 样品小提琴

Give this a try 试一试

public class Term
{
    public string Known { get; set; }
    public string Word { get; set; }
}
public class Response
{
    public List<TermWrapper> MyTerms { get; set; }
}
public class TermWrapper
{
    public Term Term { get; set; }
}

...

var response = await httpClient.GetAsync(uri);
string responseString = response.Content.ReadAsStringAsync().GetResults();
var searchTermList = JsonConvert
    .DeserializeObject<Response>(responseString)
    .MyTerms
    .Select(x => x.Term);

You have to consider the full structure of the JSON. 您必须考虑JSON的完整结构。 You have an object with 3 properties. 您有一个具有3个属性的对象。 The one you are interested in is an Array of Objects, but the objects are not terms, they are objects with a property called "Term". 您感兴趣的是一个对象数组,但对象不是术语,它们是具有名为“Term”的属性的对象。 That property itself is of type Term . 该属性本身属于Term类型。 By creating the classes with similar structure you can then pull all the necessary data out of the structure. 通过创建具有类似结构的类,您可以从结构中提取所有必要的数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM