这是我在这里提出的问题的进一步

JSON.NET - Confusion in getting Parent from JToken

我仍然在理解如何在 JSON.NET 中发现父级时遇到问题

所以现在我有了这个 JSON 文档

{
    "attributes": {"attr0":"value0"},
    "children" : {
        "ProductA" : {
            "attributes": {"attr1":"value1", "attr2":"value2"},
            "children" : {
                "ProductC":{
                    "attributes": {"attr3":"value3", "attr4":"value4"},
                    "children" : {
                        "ProductD":{
                            "attributes": {"attr7":"value7", "attr8":"value8"},
                            "children" : {
                                "ProductE":{
                                    "attributes": {"attr9":"value9", "attr10":"value10"},
                                    "children" : {},
                                    "referencedChildren" : {}
                                }
                            },
                            "referencedChildren" : {}
                        }
                    },
                    "referencedChildren" : {}
                }
            },
            "referencedChildren" : {}
        },
        "ProductB" : {
            "attributes": {"attr5":"value5", "attr6":"value6"},
            "children" : {},
            "referencedChildren" : {}
        }
    },
    "referencedChildren" : {}
}

基于此,我编写了这段代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;

namespace JSonTest {
  class Program {
    static void Main(string[] args) {
      string content = File.ReadAllText(@"c:\temp\foo.txt");
      JObject token = JObject.Parse(content);
      JToken p2 = token["children"]["ProductA"]["children"]["ProductC"]["children"]["ProductD"]["children"]["ProductE"];
      JToken parent = p2;
      do {
        parent = GetParentModule(parent);
        Console.WriteLine(((JProperty)parent).Name);
      } while (parent != null);
    }

    private static JToken GetParentModule(JToken token) {
      JToken retVal = token;
      int i = 5;
      while (i > 0) {
        retVal = retVal.Parent;
        if (retVal == null) {
          break;
        } else {
          --i;
        }
      }
      return retVal;
    }
  }
}

当我运行此代码时,对 GetParentModule 的第一次调用返回“ParentD”...但第二次调用不返回“ParentC”

我的目标是,当我在 ProductE 上调用 GetParentModule 时,它​​返回 ProductD,当我在 ProductD 上调用 GetParentModule 时,它​​返回 ProductC,当我在 ParentC 上调用 GetParentModule 时,它​​返回 ProductA。

在我之前的线程中,我发现对父级的 5 次调用正确地将父级返回给了我。但在随后的调用中,我看到对 Parent 的“4”调用返回“ProductC”。

你能解释一下发生了什么以及如何成功地走上父层次结构吗?

最佳答案

我认为你很困惑,因为两个因素同时对你不利:

  • Json.Net 使用的实际内存层次结构与您的 JSON 心智模型不匹配。
  • 语法 token["property"] 通过抽象出实际结构以更好地适应您的心理模型,从而简化了 JSON 的向下遍历。但是,向上导航没有这样的便利,因此您会接触到所有额外的层。

  • 让我们举一个 JSON 的简化示例,并更详细地探讨发生了什么。假设我们有这个 JSON:
    {
        "children": {
            "ProductA": {
                "children": {
                    "ProductC": {
                        "attribute": "some stuff"
                    }
                }
            }
        }
    }
    

    在你的心智模型中,你有这个:
  • 一个顶级对象(没有名字),它包含
  • 一个名为“children”的对象,其中包含
  • 一个名为“ProductA”的对象,其中包含
  • 一个名为“children”的对象,其中包含
  • 一个名为“ProductC”的对象,其中包含
  • 一个值为“一些东西”的属性。

  • 但是 Json.Net 对象模型是这样工作的:
  • JObjectJProperty 对象的集合。
  • JProperty 是一个名称-值对,其中名称是字符串,值是 JObjectJValueJArray
  • JObject 的 child 是它的 JProperties
  • JProperty 的子代是它的值。

  • 所以 JSON 的实际内存表示是:
  • 一个顶级 JObject,它包含
  • 一个名为“children”的 JProperty,其中包含
  • 一个 JObject,其中包含
  • 一个名为“ProductA”的 JProperty,其中包含
  • 一个 JObject,其中包含
  • 一个名为“children”的 JProperty,其中包含
  • 一个 JObject,其中包含
  • 一个名为“ProductC”的 JProperty,其中包含
  • 一个 JObject,其中包含
  • 一个名为“attribute”的 JProperty,其中包含
  • 一个 JValue,字符串值为“一些东西”。

  • 所以你可以看到,你认为的单个命名对象实际上是一个包裹在命名 JProperty 中的未命名 JObject。这有助于使对象层次结构达到您预期的两倍。

    当你做这样的事情时:
    JObject productA = (JObject)top["children"]["ProductA"];
    

    这些额外的层对你是隐藏的。看起来好像每个对象(或属性)都直接嵌套在它上面的对象中。但不要被愚弄。在幕后,这个索引器语法实际上只是这个等效代码的快捷方式:
    JObject productA = (JObject)top.Children<JProperty>()
                                   .First(prop => prop.Name == "children")
                                   .Value
                                   .Children<JProperty>()
                                   .First(prop => prop.Name == "ProductA")
                                   .Value;
    

    希望现在应该清楚发生了什么,我们可以回到您真正的问题,即如何向上链并获得所需的结果。例如,假设我们有一个对产品 C 的引用,我们想要获得产品 A(或者更准确地说,我们有一个对 JObject 的引用,它是名称为“ProductC”的 JProperty 的值,我们想要向上链以获取名称为“ProductA”的 JProperty 的值)。我们怎么做?

    好吧,再一次,如果您查看实际的 Json.Net 结构,您可以看到它的模式。您确定为“产品”的每个 JObject 都位于 JProperty 中,其名称为“有趣”而不是“子项”。如果该产品有一个“父产品”,它将有一个名为“子项”的祖先 JProperty。而该 JProperty 的父级就是您想要的。

    换句话说,您需要做的就是向上走,直到找到第一个名为“children”的 JProperty,然后取该 JProperty 的父级,这应该就是您要查找的 JObject。

    在代码中:
    private static JToken GetParentModule(JToken token)
    {
        while (token != null &&
              (token.Type != JTokenType.Property ||
              ((JProperty)token).Name != "children"))
        {
            token = token.Parent;
        }
        return (token != null ? token.Parent : null);
    }
    

    关于json - 在 JSON.Net 中发现父节点的棘手业务,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20534331/

    10-12 18:50