这是我在这里的问题
JSON.NET-从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:tempfoo.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调用GetParent Module时,会返回ProductC,而当我对ParentC调用GetParenthModule时,则会返回ProductA。
在我之前的线程中,我发现对Parent的5次调用正确地返回了我的父级。但在随后的调用中,我看到对Parent的"4"调用返回了"ProductC"。
你能解释一下发生了什么,以及如何成功地进入父层次结构吗?
我认为您感到困惑,因为有两个因素对您不利:
- Json.Net使用的实际内存层次结构与Json的心理模型不匹配
- 语法
token["property"]
通过抽象掉实际结构以更好地适应您的心理模型,简化了JSON的向下遍历。但是,向上导航没有这样的便利,所以你会暴露在所有额外的层中
让我们举一个JSON的简化示例,并更详细地探究发生了什么。假设我们有这个JSON:
{
"children": {
"ProductA": {
"children": {
"ProductC": {
"attribute": "some stuff"
}
}
}
}
}
在你的心理模型中,你有这样的:
- 一个顶级对象(没有名称),它包含
- 一个名为"children"的对象,它包含
- 一个名为"ProductA"的对象,它包含
- 一个名为"children"的对象,它包含
- 一个名为"ProductC"的对象,它包含
- 值为"somethings"的属性
- 一个名为"ProductC"的对象,它包含
- 一个名为"children"的对象,它包含
- 一个名为"ProductA"的对象,它包含
- 一个名为"children"的对象,它包含
但是Json.Net对象模型是这样工作的:
JObject
是JProperty
对象的集合JProperty
是名称-值对,其中名称是字符串,值是JObject
、JValue
或JArray
- 一个
JObject
的子代是它的JProperties
JProperty
的子级是其值
因此JSON的实际内存表示形式是:
- 一个顶级JObject,它包含
- 名为"children"的JProperty,包含
- 一个JObject,它包含
- 名为"ProductA"的JProperty,其中包含
- 一个JObject,它包含
- 名为"children"的JProperty,其中包含
- 一个JObject,它包含
- 名为"ProductC"的JProperty,其中包含
- 一个JObject,它包含
- 一个名为"attribute"的JProperty,它包含
- 字符串值为"somethings"的JValue
- 一个名为"attribute"的JProperty,它包含
- 一个JObject,它包含
- 名为"ProductC"的JProperty,其中包含
- 一个JObject,它包含
- 名为"children"的JProperty,其中包含
- 一个JObject,它包含
- 名为"ProductA"的JProperty,其中包含
- 一个JObject,它包含
- 名为"children"的JProperty,包含
当你做这样的事情时:
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的引用,该JObject是名称为"ProductC"的JProperty的值,并且我们希望向上链以获得名称为"ProductiA"的JPProperty的值)。我们该怎么做?
同样,如果你看一下Json.Net的实际结构,你可以看到它的模式。你识别为"产品"的每个JObject都在一个JProperty中,它有一个"有趣"的名称,而不是"children"。如果该产品有一个"父产品",它将有一个名为"children"的祖先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);
}