从JToken获取Parent时的困惑



我在一个文本文件中存储了以下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" : {}
}

我使用NewtonSoft JSon用C#编写了这段代码。NET库

string content = File.ReadAllText(@"c:tempfoo.txt");
JToken token = JToken.Parse(content);
JToken p2 = token["children"]["ProductA"]["children"]["ProductC"];

这很有效,我得到了p2的节点。

但是,如果我想要p2节点中ParentA的节点。我不得不说

JToken p1 = p2.Parent.Parent.Parent.Parent.Parent;
Console.WriteLine(((JProperty)p1).Name);

上面的代码打印"ProductA"。但令人困惑的是,为什么我必须给家长打5次电话。

当我查看我的文档时,我可以看到"children""ProductC"的父级,然后"ProductA"是子级的父级。因此,对Parent的两次调用应该会得到ParentA

为什么我需要5个电话?

您正在遍历的层次结构是Json.net构建对象的方式,它不能代表Json字符串本身。

相对于ProductA对象(好吧,向上一个),这就是ProductC:

JProperty: "ProductA"
 -> JObject (ProductA object)
     -> JProperty: "children"
         -> JObject (children object)
             -> JProperty: "ProductC"
                 -> JObject (ProductC object)  *you are here

因此,如果你这样看,你应该看到你实际上是在访问JProperty"ProductA"(5个父对象),而不是对象本身。正如您可能已经注意到的,JObject没有名称,您得到的是JProperty的名称。

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

这里有一个获取父对象的实现。我不知道我们还会遇到什么其他的JToken,我们想跳过,但这只是一个开始。只需传入您想要获取的父级的令牌。传入一个可选的父编号,以指示您想要的父编号。

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();
}

最新更新