JsonReferenceResolver
Resolves JSON Pointer references.
using NJsonSchema.Infrastructure;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace NJsonSchema
{
public class JsonReferenceResolver
{
private readonly Dictionary<string, JsonSchema4> _resolvedSchemas = new Dictionary<string, JsonSchema4>();
public void AddDocumentReference(string documentPath, JsonSchema4 schema)
{
_resolvedSchemas[documentPath] = schema;
}
public JsonSchema4 ResolveReference(object rootObject, string jsonPath)
{
if (jsonPath == "#") {
if (rootObject is JsonSchema4)
return (JsonSchema4)rootObject;
throw new InvalidOperationException("Could not resolve the path '#' because the root object is not a JsonSchema4.");
}
if (jsonPath.StartsWith("#/")) {
List<string> list = jsonPath.Split(new char[1] {
'/'
}).Skip(1).ToList();
JsonSchema4 jsonSchema = ResolveReference(rootObject, list, list, new HashSet<object>());
if (jsonSchema == null)
throw new InvalidOperationException("Could not resolve the path '" + jsonPath + "'.");
return jsonSchema;
}
if (jsonPath.StartsWith("http://") || jsonPath.StartsWith("https://"))
return ResolveUrlReference(jsonPath, jsonPath);
string text = (rootObject as IDocumentPathProvider)?.DocumentPath;
if (text != null) {
if (text.StartsWith("http://") || text.StartsWith("https://")) {
string filePath = new Uri(new Uri(text), jsonPath).ToString();
return ResolveUrlReference(filePath, jsonPath);
}
string url = DynamicApis.PathCombine(DynamicApis.PathGetDirectoryName(text), jsonPath);
return ResolveFileReference(url, jsonPath);
}
throw new NotSupportedException("Could not resolve the path '" + jsonPath + "' because no document path is available.");
}
private JsonSchema4 ResolveReference(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 ResolveReference(((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 ResolveReference(array[result], segments.Skip(1).ToList(), allSegments, checkedObjects);
}
} else {
foreach (ReflectionCache.PropertyOrField item in from p in ReflectionCache.GetProperties(obj.GetType())
where p.CustomAttributes.JsonIgnoreAttribute == null
select p) {
if (item.GetName() == text) {
object value = item.GetValue(obj);
return ResolveReference(value, segments.Skip(1).ToList(), allSegments, checkedObjects);
}
}
}
return null;
}
private JsonSchema4 ResolveFileReference(string url, string jsonPath)
{
if (DynamicApis.SupportsFileApis)
try {
string[] array = Regex.Split(url, "(?=#)");
if (!_resolvedSchemas.ContainsKey(array[0]))
JsonSchema4.FromFile(array[0], this);
JsonSchema4 jsonSchema = _resolvedSchemas[array[0]];
return (array.Length == 1) ? jsonSchema : ResolveReference(jsonSchema, array[1]);
} catch (Exception ex) {
throw new InvalidOperationException("Could not resolve the path '" + jsonPath + "' with the file path '" + url + "': " + ex.Message, ex);
}
throw new NotSupportedException("Could not resolve the path '" + jsonPath + "' because JSON file references are not supported on this platform.");
}
private JsonSchema4 ResolveUrlReference(string filePath, string jsonPath)
{
if (DynamicApis.SupportsWebClientApis)
try {
string[] array = filePath.Split(new char[1] {
'#'
});
if (!_resolvedSchemas.ContainsKey(array[0]))
JsonSchema4.FromUrl(array[0], this);
JsonSchema4 jsonSchema = _resolvedSchemas[array[0]];
return (array.Length == 1) ? jsonSchema : ResolveReference(jsonSchema, "#" + array[1]);
} catch (Exception ex) {
throw new InvalidOperationException("Could not resolve the path '" + jsonPath + "' with the URL '" + filePath + "': " + ex.Message, ex);
}
throw new NotSupportedException("Could not resolve the path '" + jsonPath + "' because JSON web references are not supported on this platform.");
}
}
}