我想这是我系列问题中的另一个条目,但我又被卡住了。这次,我在使用JOA的JArray时遇到了麻烦,并为JArray中的每个元素确定了Property.Value类型......
我的代码在这里: https://dotnetfiddle.net/bRcSAQ
我之前的问题和这个问题之间的区别在于我的外部Linq查询同时获得了JObject和JArray令牌,这就是为什么我在第40行和if (jo is JObject)
有一个if (jo is JArray)
的原因在第48行。
一旦我知道我有一个<JObjects>
的JArray,我的代码就像这样(第48行 - ):
if (jo is JArray)
{
var items = jo.Children<JObject>();
// return a JObject object
}
当我使用调试器并查看项目时,我看到它包含3个JObject对象 - 一个用于Item_3A1,Item_3A2和Item3A3。但我需要知道每个JProperty.Value的JTokenType,因为我只对JTokenType.String类型的Property值感兴趣。
所以我试过了:
// doesn't work :(
var items = jo.Children<JObject>()
.Where(p => p.Value.Type == JTokenType.String);
编译器使用错误CS0119 'JToken.Value<T>(object)' is a method, which is not valid in the given context.
我意识到&#34; p&#34;在林克快递不是JProperty。我猜它是一个JObject。而且我不知道如何演员&#34; p&#34;这样我就可以检查它所代表的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"" }
这可能是我在这个&#34;系列&#34;中的最后一道障碍。
真诚地感谢能够并且将会提供帮助的任何人 - 并再次特别感谢用户&#34; Brian Rogers&#34;和&#34; dbc&#34;因为他们真正令人惊叹的JSON.NET/Linq知识。
答案 0 :(得分:2)
这会产生您需要的输出:
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<JObject> 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<JObject>().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()
是lambda expression将JObject o
映射到其属性集合,p => p.Value.Type == JTokenType.String
是映射属性p
的另一个lambda(由前一个{{1}生成}}子句)指示属性是否具有字符串值的true / false值。 SelectMany
和o
都是lambda输入参数implicitly typed。
此外,在p
部分中,将跳过父项为数组的对象,因为它们将被// No help needed in this section
子句收集。
请注意,如果(jo is JArray)
数组的不同子节点碰巧具有相同的属性名称,则jo
构造函数可能会抛出重复的键异常。
分叉fiddle。