SampleJsonSchemaGenerator
Generates a JSON Schema from sample JSON data.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
namespace NJsonSchema
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class SampleJsonSchemaGenerator
{
private readonly SampleJsonSchemaGeneratorSettings _settings;
public SampleJsonSchemaGenerator()
{
_settings = new SampleJsonSchemaGeneratorSettings();
}
public SampleJsonSchemaGenerator(SampleJsonSchemaGeneratorSettings settings)
{
_settings = settings;
}
public JsonSchema Generate(string json)
{
JToken token = JsonConvert.DeserializeObject<JToken>(json, new JsonSerializerSettings {
DateFormatHandling = DateFormatHandling.IsoDateFormat
});
JsonSchema jsonSchema = new JsonSchema();
Generate(token, jsonSchema, jsonSchema, "Anonymous");
return jsonSchema;
}
public JsonSchema Generate(Stream stream)
{
using (StreamReader reader = new StreamReader(stream))
using (JsonTextReader reader2 = new JsonTextReader(reader)) {
JsonSerializer jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings {
DateFormatHandling = DateFormatHandling.IsoDateFormat
});
JToken token = jsonSerializer.Deserialize<JToken>(reader2);
JsonSchema jsonSchema = new JsonSchema();
Generate(token, jsonSchema, jsonSchema, "Anonymous");
return jsonSchema;
}
}
private void Generate(JToken token, JsonSchema schema, JsonSchema rootSchema, string typeNameHint)
{
if (schema != rootSchema && token.Type == JTokenType.Object) {
JsonSchema jsonSchema = null;
JObject jObject = token as JObject;
if (jObject != null) {
IEnumerable<JProperty> properties = jObject.Properties();
jsonSchema = (from t in rootSchema.Definitions
select t.Value).FirstOrDefault(delegate(JsonSchema s) {
if ((int)s.Type == 32 && properties.Any())
return properties.All((JProperty p) => s.Properties.ContainsKey(p.Name));
return false;
});
}
if (jsonSchema == null) {
jsonSchema = new JsonSchema();
AddSchemaDefinition(rootSchema, jsonSchema, typeNameHint);
}
schema.Reference = jsonSchema;
GenerateWithoutReference(token, jsonSchema, rootSchema, typeNameHint);
} else
GenerateWithoutReference(token, schema, rootSchema, typeNameHint);
}
private void GenerateWithoutReference(JToken token, JsonSchema schema, JsonSchema rootSchema, string typeNameHint)
{
if (token == null)
return;
switch (token.Type) {
case JTokenType.Object:
GenerateObject(token, schema, rootSchema);
break;
case JTokenType.Array:
GenerateArray(token, schema, rootSchema, typeNameHint);
break;
case JTokenType.Date:
schema.Type = 64;
schema.Format = ((token.Value<DateTime>() == token.Value<DateTime>().Date) ? "date" : "date-time");
break;
case JTokenType.String:
schema.Type = 64;
break;
case JTokenType.Boolean:
schema.Type = 2;
break;
case JTokenType.Integer:
schema.Type = 4;
break;
case JTokenType.Float:
schema.Type = 16;
break;
case JTokenType.Bytes:
schema.Type = 64;
schema.Format = "byte";
break;
case JTokenType.TimeSpan:
schema.Type = 64;
schema.Format = "duration";
break;
case JTokenType.Guid:
schema.Type = 64;
schema.Format = "guid";
break;
case JTokenType.Uri:
schema.Type = 64;
schema.Format = "uri";
break;
}
if ((int)schema.Type == 64 && Regex.IsMatch(token.Value<string>(), "^[0-2][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$"))
schema.Format = "date";
if ((int)schema.Type == 64 && Regex.IsMatch(token.Value<string>(), "^[0-2][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9](:[0-9][0-9])?$"))
schema.Format = "date-time";
if ((int)schema.Type == 64 && Regex.IsMatch(token.Value<string>(), "^[0-9][0-9]:[0-9][0-9](:[0-9][0-9])?$"))
schema.Format = "duration";
if (_settings.SchemaType != SchemaType.OpenApi3)
return;
bool flag;
if ((int)schema.Type == 4) {
long? nullable = token.Value<long?>();
if (nullable.HasValue) {
long valueOrDefault = nullable.GetValueOrDefault();
if (valueOrDefault < -2147483648 || valueOrDefault > 2147483647) {
flag = true;
goto IL_01ea;
}
}
flag = false;
goto IL_01ea;
}
goto IL_0206;
IL_01ea:
if (flag)
schema.Format = "int64";
else
schema.Format = "int32";
goto IL_0206;
IL_024c:
if (flag)
schema.Format = "double";
else
schema.Format = "float";
return;
IL_0206:
if ((int)schema.Type != 16)
return;
double? nullable2 = token.Value<double?>();
if (nullable2.HasValue) {
double valueOrDefault2 = nullable2.GetValueOrDefault();
if (valueOrDefault2 < -3.4028234663852886E+38 || valueOrDefault2 > 3.4028234663852886E+38) {
flag = true;
goto IL_024c;
}
}
flag = false;
goto IL_024c;
}
private void GenerateObject(JToken token, JsonSchema schema, JsonSchema rootSchema)
{
schema.Type = 32;
foreach (JProperty item in ((JObject)token).Properties()) {
JsonSchemaProperty jsonSchemaProperty = new JsonSchemaProperty();
string input = (item.Value.Type == JTokenType.Array) ? ConversionUtilities.Singularize(item.Name) : item.Name;
string typeNameHint = ConversionUtilities.ConvertToUpperCamelCase(input, true);
Generate(item.Value, jsonSchemaProperty, rootSchema, typeNameHint);
schema.Properties[item.Name] = jsonSchemaProperty;
}
}
private void GenerateArray(JToken token, JsonSchema schema, JsonSchema rootSchema, string typeNameHint)
{
schema.Type = 1;
List<JsonSchema> list = ((JArray)token).Select(delegate(JToken item) {
JsonSchema jsonSchema = new JsonSchema();
GenerateWithoutReference(item, jsonSchema, rootSchema, typeNameHint);
return jsonSchema;
}).ToList();
if (list.Count == 0)
schema.Item = new JsonSchema();
else if ((from s in (IEnumerable<JsonSchema>)list
group s by s.Type).Count() == 1) {
MergeAndAssignItemSchemas(rootSchema, schema, list, typeNameHint);
} else {
schema.Item = list.First();
}
}
private static void MergeAndAssignItemSchemas(JsonSchema rootSchema, JsonSchema schema, List<JsonSchema> itemSchemas, string typeNameHint)
{
JsonSchema jsonSchema = itemSchemas.First();
JsonSchema jsonSchema2 = new JsonSchema {
Type = jsonSchema.Type
};
if ((int)jsonSchema.Type == 32) {
foreach (IGrouping<string, KeyValuePair<string, JsonSchemaProperty>> item in from p in itemSchemas.SelectMany((JsonSchema s) => s.Properties)
group p by p.Key) {
jsonSchema2.Properties[item.Key] = item.First().Value;
}
}
AddSchemaDefinition(rootSchema, jsonSchema2, typeNameHint);
schema.Item = new JsonSchema {
Reference = jsonSchema2
};
}
private static void AddSchemaDefinition(JsonSchema rootSchema, JsonSchema schema, string typeNameHint)
{
if (string.IsNullOrEmpty(typeNameHint) || rootSchema.Definitions.ContainsKey(typeNameHint))
rootSchema.Definitions["Anonymous" + (rootSchema.Definitions.Count + 1).ToString()] = schema;
else
rootSchema.Definitions[typeNameHint] = schema;
}
}
}