Вы наткнулись на деталь реализации 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/:
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? .