Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Json.NET get nested jToken value

Tags:

json.net

I am working at parsing a json http response with Json.NET and have working code, but am pretty sure I am going about it in an overly complicated way. My question is if there is a more direct way to get a child jToken by path and/or de-serialize it without foreaching every level.

I tried this approach but it returns null:

  JObject jObj = JObject.Parse( text );
  JToken myVal;
  jObj.TryGetValue( "response.docs", out myVal );

Here is my working overly complicated code, including de-serialization:

  JObject jObj = JObject.Parse( text );

  foreach( var kv in jObj ) {
    if( kv.Key == "response" ) {
      foreach( JToken jt in kv.Value ) {
        if( jt.Path == "response.docs" ) {
          JEnumerable<JToken> children = jt.Children();
          foreach( JToken t in children ) {       
            //THIS WORKS BUT IS NOT ELEGANT 
            Solr_User[] su = t.ToObject<Solr_User[]>();
          }
        }
      }
    }
  }

And here is the JSON raw response just for reference:

{
  "responseHeader":{
    "status":0,
    "QTime":0,
    "params":{
      "q":"*:*",
      "indent":"on",
      "wt":"json"}},
  "response":{"numFound":4,"start":0,"docs":[
      {
        "id":3,
        "first_name":"Bob",
        "_version_":"1558902640594649088"},
      {
        "id":4,
        "first_name":"Sam",
        "_version_":"1558902640613523456"},
      {
        "id":2,
        "first_name":"Fred",
        "_version_":"1558902640613523457"},
      {
        "id":1,
        "first_name":"Max",
        "_version_":"1558902640613523458"}]
  }}
like image 400
edencorbin Avatar asked Feb 17 '17 06:02

edencorbin


People also ask

Why doesn't JSON selecttoken work?

SelectToken ("data [0].user_id") doesn't work because there isn't an array in your JSON. You should use SelectToken ("data.user_id") instead. Thanks for contributing an answer to Stack Overflow!

What is the difference between jtoken index and selecttokens?

Note that SelectTokens () is slightly more forgiving than the JToken index operator, as SelectTokens () will return null for a query of the wrong type (e.g. if the value of "response" were a string literal not a nested object) while the index operator will throw an exception. Thanks for contributing an answer to Stack Overflow!

How do I get the value of a jtoken?

TryGetValue Method (String, JToken) Tries to get the JToken with the specified property name. public bool TryGetValue ( string propertyName , out JToken value ) Type: System. String Name of the property. The value. true if a value was successfully retrieved; otherwise, false. IDictionary < TKey, TValue >.

What is TryGetValue method in jtoken?

TryGetValue Method (String, JToken) Tries to get the JToken with the specified property name. public bool TryGetValue ( string propertyName , out JToken value ) Type: System. String Name of the property.


1 Answers

You can use SelectToken() to select a token from deep within the LINQ-to-JSON hierarchy for deserialization. In two lines:

var token = jObj.SelectToken("response.docs");
var su = token == null ? null : token.ToObject<Solr_User []>();

Or in one line, by conditionally deserializing a null JToken when the selected token is missing:

var su = (jObj.SelectToken("response.docs") ?? JValue.CreateNull()).ToObject<Solr_User []>();

Sample fiddle.

In c# 6 or later it's even easier to deserialize a nested token in one line using the null conditional operator:

var su = jObj.SelectToken("response.docs")?.ToObject<Solr_User []>();

Or even

var su = jObj?["response"]?["docs"]?.ToObject<Solr_User []>();

Note that SelectTokens() is slightly more forgiving than the JToken index operator, as SelectTokens() will return null for a query of the wrong type (e.g. if the value of "response" were a string literal not a nested object) while the index operator will throw an exception.

like image 189
dbc Avatar answered Jan 04 '23 05:01

dbc