【问题标题】:Linq-To-JSON Walking Up Ancestor Tree To Obtain JProperty for Nearest ParentLinq-To-JSON 遍历祖先树以获取最近父级的 JProperty
【发布时间】:2017-03-11 10:46:55
【问题描述】:

我在这里有一个小提琴: https://dotnetfiddle.net/x6u5wH

我有两个问题,但为了公平起见,我会将它们分成两个帖子。发布后,我将在本文顶部添加指向第二个问题的链接。

总结 如果您运行上述小提琴,您将看到结果显示正在处理的 JProperty。很好。

问题是“Immediate Ancestor Property Name”的值,目前显示的是预期值。但是,如果我希望祖先的值显示作为最近父的祖先的 JProperty 名称怎么办?我将解释我所说的“最近的父母”是什么意思,因为它可能有一个我不知道的实际 JSON 术语。

为了说明,让我们关注 JSON 中的 Data7 属性。注意它是 JArray Data5 中的第二个元素(Data6 是第一个)。

问题 我想做的是创建一个 Linq 查询,查看当前属性,然后向上查找最近的父属性的祖先树。从 Data8 开始,最近的父节点是 Data7。但是,与 Data7 最接近的父级将是 Data4,而不是 Data5。我不认为 Data5 是最近的父级,因为 Data5 是一个包含 Data6 和 Data7 的 JArray。当涉及 JArrays 时,我想要 JArray 的父级,无论是 JArray 还是 JObject。 Data6 的父级也是 Data4。

Data4 的父级是 Data3;对于 Data3,父级是 Data2;对于 Data2,父级将是 Data1(Data 将有一个 null/空父级)。

谢谢。

附:万一小提琴消失了,这里是有问题的代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;

    public class Program
    {
        public static void Main()
        {
            string json = @"{
  ""Data1"": {
    ""SPECIAL"": ""QQ01"",
    ""AA"": ""QQ"",
    ""BB"": ""QQ"",
    ""Data2"": [
      {
        ""SPECIAL"": ""QQ02"",
        ""AA"": ""QQ"",
        ""BB"": ""QQ"",
        ""CC"": ""QQ"",
        ""Data3"": [
          {
            ""SPECIAL"": ""QQ03"",
            ""AA"": ""QQ"",
            ""CC"": ""QQ"",
            ""Data4"": [
              {
                ""SPECIAL"": ""QQ04"",
                ""AA"": ""QQ"",
                ""CC"": ""QQ"",
                ""Data5"": [
                  {
                    ""SPECIAL"": ""QQ05"",
                    ""AA"": ""QQ"",
                    ""CC"": ""QQ"",
                    ""Data6"": [
                      {
                        ""SPECIAL"": ""QQ06"",
                        ""AA"": ""QQ"",
                        ""CC"": ""QQ""
                      }
                    ]
                  },
                  {
                    ""SPECIAL"": ""QQ07"",
                    ""AA"": ""QQ"",
                    ""CC"": ""QQ"",
                    ""DD"": ""QQ"",
                    ""Data7"": [
                      {
                        ""SPECIAL"": ""QQ08"",
                        ""AA"": ""QQ"",
                        ""CC"": ""QQ"",
                        ""Data8"": [
                          {
                            ""SPECIAL"": ""QQ09"",
                            ""AA"": ""QQ"",
                            ""BB"": ""QQ"",
                            ""CC"": ""QQ""
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  },
  ""Data9"":
  {
    ""SPECIAL"": ""QQ10"",
    ""AA"": ""QQ"",
    ""BB"": ""QQ"",
    ""CC"": ""QQ"",
    ""Data10"":
    {
        ""SPECIAL"": ""QQ11"",
        ""AA"": ""QQ"",
        ""BB"": ""QQ"",
        ""CC"": ""QQ"",
        ""Data11"":
        {
            ""SPECIAL"": ""QQ12"",
            ""AA"": ""QQ"",
            ""BB"": ""QQ"",
            ""CC"": ""QQ""                  
        }
    }
  }
}";

            List<JObject> list = 
                JObject.Parse(json)
                .Descendants()
                .Where(jt => jt.Type == JTokenType.Property && ((JProperty)jt).Value.HasValues)
                .Cast<JProperty>()
                .Select(prop =>
                {

                    var parentName = prop.Ancestors()
                                         .Where(jt => jt.Type == JTokenType.Property)
                                         .Select(jt => ((JProperty)jt).Name)
                                         .FirstOrDefault();
                    var obj = new JObject(new JProperty("Current Property", prop.Name));

                    obj.Add(new JProperty("Immediate Ancestor Property Name", parentName ?? ""));


    // HERE***  (Question 2)
                    // here I would like to be able to add a new JObject property (just like I do above with "Parent")
                    // but this time I want to add the property values for Item1 and Item2 for a specific ancestor. 
                    // To achieve this, I want to grab all of the properties for an ancestor.

                    return obj;
                })
                .ToList();


            for (int i = 0; i < list.Count; i++)
            {
                Console.WriteLine("list[" + i + "]:");
                Console.WriteLine(list[i].ToString(Formatting.None));
                Console.WriteLine();
            }
        }
    }

【问题讨论】:

  • 您确实意识到在您的 JSON 中,DataX 属性中的 ALL 都包含 JArray,除了 Data1Data5 是唯一一个有多个子元素的数组,但其他数组仍然是数组,即使它们每个只有一个子元素。
  • 嗨,布莱恩,我的懒惰。我刚刚从您回答的上一个问题中重用了我的 JSON。我的实际 JSON(数千字节)确实具有不是数组的 DataX 元素。我修改了我的问题中的 JSON,并通过在不是数组的末尾添加另一个 DataX 块来更新提琴手以反映更改。谢谢。
  • 您真的想要值不是JArray 类型的父母,还是您真的想要值不是JArray 的具有多个元素的父母?对于前者,所有的父母都是"Data1",见here。对于后者,请参阅here
  • 看到你的例子后,我需要思考一下。但是,您的两个小提琴链接(每个不同)似乎包含相同的代码和结果......谢谢。
  • 在一个不寻常的事件中,第二小提琴获胜。 :) 这正是我所需要的。请作为建议的答案提交,我将接受并奖励。您使用 .Count 在 lambda 中所做的非常聪明——如果需要,我将研究进一步定制。非常感谢。

标签: c# json json.net linq-to-json


【解决方案1】:

听起来好像您想要最低的父 JProperty,其值不是数组,或者是只有一项的数组。如果是这样,你可以这样做:

var list = 
    JObject.Parse(json)
    .Descendants()
    .OfType<JProperty>()
    .Where(prop => prop.Value.HasValues)
    .Select(prop =>
    {

        var parentName = prop.Ancestors()
                             .OfType<JProperty>()
                             .Where(p => !(p.Value is JArray && ((JArray)p.Value).Count > 1))
                             .Select(p => p.Name)
                             .FirstOrDefault();
        var obj = new JObject(new JProperty("Current Property", prop.Name));

        obj.Add(new JProperty("Immediate Ancestor Property Name", parentName ?? ""));


        return obj;
    })
    .ToList();

这给出了所需的父列表。原型fiddle.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    • 2013-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多