JSON.NET - 选择所有对象

时间:2017-10-06 18:31:02

标签: c# json json.net

我正在寻找一种方法,使用Json.NET选择JObject中的所有对象。简而言之,如果我有以下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",
    }
  ]
}

我会运行一些命令来获取其中所有对象的数组,即{}块中的任何对象。

理想情况下,我会找到someProp具有some value的所有对象,因此只有属性engine的对象的值为V6

tl;问题:

  1. 如何获取嵌套在JObject中的所有对象的列表?
  2. (Bonus)仅获取具有特定属性的对象。

2 个答案:

答案 0 :(得分:4)

您可以像这样建模数据:

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

然后使用模型使用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);

答案 1 :(得分:4)

当没有预定义架构时,您可以使用LINQ to JSON来解析和过滤JSON对象。

首先,使用JObject将您的JSON解析为JToken.Parse()。然后,您可以使用JContainer.DescendantsAndSelf()按文档顺序遍历该根对象及其所有后代标记。 (或者如果要跳过根对象,请使用JContainer.Descendants()。)然后,您可以使用.OfType<JObject>()进行过滤,以返回所有对象,无论是否嵌套:

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

要按某些值过滤,您可以添加其他Where()子句,如以下扩展方法所示:

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

然后做:

var filteredObjs = root.FilterObjects(someProp, someValue);

要使FilterObjects()完全通用,我会将所需的值序列化为JToken,然后使用JTokenEqualityComparer将实际值与所需值进行比较。如果您知道所需的值是基本类型,则可以执行以下操作:

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

注意 - 您也可以考虑使用支持SelectTokens()JSONPath query syntax,例如:

var someProp = "id";
var someValue = "3";
var filterString = string.Format(@"..*[?(@.{0} == '{1}')]", someProp, someValue);
var filteredObjs = root.SelectTokens(filterString).ToArray();

但是,您的JSON包含直接嵌套在其他对象中的对象,而Newtonsoft的JSONPath实现找不到这样的直接嵌套对象,如JSONPath scripts not executing correctly for objects #1256中所述。