JSON.NET - 选择所有对象

VSO*_*VSO 5 c# json json.net

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

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

理想情况下,我会找到的所有对象,其中somePropsome value,所以只有那些具有属性的对象engine具有的价值V6.

tl;博士问题:

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

dbc*_*dbc 6

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

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

var root = JObject.Parse(jsonString;
var allObjs = root.DescendantsAndSelf()
    .OfType<JObject>()
    .ToArray();
Run Code Online (Sandbox Code Playgroud)

要按某个值进行过滤,您可以添加一个附加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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后做:

var filteredObjs = root.FilterObjects(someProp, someValue);
Run Code Online (Sandbox Code Playgroud)

为了使其FilterObjects()完全通用,我将所需值序列化为 aJToken然后用于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;
    }
}
Run Code Online (Sandbox Code Playgroud)

样品小提琴

注意 - 您也可以考虑使用SelectTokens(),它支持JSONPath 查询语法,例如:

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

但是,您的 JSON 包括直接嵌套在其他对象内部的对象,并且 Newtonsoft 的 JSONPath 实现找不到此类直接嵌套的对象,如JSONPath 脚本未正确执行对象 #1256 中所述