从JToken获得Parent的困惑

Kno*_*uch 9 c# json json.net

我将以下JSON文档存储在文本文件中

{
    "attributes": {"attr0":"value0"},
    "children" : {
        "ProductA" : {
            "attributes": {"attr1":"value1", "attr2":"value2"}, 
            "children" : {
                "ProductC":{
                    "attributes": {"attr3":"value3", "attr4":"value4"}, 
                    "children" : {}, 
                    "referencedChildren" : {}
                }
            }, 
            "referencedChildren" : {}
        }, 
        "ProductB" : {
            "attributes": {"attr5":"value5", "attr6":"value6"}, 
            "children" : {}, 
            "referencedChildren" : {}
        }
    },
    "referencedChildren" : {}
}
Run Code Online (Sandbox Code Playgroud)

我使用NewtonSoft JSon.NET Library在C#中编写了这段代码

string content = File.ReadAllText(@"c:\temp\foo.txt");
JToken token = JToken.Parse(content);
JToken p2 = token["children"]["ProductA"]["children"]["ProductC"];
Run Code Online (Sandbox Code Playgroud)

这有效,我得到了节点p2.

但是,如果我想为节点ParentAp2节点.我不得不说

JToken p1 = p2.Parent.Parent.Parent.Parent.Parent;
Console.WriteLine(((JProperty)p1).Name);
Run Code Online (Sandbox Code Playgroud)

上面的代码打印出来"ProductA".但令人困惑的是,为什么我要打电话给父母5次.

当我查看我的文档时,我可以看到它"children"是父母,"ProductC"然后"ProductA"是孩子的父母.因此2个电话Parent应该得到我ParentA.

为什么我需要5个电话?

Jef*_*ado 9

您正在遍历的层次结构是Json.net如何构造对象,它不代表json字符串本身.

相对于ProductA对象(好吧,一个),这是你如何做到ProductC:

JProperty: "ProductA"
 -> JObject (ProductA object)
     -> JProperty: "children"
         -> JObject (children object)
             -> JProperty: "ProductC"
                 -> JObject (ProductC object)  *you are here
Run Code Online (Sandbox Code Playgroud)

因此,如果以这种方式看待它,您应该看到您实际上正在访问JProperty"ProductA"(5个父母),而不是对象本身.正如你可能已经注意到的,JObjects没有名字,你得到的名字JProperty.

我不能告诉你你是如何访问它的,因为它在json字符串中描述,它似乎不是一个选项.但是你当然可以编写一些辅助方法来为你获取它们.

这是获取父对象的一个​​实现.我不知道我们想要跳过的其他JTokens,但这是一个开始.只需传入您想要获得父级的令牌即可.传入可选的父编号以指示您想要的父级.

JToken GetParent(JToken token, int parent = 0)
{
    if (token == null)
        return null;
    if (parent < 0)
        throw new ArgumentOutOfRangeException("Must be positive");

    var skipTokens = new[]
    {
        typeof(JProperty),
    };
    return token.Ancestors()
        .Where(a => skipTokens.All(t => !t.IsInstanceOfType(a)))
        .Skip(parent)
        .FirstOrDefault();
}
Run Code Online (Sandbox Code Playgroud)