简体   繁体   中英

Deserialize objects from array nested inside Json response

I'm trying to deserialize some objects nested inside a Json response using Newtonsoft.Json. I want to deserialize the following Jsons Term objects into a list. I have many Term objects in the Json response, so performance and compactness is important to me. I also would only like to define the Term class as I do not care about the other data for the time being.

I have a model defined for Term:

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

My Json looks like this:

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

My C# deserializing code:

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:

{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 .

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.

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() :

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 [*] . This operator matches all array elements under the parent element "myTerms" .

    Json.NET supports JSONPath syntax as documented in Querying JSON with JSONPath .

  • 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:

     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.

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. You have an object with 3 properties. 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". That property itself is of type Term . By creating the classes with similar structure you can then pull all the necessary data out of the structure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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