Json.Net - 未返回直接 parent 路径

Json.Net - Immediate parent path not being returned

我正在尝试检索通过 SelectToken 找到的 JToken object 的直接路径 parent。

在上面的结构中,object.Path的值为"grandparent.parent.object",object.Parent.Path[=35=的值为] 也是 "grandparent.parent.object".

这是一个错误还是应该以其他方式检索 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)

您无意中发现了 Json.NET 的一个实现细节,即它使用两层容器对 JSON 对象建模,即 JObject which contains a collection of JProperty items, each of which in turn contains the actual property 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/object 的图表:

JObject对应大括号之间的整个部分,JProperty对应特定的string : value部分。

我认为选择此实现是为了将名称与值分开,因此 JValue could be used for both array and object primitive values, without having to add in a meaningless Name property for array items. However, from the point of view of SelectToken, the existence of JProperty is a bit awkward because it doesn't correspond to anything selectable via a JSONPath 查询因为 SelectToken 总是 returns 实际值而不是容器 属性. 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

演示 fiddle here.

相关:.

下面的实际例子帮助我理解了 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"
//}