JSON.NET - select all objects

I am looking for a method to select ALL objects in a JObject using Json.NET. 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 execute some command to get an array of all the objects in it, i.e. anything in {} .

Ideally, I would find all the objects where someProp has some value , so only objects that have an engine property with a value of V6 .

tl; dr question:

  • How to get a list of ALL objects nested in a JObject?
  • (Bonus) receive objects with specific properties.
+5
source share
2 answers

You can use LINQ to JSON to parse and filter JSON objects when there is no predefined schema.

First, break your JSON into a JObject using JToken.Parse() . Then you can use JContainer.DescendantsAndSelf() to repeat this root object and all its descendants in document order. (Or use JContainer.Descendants() if you want to skip the root object.) Then you can filter using .OfType<JObject>() to return all objects nested or not:

 var root = JObject.Parse(jsonString; var allObjs = root.DescendantsAndSelf() .OfType<JObject>() .ToArray(); 

To filter a 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() completely general, I serialize the desired value in a JToken and then the JTokenEqualityComparer to compare the actual value with the desired value. If you know that the desired value is a primitive type, you can do the following:

 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; } } 

Fiddle example.

Note. You can also use SelectTokens() , which supports JSONPath request syntax , for example:

 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 in other objects, and the Newtonsoft implementation of JSONPath does not find such directly nested objects, as described in JSONPath scripts do not execute correctly for objects # 1256 .

+4
source

You model your data as follows:

 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); 
+4
source

Source: https://habr.com/ru/post/1272405/


All Articles