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"}]
}}
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!
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!
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 >.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With