我试图检索通过SelectToken找到的JToken对象的直接父对象的路径。
在上面的结构中,object.Path的值是“grandparent.parent.object”,object.Parent.Path的值也是“grandparent.parent.object”。
这是一个错误还是应该以另一种方式检索父路径?
下面是一个示例,说明了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)
您偶然发现了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?。
以下实际示例帮助我理解了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"
//}