我正在尝试检索通过SelectToken找到的JToken对象的直接父级的路径。
在上面的结构中, object.Path 的值是“ grandparent.parent.object”, object.Parent.Path 的值也是“ grandparent.parent”。对象”。
这是错误还是应该以另一种方式检索父级的路径?
下面是一个说明object.Path和object.Parent.Path相同的示例:
var input = "{'grandparent': { 'parent' : {'object' : 'value'}}}";
var jsonInput = JObject.Parse(input);
var jsonObject = jsonInput.SelectToken("..object");
var path = jsonObject.Path; //grandparent.parent.object
var parentPath = jsonObject.Parent.Path; //grandparent.parent.object (same as object)
var realParentPath = jsonObject.Parent.Parent.Path; //grandparent.parent (actual parent path)
答案 0 :(得分:1)
您偶然发现了Json.NET的实现细节,即它为具有两个容器级别的JSON对象建模,即JObject
包含collection的JProperty
项,每个项依次包含实际属性value:
JObject // A JSON object: an unordered set of name/value pairs
-> IEnumerable<JProperty> Properties()
JProperty // A property name/value pair
-> string Name // The property name
-> JToken Value // The property value
即,将图表用于https://json.org/中的对象:
JObject
对应于括号之间的整个部分,JProperty
对应于特定的string : value
部分。
我认为选择此实现是为了将名称与值分开,以便JValue
可以用于数组和对象原始值,而不必为数组添加无意义的Name
属性项目。但是,从SelectToken
的角度来看,JProperty
的存在有点尴尬,因为它与通过JSONPath查询选择的任何内容都不对应,因为SelectToken
总是返回实际值,而不是容器属性。 Newtonsoft选择使JProperty.Path
与值的路径相同;可能他们可以选择让JProperty.Path
引发异常,但是他们没有。
要隐藏此实现细节,可以引入扩展方法SelectableParent()
:
public static partial class JsonExtensions
{
public static JToken SelectableParent(this JToken token)
{
if (token == null)
return null;
var parent = token.Parent;
if (parent is JProperty)
parent = parent.Parent;
return parent;
}
}
然后按以下方式使用它:
var path = jsonObject.Path; //grandparent.parent.object
var parentPath = jsonObject.SelectableParent().Path; //grandparent.parent
演示小提琴here。
相关: Why does AddAfterSelf return 'JProperty cannot have multiple values' when used with SelectToken? 。
答案 1 :(得分:1)
下面的实际示例有助于我理解JValue及其JProperty父级之间的区别。
var input = "{'grandparent': { 'parent' : {'object' : 'value', 'object2': 'value2'}}}";
var jsonInput = JObject.Parse(input);
var jsonObject = jsonInput.SelectToken("..object");
//value
var jsonParentObject = jsonObject.Parent;
//"object": "value"
var jsonParentParentObject = jsonObject.Parent.Parent;
//{
//"object": "value",
//"object2": "value2"
//}
var jsonParentParentParentObject = jsonObject.Parent.Parent.Parent;
//"parent": {
// "object": "value",
// "object2": "value2"
//}