I am looking for a method to select ALL the objects in the JObject
using Json.NET. So in short, if I had the following JSON:
{
"someCar" : {
"id" : "3",
"model" : "M7",
"engine" : "FI V8",
},
"name" : "carparkone",
"id" : "1",
"cars" : [
{
"id" : "1",
"model" : "s60",
"engine" : "i5",
},
{
"id" : "2",
"model" : "m3",
"engine" : "FI V6",
},
{
"id" : "3",
"model" : "M7",
"engine" : "FI V8",
}
]
}
I would run some command to get an array of all the objects in it, i.e. anything in {}
blocks.
Ideally, I would find all the objects where someProp
has some value
, so only objects that have a property engine
with a value of V6
.
tl;dr the question:
The JToken hierarchy looks like this: JToken - abstract base class JContainer - abstract base class of JTokens that can contain other JTokens JArray - represents a JSON array (contains an ordered list of JTokens) JObject - represents a JSON object (contains a collection of JProperties) JProperty - represents a JSON ...
SelectToken is a method on JToken and takes a string path to a child token. SelectToken returns the child token or a null reference if a token couldn't be found at the path's location. The path is made up of property names and array indexes separated by periods, e.g. Manufacturers[0]. Name.
Provides methods for converting between . NET types and JSON types.
You can simply convert the JObject into a Dictionary object and access the method Keys() from the Dictionary object.
You can use LINQ to JSON to parse and filter JSON objects when there is no predefined schema.
First, parse your JSON to a JObject
using JToken.Parse()
. Then you can use JContainer.DescendantsAndSelf()
to iterate through that root object, and all descendant tokens of it, in document order. (Or use JContainer.Descendants()
if you want to skip the root object.) Then you can filter then using using .OfType<JObject>()
to return all objects whether nested or not:
var root = JObject.Parse(jsonString;
var allObjs = root.DescendantsAndSelf()
.OfType<JObject>()
.ToArray();
To filter by some value, you can add an additional Where()
clause as shown in the following extension method:
public static partial class JTokenExtensions
{
public static JObject [] FilterObjects<T>(this JObject root, string someProp, T someValue)
{
var comparer = new JTokenEqualityComparer();
var someValueToken = JToken.FromObject(someValue);
var objs = root.DescendantsAndSelf()
.OfType<JObject>()
.Where(t => comparer.Equals(t[someProp], someValueToken))
.ToArray();
return objs;
}
}
And then do:
var filteredObjs = root.FilterObjects(someProp, someValue);
To make FilterObjects()
be completely generic, I serialize the desired value to a JToken
then use JTokenEqualityComparer
to compare the actual value with the desired value. If you know that the desired value is a primitive type, instead you can do:
public static partial class JTokenExtensions
{
public static bool IsNull(this JToken token)
{
return token == null || token.Type == JTokenType.Null;
}
public static JObject[] FilterObjectsSimple<T>(this JObject root, string someProp, T someValue)
{
var comparer = EqualityComparer<T>.Default;
var objs = root.DescendantsAndSelf()
.OfType<JObject>()
.Where(t => { var v = t[someProp]; return v != null && (someValue == null ? v.IsNull() : comparer.Equals(v.ToObject<T>(), someValue)); })
.ToArray();
return objs;
}
}
Sample fiddle.
Note - you might also consider using SelectTokens()
, which supports the JSONPath query syntax, e.g.:
var someProp = "id";
var someValue = "3";
var filterString = string.Format(@"..*[?(@.{0} == '{1}')]", someProp, someValue);
var filteredObjs = root.SelectTokens(filterString).ToArray();
However, your JSON includes objects nested directly inside other objects, and Newtonsoft's implementation of JSONPath does not find such directly nested objects, as explained in JSONPath scripts not executing correctly for objects #1256.
You model your data like this:
public class Carpark {
[JsonProperty(PropertyName = "name")]
public string Name{ get; set; }
[JsonProperty(PropertyName = "id")]
public int Id {get; set;}
[JsonProperty(PropertyName = "cars")]
public IEnumerable<Car> Cars { get; set; }
}
public class Car {
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
[JsonProperty(PropertyName = "model")]
public string Model { get; set; }
[JsonProperty(PropertyName = "engine")]
public string Engine { get; set; }
}
Then use the model to Deserialize your string using Json.Net.
var carpark = JsonConvert.DeserializeObject<Carpark>(myJsonString);
foreach(var car in carpark.Cars.Where(c => c.Engine.ToLower().Contains("v6"))
Console.WriteLine(car.Model);
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