<PackageReference Include="NJsonSchema" Version="9.9.0" />

JsonReferenceResolver

public class JsonReferenceResolver
Resolves JSON Pointer references.
using NJsonSchema.Infrastructure; using NJsonSchema.References; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace NJsonSchema { public class JsonReferenceResolver { private readonly JsonSchemaResolver _schemaResolver; private readonly Dictionary<string, IJsonReference> _resolvedObjects = new Dictionary<string, IJsonReference>(); public JsonReferenceResolver(JsonSchemaResolver schemaResolver) { _schemaResolver = schemaResolver; } public void AddDocumentReference(string documentPath, IJsonReference schema) { _resolvedObjects[documentPath] = schema; } public async Task<IJsonReference> ResolveReferenceAsync(object rootObject, string jsonPath) { return await ResolveReferenceAsync(rootObject, jsonPath, true); } public async Task<IJsonReference> ResolveReferenceWithoutAppendAsync(object rootObject, string jsonPath) { return await ResolveReferenceAsync(rootObject, jsonPath, false); } public virtual IJsonReference ResolveDocumentReference(object rootObject, string jsonPath) { List<string> segments = jsonPath.Split(new char[1] { '/' }).Skip(1).ToList(); IJsonReference jsonReference = ResolveDocumentReference(rootObject, segments, new HashSet<object>()); if (jsonReference == null) throw new InvalidOperationException("Could not resolve the path '" + jsonPath + "'."); return jsonReference; } public virtual async Task<IJsonReference> ResolveFileReferenceAsync(string filePath) { return await JsonSchema4.FromFileAsync(filePath, (JsonSchema4 schema) => this).ConfigureAwait(false); } public virtual async Task<IJsonReference> ResolveUrlReferenceAsync(string url) { return await JsonSchema4.FromUrlAsync(url, (JsonSchema4 schema) => this).ConfigureAwait(false); } private async Task<IJsonReference> ResolveReferenceAsync(object rootObject, string jsonPath, bool append) { if (jsonPath == "#") { if (rootObject is IJsonReference) return (IJsonReference)rootObject; throw new InvalidOperationException("Could not resolve the JSON path '#' because the root object is not a JsonSchema4."); } if (jsonPath.StartsWith("#/")) return ResolveDocumentReference(rootObject, jsonPath); if (jsonPath.StartsWith("http://") || jsonPath.StartsWith("https://")) return await ResolveUrlReferenceWithAlreadyResolvedCheckAsync(jsonPath, jsonPath, append).ConfigureAwait(false); string documentPath = (rootObject as IDocumentPathProvider)?.DocumentPath; if (documentPath != null) { if (documentPath.StartsWith("http://") || documentPath.StartsWith("https://")) return await ResolveUrlReferenceWithAlreadyResolvedCheckAsync(new Uri(new Uri(documentPath), jsonPath).ToString(), jsonPath, append).ConfigureAwait(false); return await ResolveFileReferenceWithAlreadyResolvedCheckAsync(DynamicApis.PathCombine(DynamicApis.PathGetDirectoryName(documentPath), jsonPath), jsonPath, append).ConfigureAwait(false); } throw new NotSupportedException("Could not resolve the JSON path '" + jsonPath + "' because no document path is available."); } private async Task<IJsonReference> ResolveFileReferenceWithAlreadyResolvedCheckAsync(string fullJsonPath, string jsonPath, bool append) { try { string[] arr = Regex.Split(fullJsonPath, "(?=#)"); string filePath = arr[0]; if (!_resolvedObjects.ContainsKey(filePath)) { IJsonReference jsonReference = await ResolveFileReferenceAsync(filePath).ConfigureAwait(false); jsonReference.DocumentPath = jsonPath; if ((jsonReference is JsonSchema4) & append) _schemaResolver.AppendSchema((JsonSchema4)jsonReference, filePath.Split('/', '\\').Last().Split(new char[1] { '.' }) .First()); _resolvedObjects[filePath] = jsonReference; } IJsonReference jsonReference2 = _resolvedObjects[filePath]; return (arr.Length != 1) ? (await ResolveReferenceAsync(jsonReference2, arr[1]).ConfigureAwait(false)) : jsonReference2; } catch (Exception innerException) { throw new InvalidOperationException("Could not resolve the JSON path '" + jsonPath + "' with the full JSON path '" + fullJsonPath + "'.", innerException); } } private async Task<IJsonReference> ResolveUrlReferenceWithAlreadyResolvedCheckAsync(string fullJsonPath, string jsonPath, bool append) { try { string[] arr = fullJsonPath.Split(new char[1] { '#' }); if (!_resolvedObjects.ContainsKey(arr[0])) { IJsonReference jsonReference = await ResolveUrlReferenceAsync(arr[0]).ConfigureAwait(false); jsonReference.DocumentPath = jsonPath; if ((jsonReference is JsonSchema4) & append) _schemaResolver.AppendSchema((JsonSchema4)jsonReference, null); _resolvedObjects[arr[0]] = jsonReference; } IJsonReference jsonReference2 = _resolvedObjects[arr[0]]; return (arr.Length != 1) ? (await ResolveReferenceAsync(jsonReference2, "#" + arr[1]).ConfigureAwait(false)) : jsonReference2; } catch (Exception innerException) { throw new InvalidOperationException("Could not resolve the JSON path '" + jsonPath + "' with the full JSON path '" + fullJsonPath + "'.", innerException); } } private IJsonReference ResolveDocumentReference(object obj, List<string> segments, HashSet<object> checkedObjects) { if (obj == null || obj is string || checkedObjects.Contains(obj)) return null; IJsonReference jsonReference; if ((jsonReference = (obj as IJsonReference)) != null && jsonReference.Reference != null) obj = jsonReference.Reference; if (segments.Count == 0) return obj as IJsonReference; checkedObjects.Add(obj); string text = segments[0]; if (obj is IDictionary) { if (((IDictionary)obj).Contains(text)) return ResolveDocumentReference(((IDictionary)obj)[text], segments.Skip(1).ToList(), 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 ResolveDocumentReference(array[result], segments.Skip(1).ToList(), checkedObjects); } } else { IJsonExtensionObject jsonExtensionObject = obj as IJsonExtensionObject; if (jsonExtensionObject != null && jsonExtensionObject.ExtensionData?.ContainsKey(text) == true) return ResolveDocumentReference(jsonExtensionObject.ExtensionData[text], segments.Skip(1).ToList(), checkedObjects); foreach (ReflectionCache.PropertyOrField item in from p in ReflectionCache.GetPropertiesAndFields(obj.GetType()) where p.CustomAttributes.JsonIgnoreAttribute == null select p) { if (item.GetName() == text) { object value = item.GetValue(obj); return ResolveDocumentReference(value, segments.Skip(1).ToList(), checkedObjects); } } } return null; } } }