使用Linq查询和过滤JObject数组

我想这是我系列问题中的另一个条目,但我又被卡住了。 这一次,我在使用JArray的JObjects和确定JArray中每个元素的Property.Value类型时遇到了麻烦……

我的代码在这里: https : //dotnetfiddle.net/bRcSAQ

我之前的问题和这个问题之间的区别在于我的外部Linq查询同时获得了JObject和JArray标记,这就是为什么我在第40行有一个if (jo is JArray)而第48行有一个if (jo is JArray)

一旦我知道我有一个 ,我就有了这样的代码(第48行):

  if (jo is JArray) { var items = jo.Children(); // return a JObject object } 

当我使用调试器并查看项目时,我看到它包含3个JObject对象 – 一个用于Item_3A1,Item_3A2和Item3A3。 但我需要知道每个JProperty.Value的JTokenType,因为我只对JTokenType.String类型的Property值感兴趣。

所以我尝试过:

 // doesn't work :( var items = jo.Children() .Where(p => p.Value.Type == JTokenType.String); 

编译器使用错误CS0119 'JToken.Value(object)' is a method, which is not valid in the given context.属性进行CS0119 'JToken.Value(object)' is a method, which is not valid in the given context.

我意识到Linq express中的“p”不是JProperty。 我想这是一个JObject。 而且我不知道如何投射“p”以便我可以检查它所代表的JProperty对象的类型。

最后,我需要JArray处理的代码(从第48行开始)添加一个返回一个JObject,它包含一个仅由JTokenType.String类型的JProperty对象组成的JSON数组。 这意味着给定样本JSON,它首先应返回一个持有这些JSON属性的JObject:

 { ""Item_3A1"": ""Desc_3A1"" }, { ""Item_3A2"": ""Desc_3A2"" }, { ""Item_3A3"": ""Desc_3A3"" } 

在下一次迭代中,它应该返回一个持有这些JSON属性的JObject(请注意,嵌套的Array3B1属性被省略,因为Array3B1不是具有值类型JTokenType.String的JProperty):

 { ""Item_3B1"": ""Desc_3B1"" }, { ""Item_3B2"": ""Desc_3B2"" }, 

第三次迭代将包含:

 { ""Item_3B11"": ""Desc_3B11"" }, { ""Item_3B12"": ""Desc_3B12"" }, { ""Item_3B13"": ""Desc_3B13"" } 

第四个(最终)迭代将包含:

 { ""Item_3C1"": ""Desc_3C1"" }, { ""Item_3C2"": ""Desc_3C2"" }, { ""Item_3C3"": ""Desc_3C3"" } 

这可能是我在这个“系列”中的最后一道障碍。

衷心感谢能够并且将会提供帮助的任何人 – 并再次特别感谢用户“Brian Rogers”和“dbc”获得真正令人惊叹的JSON.NET/Linq知识。

这会产生您需要的输出:

 var root = (JContainer)JToken.Parse(json); var query = root.Descendants() .Where(jt => (jt.Type == JTokenType.Object) || (jt.Type == JTokenType.Array)) .Select(jo => { if (jo is JObject) { if (jo.Parent != null && jo.Parent.Type == JTokenType.Array) return null; // No help needed in this section // populate and return a JObject for the List result // next line appears for compilation purposes only--I actually want a populated JObject to be returned return new JObject(); } if (jo is JArray) { var items = jo.Children().SelectMany(o => o.Properties()).Where(p => p.Value.Type == JTokenType.String); return new JObject(items); } return null; }) .Where(jo => jo != null) .ToList(); 

在这里,我使用SelectMany()jo的子对象的枚举属性的嵌套枚举展平为子对象的所有属性的单个枚举。 o => o.Properties()是将JObject o映射到其属性集合的lambda表达式 , p => p.Value.Type == JTokenType.String是映射属性p另一个lambda(由前一个SelectMany子句生成) )表示属性是否具有字符串值的true / false值。 op都是隐式输入的 lambda输入参数。

此外,在// No help needed in this section部分中,将跳过父项为数组的对象,因为它们将由(jo is JArray)子句收集。

请注意,如果jo数组的不同子JObject碰巧具有相同的属性名称,则JObject构造函数可能会抛出重复的键exception。

叉小提琴 。