使用Linq查询和过滤JObjects数组 [英] Querying and Filtering Array of JObjects with Linq

查看:143
本文介绍了使用Linq查询和过滤JObjects数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想这是我一系列问题中的另一个条目,但我再次陷入困境.这次,我在使用JObjects的JArray并确定JArray中每个元素的Property.Value类型时遇到了麻烦.

I suppose this is another entry in my series of questions, but I'm stuck again. This time, I'm having trouble working with a JArray of JObjects and determining the Property.Value type for each element in the JArray...

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

我之前的问题和这个问题之间的区别是我的外部Linq查询同时获得JObject和JArray令牌,因此这就是为什么我在第40行有一个if (jo is JObject)在第48行有一个if (jo is JArray)的原因.

The difference between my previous questions and this question is that my outer Linq query gets both JObject and JArray tokens, so that's why I have an if (jo is JObject) at Line 40 and a if (jo is JArray) at Line 48.

一旦我知道我有一个<JObjects>的JArray,我就会看到类似下面的代码(第48行):

Once I know I have a JArray of <JObjects>, I have code that looks like this (Lines 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值感兴趣.

When I use a debugger and look at items, I see that it contains 3 JObject objects--one for Item_3A1, Item_3A2, and Item3A3. But I need to know the JTokenType for each JProperty.Value because I am interested only in Property values of type JTokenType.String.

所以我尝试了:

// 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.

我意识到Linq express中的"p"不是JProperty.我猜这是一个JObject.而且我不知道如何强制转换"p",以便我可以检查它代表的JProperty对象的类型.

I realize that "p" in the Linq express is not a JProperty. I guess it's a JObject. And I don't know how to cast "p" so that I can examine the type of JProperty object it represents.

最终,我需要用于JArray处理的代码(从第48行开始)添加返回JObject,该JObject包含仅由JTokenType.String类型的JProperty对象组成的JSON数组.这意味着在给定示例JSON的情况下,它首先应返回一个包含以下JSON属性的JObject:

Ultimately, I need the code for JArray processing (starting at Line 48) to add an return a JObject that contains an JSON array composed only of JProperty objects of type JTokenType.String. This means that given the sample JSON, it first should return a JObject holding these JSON properties:

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

在下一次迭代中,它应该返回一个保存以下JSON属性的JObject(注意,由于Array3B1不是具有JTokenType.String值类型的JProperty,因此省略了嵌套的Array3B1属性):

On the next iteration, it should return a JObject holding these JSON properties (notice that the nested Array3B1 properties are omitted because Array3B1 is not a JProperty with a Value type of JTokenType.String):

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

第三次迭代将包含:

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

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

And the fourth (final) iteration would contain:

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

这可能是我在系列"中的最后一个障碍.

This might be my final hurdle in this "series".

衷心感谢任何能够而且会帮助您的人,并再次特别感谢用户"Brian Rogers"和"dbc"对JSON.NET/Linq的真正了解.

Sincere thanks to anyone who can and will help--and a special thanks again to users "Brian Rogers" and "dbc" for their truly amazing JSON.NET/Linq knowledge.

推荐答案

这将产生您需要的输出:

This produces the output you require:

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表达式,将JObject o映射到其集合属性p => p.Value.Type == JTokenType.String是另一个lambda,它将属性p(由先前的SelectMany子句生成)映射到表示该属性是否具有字符串值的true/false值. op都是lambda输入参数,它们是隐式键入的.

Here I use SelectMany() to flatten the nested enumeration of properties of the enumeration of child objects of jo to a single enumeration of all properties of child objects. o => o.Properties() is a lambda expression mapping the JObject o to its collection of properties, and p => p.Value.Type == JTokenType.String is another lambda mapping a property p (generated by the previous SelectMany clause) to a true/false value indicating whether the property has a string value. Both o and p are lambda input parameters that are implicitly typed.

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

Also, in the // No help needed in this section section, objects whose parents are arrays are skipped, since they will get collected by the (jo is JArray) clause.

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

Note that if different children of the jo array happen to have identical property names, the JObject constructor may throw a duplicated key exception.

分叉的小提琴.

这篇关于使用Linq查询和过滤JObjects数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆