Json.Net - Прямой родительский путь не возвращается - PullRequest
1 голос
/ 19 марта 2019

Я пытаюсь получить путь непосредственного родителя объекта JToken, найденного через SelectToken.

  • прародитель
    • родитель
      • объект

В приведенной выше структуре значение 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)

Ответы [ 2 ]

1 голос
/ 23 марта 2019

Следующий практический пример помог мне понять различия между 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"
//}
1 голос
/ 22 марта 2019

Вы наткнулись на деталь реализации Json.NET, которая заключается в том, что она моделирует объект JSON с двумя уровнями контейнера, а именно JObject, который содержит коллекцию JProperty элементов, каждый из которых, в свою очередь, содержит фактическое свойство значение :

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/:

JSON object

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

Демонстрационная скрипка здесь .

Связано: Почему AddAfterSelf возвращает 'JProperty не может иметь несколько значений'при использовании с SelectToken? .

...