JsonPathUtilities
Utilities to work with JSON paths.
using Newtonsoft.Json.Serialization;
using NJsonSchema.Infrastructure;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace NJsonSchema
{
public static class JsonPathUtilities
{
private static readonly Lazy<CamelCasePropertyNamesContractResolver> CamelCaseResolverLazy = new Lazy<CamelCasePropertyNamesContractResolver>();
public static string GetJsonPath(object root, object objectToSearch, ISchemaDefinitionAppender schemaDefinitionAppender = null)
{
string jsonPath = GetJsonPath(root, objectToSearch, "#", new HashSet<object>());
if (jsonPath == null) {
if (schemaDefinitionAppender != null && objectToSearch is JsonSchema4) {
schemaDefinitionAppender.Append(root, (JsonSchema4)objectToSearch);
return GetJsonPath(root, objectToSearch, schemaDefinitionAppender);
}
throw new InvalidOperationException("Could not find the JSON path of a child object.");
}
return jsonPath;
}
public static JsonSchema4 GetObjectFromJsonPath(object root, string path)
{
if (path == "#") {
if (root is JsonSchema4)
return (JsonSchema4)root;
throw new InvalidOperationException("Could not resolve the path '#' because the root object is not a JsonSchema4.");
}
if (path.StartsWith("#/")) {
List<string> list = path.Split(new char[1] {
'/'
}).Skip(1).ToList();
JsonSchema4 objectFromJsonPath = GetObjectFromJsonPath(root, list, list, new HashSet<object>());
if (objectFromJsonPath == null)
throw new InvalidOperationException("Could not resolve the path '" + path + "'.");
return objectFromJsonPath;
}
if (path.StartsWith("http://") || path.StartsWith("https://")) {
if (FullDotNetMethods.SupportsFullDotNetMethods)
return JsonSchema4.FromJson(FullDotNetMethods.HttpGet(path), null);
throw new NotSupportedException("Could not resolve the path '" + path + "' because JSON web references are not supported on this platform.");
}
if (FullDotNetMethods.SupportsFullDotNetMethods) {
JsonSchema4 jsonSchema = root as JsonSchema4;
if (jsonSchema != null && jsonSchema.RootDirectory != null)
return JsonSchema4.FromJson(FullDotNetMethods.FileReadAllText(FullDotNetMethods.PathCombine(jsonSchema.RootDirectory, path)), null);
throw new NotSupportedException("Could not resolve the path '" + path + "' because no root path is available.");
}
throw new NotSupportedException("Could not resolve the path '" + path + "' because JSON file references are not supported on this platform.");
}
public static string GetPropertyName(PropertyInfo property, PropertyNameHandling propertyNameHandling)
{
switch (propertyNameHandling) {
case PropertyNameHandling.Default:
return ReflectionCache.GetProperties(property.DeclaringType).First((ReflectionCache.Property p) => p.PropertyInfo.Name == property.Name).GetName();
case PropertyNameHandling.CamelCase:
return CamelCaseResolverLazy.Value.GetResolvedPropertyName(property.Name);
default:
throw new NotSupportedException($"""{new object[1] {
propertyNameHandling
}}""");
}
}
private static string GetJsonPath(object obj, object objectToSearch, string basePath, HashSet<object> checkedObjects)
{
if (obj == null || obj is string || checkedObjects.Contains(obj))
return null;
if (obj == objectToSearch)
return basePath;
checkedObjects.Add(obj);
if (obj is IDictionary) {
foreach (object key in ((IDictionary)obj).Keys) {
string jsonPath = GetJsonPath(((IDictionary)obj)[key], objectToSearch, basePath + "/" + key, checkedObjects);
if (jsonPath != null)
return jsonPath;
}
} else if (obj is IEnumerable) {
int num = 0;
foreach (object item in (IEnumerable)obj) {
string jsonPath2 = GetJsonPath(item, objectToSearch, basePath + "/" + num, checkedObjects);
if (jsonPath2 != null)
return jsonPath2;
num++;
}
} else {
foreach (ReflectionCache.Property item2 in from p in ReflectionCache.GetProperties(obj.GetType())
where p.CustomAttributes.JsonIgnoreAttribute == null
select p) {
object value = item2.PropertyInfo.GetValue(obj);
if (value != null) {
string name = item2.GetName();
string jsonPath3 = GetJsonPath(value, objectToSearch, basePath + "/" + name, checkedObjects);
if (jsonPath3 != null)
return jsonPath3;
}
}
}
return null;
}
private static JsonSchema4 GetObjectFromJsonPath(object obj, List<string> segments, List<string> allSegments, HashSet<object> checkedObjects)
{
if (obj == null || obj is string || checkedObjects.Contains(obj))
return null;
if (segments.Count == 0) {
JsonSchema4 jsonSchema = obj as JsonSchema4;
if (jsonSchema != null && jsonSchema.TypeNameRaw == null && allSegments.Count >= 2 && allSegments.ElementAt(allSegments.Count - 2) == "definitions")
jsonSchema.TypeNameRaw = allSegments.Last();
return jsonSchema;
}
checkedObjects.Add(obj);
string text = segments[0];
if (obj is IDictionary) {
if (((IDictionary)obj).Contains(text))
return GetObjectFromJsonPath(((IDictionary)obj)[text], segments.Skip(1).ToList(), allSegments, checkedObjects);
} else if (obj is IEnumerable) {
if (int.TryParse(text, out int result)) {
object[] array = ((IEnumerable)obj).Cast<object>().ToArray();
if (array.Length > result)
return GetObjectFromJsonPath(array[result], segments.Skip(1).ToList(), allSegments, checkedObjects);
}
} else {
foreach (ReflectionCache.Property item in from p in ReflectionCache.GetProperties(obj.GetType())
where p.CustomAttributes.JsonIgnoreAttribute == null
select p) {
if (item.GetName() == text)
return GetObjectFromJsonPath(item.PropertyInfo.GetValue(obj), segments.Skip(1).ToList(), allSegments, checkedObjects);
}
}
return null;
}
}
}