Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/Newtonsoft.Json.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamesNK <james@newtonking.com>2011-01-02 12:19:53 +0300
committerJamesNK <james@newtonking.com>2011-01-02 12:19:53 +0300
commitf00d796e03c565424071b30d345fd72a2e3eb6ee (patch)
tree56366a0d528052c63ee312c39299ad32fad06631 /Src/Newtonsoft.Json
parent3ad33f73299e6a8f05405d5b49a30ad1702a756a (diff)
-Added PatternProperties, ExclusiveMinimum and ExclusiveMaximum support to JSON schema
Diffstat (limited to 'Src/Newtonsoft.Json')
-rw-r--r--Src/Newtonsoft.Json/JsonValidatingReader.cs224
-rw-r--r--Src/Newtonsoft.Json/Schema/JsonSchema.cs19
-rw-r--r--Src/Newtonsoft.Json/Schema/JsonSchemaBuilder.cs30
-rw-r--r--Src/Newtonsoft.Json/Schema/JsonSchemaConstants.cs3
-rw-r--r--Src/Newtonsoft.Json/Schema/JsonSchemaModel.cs6
-rw-r--r--Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs34
-rw-r--r--Src/Newtonsoft.Json/Schema/JsonSchemaNode.cs3
-rw-r--r--Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs30
8 files changed, 264 insertions, 85 deletions
diff --git a/Src/Newtonsoft.Json/JsonValidatingReader.cs b/Src/Newtonsoft.Json/JsonValidatingReader.cs
index 6fc83ce..5bace6d 100644
--- a/Src/Newtonsoft.Json/JsonValidatingReader.cs
+++ b/Src/Newtonsoft.Json/JsonValidatingReader.cs
@@ -43,15 +43,15 @@ namespace Newtonsoft.Json
private class SchemaScope
{
private readonly JTokenType _tokenType;
- private readonly JsonSchemaModel _schema;
+ private readonly IList<JsonSchemaModel> _schemas;
private readonly Dictionary<string, bool> _requiredProperties;
public string CurrentPropertyName { get; set; }
public int ArrayItemCount { get; set; }
- public JsonSchemaModel Schema
+ public IList<JsonSchemaModel> Schemas
{
- get { return _schema; }
+ get { return _schemas; }
}
public Dictionary<string, bool> RequiredProperties
@@ -64,19 +64,19 @@ namespace Newtonsoft.Json
get { return _tokenType; }
}
- public SchemaScope(JTokenType tokenType, JsonSchemaModel schema)
+ public SchemaScope(JTokenType tokenType, IList<JsonSchemaModel> schemas)
{
_tokenType = tokenType;
- _schema = schema;
+ _schemas = schemas;
- if (_schema != null && _schema.Properties != null)
- _requiredProperties = GetRequiredProperties(_schema).Distinct().ToDictionary(p => p, p => false);
- else
- _requiredProperties = new Dictionary<string, bool>();
+ _requiredProperties = schemas.SelectMany(GetRequiredProperties).Distinct().ToDictionary(p => p, p => false);
}
private IEnumerable<string> GetRequiredProperties(JsonSchemaModel schema)
{
+ if (schema == null || schema.Properties == null)
+ return Enumerable.Empty<string>();
+
return schema.Properties.Where(p => p.Value.Required).Select(p => p.Key);
}
}
@@ -154,47 +154,79 @@ namespace Newtonsoft.Json
return poppedScope;
}
- private JsonSchemaModel CurrentSchema
+ private IEnumerable<JsonSchemaModel> CurrentSchemas
{
- get { return _currentScope.Schema; }
+ get { return _currentScope.Schemas; }
}
- private JsonSchemaModel CurrentMemberSchema
+ private IEnumerable<JsonSchemaModel> CurrentMemberSchemas
{
get
{
if (_currentScope == null)
- return _model;
+ return new List<JsonSchemaModel>(new [] { _model });
- if (_currentScope.Schema == null)
- return null;
+ if (_currentScope.Schemas == null || _currentScope.Schemas.Count == 0)
+ return Enumerable.Empty<JsonSchemaModel>();
switch (_currentScope.TokenType)
{
case JTokenType.None:
- return _currentScope.Schema;
+ return _currentScope.Schemas;
case JTokenType.Object:
- if (_currentScope.CurrentPropertyName == null)
- throw new Exception("CurrentPropertyName has not been set on scope.");
-
- JsonSchemaModel propertySchema;
- if (CurrentSchema.Properties != null && CurrentSchema.Properties.TryGetValue(_currentScope.CurrentPropertyName, out propertySchema))
- return propertySchema;
-
- return (CurrentSchema.AllowAdditionalProperties) ? CurrentSchema.AdditionalProperties : null;
+ {
+ if (_currentScope.CurrentPropertyName == null)
+ throw new Exception("CurrentPropertyName has not been set on scope.");
+
+ IList<JsonSchemaModel> schemas = new List<JsonSchemaModel>();
+
+ foreach (JsonSchemaModel schema in CurrentSchemas)
+ {
+ JsonSchemaModel propertySchema;
+ if (schema.Properties != null && schema.Properties.TryGetValue(_currentScope.CurrentPropertyName, out propertySchema))
+ {
+ schemas.Add(propertySchema);
+ }
+ if (schema.PatternProperties != null)
+ {
+ foreach (KeyValuePair<string, JsonSchemaModel> patternProperty in schema.PatternProperties)
+ {
+ if (Regex.IsMatch(_currentScope.CurrentPropertyName, patternProperty.Key))
+ {
+ schemas.Add(patternProperty.Value);
+ }
+ }
+ }
+
+ if (schemas.Count == 0 && schema.AllowAdditionalProperties && schema.AdditionalProperties != null)
+ schemas.Add(schema.AdditionalProperties);
+ }
+
+ return schemas;
+ }
case JTokenType.Array:
- if (!CollectionUtils.IsNullOrEmpty(CurrentSchema.Items))
{
- if (CurrentSchema.Items.Count == 1)
- return CurrentSchema.Items[0];
-
- if (CurrentSchema.Items.Count > (_currentScope.ArrayItemCount - 1))
- return CurrentSchema.Items[_currentScope.ArrayItemCount - 1];
+ IList<JsonSchemaModel> schemas = new List<JsonSchemaModel>();
+
+ foreach (JsonSchemaModel schema in CurrentSchemas)
+ {
+ if (!CollectionUtils.IsNullOrEmpty(schema.Items))
+ {
+ if (schema.Items.Count == 1)
+ schemas.Add(schema.Items[0]);
+
+ if (schema.Items.Count > (_currentScope.ArrayItemCount - 1))
+ schemas.Add(schema.Items[_currentScope.ArrayItemCount - 1]);
+ }
+
+ if (schema.AllowAdditionalProperties && schema.AdditionalProperties != null)
+ schemas.Add(schema.AdditionalProperties);
+ }
+
+ return schemas;
}
-
- return (CurrentSchema.AllowAdditionalProperties) ? CurrentSchema.AdditionalProperties : null;
case JTokenType.Constructor:
- return null;
+ return Enumerable.Empty<JsonSchemaModel>();
default:
throw new ArgumentOutOfRangeException("TokenType", "Unexpected token type: {0}".FormatWith(CultureInfo.InvariantCulture, _currentScope.TokenType));
}
@@ -371,58 +403,80 @@ namespace Newtonsoft.Json
_model = builder.Build(_schema);
}
+ //ValidateValueToken();
+
switch (_reader.TokenType)
{
case JsonToken.StartObject:
ProcessValue();
- JsonSchemaModel objectSchema = (ValidateObject(CurrentMemberSchema))
- ? CurrentMemberSchema
- : null;
- Push(new SchemaScope(JTokenType.Object, objectSchema));
+ IList<JsonSchemaModel> objectSchemas = CurrentMemberSchemas.Where(ValidateObject).ToList();
+ Push(new SchemaScope(JTokenType.Object, objectSchemas));
break;
case JsonToken.StartArray:
ProcessValue();
- JsonSchemaModel arraySchema = (ValidateArray(CurrentMemberSchema))
- ? CurrentMemberSchema
- : null;
- Push(new SchemaScope(JTokenType.Array, arraySchema));
+ IList<JsonSchemaModel> arraySchemas = CurrentMemberSchemas.Where(ValidateArray).ToList();
+ Push(new SchemaScope(JTokenType.Array, arraySchemas));
break;
case JsonToken.StartConstructor:
Push(new SchemaScope(JTokenType.Constructor, null));
break;
case JsonToken.PropertyName:
- ValidatePropertyName(CurrentSchema);
+ foreach (JsonSchemaModel schema in CurrentSchemas)
+ {
+ ValidatePropertyName(schema);
+ }
break;
case JsonToken.Raw:
break;
case JsonToken.Integer:
ProcessValue();
- ValidateInteger(CurrentMemberSchema);
+ foreach (JsonSchemaModel schema in CurrentMemberSchemas)
+ {
+ ValidateInteger(schema);
+ }
break;
case JsonToken.Float:
ProcessValue();
- ValidateFloat(CurrentMemberSchema);
+ foreach (JsonSchemaModel schema in CurrentMemberSchemas)
+ {
+ ValidateFloat(schema);
+ }
break;
case JsonToken.String:
ProcessValue();
- ValidateString(CurrentMemberSchema);
+ foreach (JsonSchemaModel schema in CurrentMemberSchemas)
+ {
+ ValidateString(schema);
+ }
break;
case JsonToken.Boolean:
ProcessValue();
- ValidateBoolean(CurrentMemberSchema);
+ foreach (JsonSchemaModel schema in CurrentMemberSchemas)
+ {
+ ValidateBoolean(schema);
+ }
break;
case JsonToken.Null:
ProcessValue();
- ValidateNull(CurrentMemberSchema);
+ foreach (JsonSchemaModel schema in CurrentMemberSchemas)
+ {
+ ValidateNull(schema);
+ }
break;
case JsonToken.Undefined:
break;
case JsonToken.EndObject:
- ValidateEndObject(CurrentSchema);
+ foreach (JsonSchemaModel schema in CurrentSchemas)
+ {
+ ValidateEndObject(schema);
+ }
Pop();
break;
case JsonToken.EndArray:
- ValidateEndArray(CurrentSchema);
+ foreach (JsonSchemaModel schema in CurrentSchemas)
+ {
+ ValidateEndArray(schema);
+ }
Pop();
break;
case JsonToken.EndConstructor:
@@ -528,11 +582,24 @@ namespace Newtonsoft.Json
long value = Convert.ToInt64(_reader.Value, CultureInfo.InvariantCulture);
- if (schema.Maximum != null && value > schema.Maximum)
- RaiseError("Integer {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Maximum), schema);
+ if (schema.Maximum != null)
+ {
+ if (value > schema.Maximum)
+ RaiseError("Integer {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Maximum), schema);
+ if (schema.ExclusiveMaximum && value == schema.Maximum)
+ RaiseError("Integer {0} equals maximum value of {1} and exclusive maximum is true.".FormatWith(CultureInfo.InvariantCulture, value, schema.Maximum), schema);
+ }
+
+ if (schema.Minimum != null)
+ {
+ if (value < schema.Minimum)
+ RaiseError("Integer {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Minimum), schema);
+ if (schema.ExclusiveMinimum && value == schema.Minimum)
+ RaiseError("Integer {0} equals minimum value of {1} and exclusive minimum is true.".FormatWith(CultureInfo.InvariantCulture, value, schema.Minimum), schema);
+ }
- if (schema.Minimum != null && value < schema.Minimum)
- RaiseError("Integer {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Minimum), schema);
+ if (schema.DivisibleBy != null && !IsZero(value % schema.DivisibleBy.Value))
+ RaiseError("Integer {0} is not evenly divisible by {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.DivisibleBy), schema);
}
private void ProcessValue()
@@ -541,8 +608,11 @@ namespace Newtonsoft.Json
{
_currentScope.ArrayItemCount++;
- if (CurrentSchema != null && CurrentSchema.Items != null && CurrentSchema.Items.Count > 1 && _currentScope.ArrayItemCount >= CurrentSchema.Items.Count)
- RaiseError("Index {0} has not been defined and the schema does not allow additional items.".FormatWith(CultureInfo.InvariantCulture, _currentScope.ArrayItemCount), CurrentSchema);
+ foreach (JsonSchemaModel currentSchema in CurrentSchemas)
+ {
+ if (currentSchema != null && currentSchema.Items != null && currentSchema.Items.Count > 1 && _currentScope.ArrayItemCount >= currentSchema.Items.Count)
+ RaiseError("Index {0} has not been defined and the schema does not allow additional items.".FormatWith(CultureInfo.InvariantCulture, _currentScope.ArrayItemCount), currentSchema);
+ }
}
}
@@ -558,11 +628,21 @@ namespace Newtonsoft.Json
double value = Convert.ToDouble(_reader.Value, CultureInfo.InvariantCulture);
- if (schema.Maximum != null && value > schema.Maximum)
- RaiseError("Float {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Maximum), schema);
+ if (schema.Maximum != null)
+ {
+ if (value > schema.Maximum)
+ RaiseError("Float {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Maximum), schema);
+ if (schema.ExclusiveMaximum && value == schema.Maximum)
+ RaiseError("Float {0} equals maximum value of {1} and exclusive maximum is true.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Maximum), schema);
+ }
- if (schema.Minimum != null && value < schema.Minimum)
- RaiseError("Float {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Minimum), schema);
+ if (schema.Minimum != null)
+ {
+ if (value < schema.Minimum)
+ RaiseError("Float {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Minimum), schema);
+ if (schema.ExclusiveMinimum && value == schema.Minimum)
+ RaiseError("Float {0} equals minimum value of {1} and exclusive minimum is true.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Minimum), schema);
+ }
if (schema.DivisibleBy != null && !IsZero(value % schema.DivisibleBy.Value))
RaiseError("Float {0} is not evenly divisible by {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.DivisibleBy), schema);
@@ -585,14 +665,34 @@ namespace Newtonsoft.Json
if (_currentScope.RequiredProperties.ContainsKey(propertyName))
_currentScope.RequiredProperties[propertyName] = true;
- bool propertyDefinied = (schema.Properties != null && schema.Properties.ContainsKey(propertyName));
+ if (!schema.AllowAdditionalProperties)
+ {
+ bool propertyDefinied = IsPropertyDefinied(schema, propertyName);
- if (!propertyDefinied && !schema.AllowAdditionalProperties)
- RaiseError("Property '{0}' has not been defined and the schema does not allow additional properties.".FormatWith(CultureInfo.InvariantCulture, propertyName), schema);
+ if (!propertyDefinied)
+ RaiseError("Property '{0}' has not been defined and the schema does not allow additional properties.".FormatWith(CultureInfo.InvariantCulture, propertyName), schema);
+ }
_currentScope.CurrentPropertyName = propertyName;
}
+ private bool IsPropertyDefinied(JsonSchemaModel schema, string propertyName)
+ {
+ if (schema.Properties != null && schema.Properties.ContainsKey(propertyName))
+ return true;
+
+ if (schema.PatternProperties != null)
+ {
+ foreach (string pattern in schema.PatternProperties.Keys)
+ {
+ if (Regex.IsMatch(propertyName, pattern))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private bool ValidateArray(JsonSchemaModel schema)
{
if (schema == null)
diff --git a/Src/Newtonsoft.Json/Schema/JsonSchema.cs b/Src/Newtonsoft.Json/Schema/JsonSchema.cs
index c5c752f..5eeb88b 100644
--- a/Src/Newtonsoft.Json/Schema/JsonSchema.cs
+++ b/Src/Newtonsoft.Json/Schema/JsonSchema.cs
@@ -89,9 +89,9 @@ namespace Newtonsoft.Json.Schema
/// <value>The maximum length.</value>
public int? MaximumLength { get; set; }
/// <summary>
- /// Gets or sets the maximum decimals.
+ /// Gets or sets a number that the value should be divisble by.
/// </summary>
- /// <value>The maximum decimals.</value>
+ /// <value>A number that the value should be divisble by.</value>
public double? DivisibleBy { get; set; }
/// <summary>
/// Gets or sets the minimum.
@@ -104,6 +104,16 @@ namespace Newtonsoft.Json.Schema
/// <value>The maximum.</value>
public double? Maximum { get; set; }
/// <summary>
+ /// Gets or sets a flag indicating whether the value can not equal the number defined by the "minimum" attribute.
+ /// </summary>
+ /// <value>A flag indicating whether the value can not equal the number defined by the "minimum" attribute.</value>
+ public bool? ExclusiveMinimum { get; set; }
+ /// <summary>
+ /// Gets or sets a flag indicating whether the value can not equal the number defined by the "maximum" attribute.
+ /// </summary>
+ /// <value>A flag indicating whether the value can not equal the number defined by the "maximum" attribute.</value>
+ public bool? ExclusiveMaximum { get; set; }
+ /// <summary>
/// Gets or sets the minimum number of items.
/// </summary>
/// <value>The minimum number of items.</value>
@@ -129,6 +139,11 @@ namespace Newtonsoft.Json.Schema
/// <value>The <see cref="JsonSchema"/> of additional properties.</value>
public JsonSchema AdditionalProperties { get; set; }
/// <summary>
+ /// Gets or sets the pattern properties.
+ /// </summary>
+ /// <value>The pattern properties.</value>
+ public IDictionary<string, JsonSchema> PatternProperties { get; set; }
+ /// <summary>
/// Gets or sets a value indicating whether additional properties are allowed.
/// </summary>
/// <value>
diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaBuilder.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaBuilder.cs
index e5e5ad4..830adbe 100644
--- a/Src/Newtonsoft.Json/Schema/JsonSchemaBuilder.cs
+++ b/Src/Newtonsoft.Json/Schema/JsonSchemaBuilder.cs
@@ -146,6 +146,9 @@ namespace Newtonsoft.Json.Schema
case JsonSchemaConstants.AdditionalPropertiesPropertyName:
ProcessAdditionalProperties();
break;
+ case JsonSchemaConstants.PatternPropertiesPropertyName:
+ ProcessPatternProperties();
+ break;
case JsonSchemaConstants.RequiredPropertyName:
CurrentSchema.Required = (bool)_reader.Value;
break;
@@ -161,6 +164,12 @@ namespace Newtonsoft.Json.Schema
case JsonSchemaConstants.MaximumPropertyName:
CurrentSchema.Maximum = Convert.ToDouble(_reader.Value, CultureInfo.InvariantCulture);
break;
+ case JsonSchemaConstants.ExclusiveMinimumPropertyName:
+ CurrentSchema.ExclusiveMinimum = (bool)_reader.Value;
+ break;
+ case JsonSchemaConstants.ExclusiveMaximumPropertyName:
+ CurrentSchema.ExclusiveMaximum = (bool)_reader.Value;
+ break;
case JsonSchemaConstants.MaximumLengthPropertyName:
CurrentSchema.MaximumLength = Convert.ToInt32(_reader.Value, CultureInfo.InvariantCulture);
break;
@@ -311,6 +320,27 @@ namespace Newtonsoft.Json.Schema
CurrentSchema.AdditionalProperties = BuildSchema();
}
+ private void ProcessPatternProperties()
+ {
+ Dictionary<string, JsonSchema> patternProperties = new Dictionary<string, JsonSchema>();
+
+ if (_reader.TokenType != JsonToken.StartObject)
+ throw new Exception("Expected start object token.");
+
+ while (_reader.Read() && _reader.TokenType != JsonToken.EndObject)
+ {
+ string propertyName = Convert.ToString(_reader.Value, CultureInfo.InvariantCulture);
+ _reader.Read();
+
+ if (patternProperties.ContainsKey(propertyName))
+ throw new Exception("Property {0} has already been defined in schema.".FormatWith(CultureInfo.InvariantCulture, propertyName));
+
+ patternProperties.Add(propertyName, BuildSchema());
+ }
+
+ CurrentSchema.PatternProperties = patternProperties;
+ }
+
private void ProcessItems()
{
CurrentSchema.Items = new List<JsonSchema>();
diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaConstants.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaConstants.cs
index 906b45f..0e9eda1 100644
--- a/Src/Newtonsoft.Json/Schema/JsonSchemaConstants.cs
+++ b/Src/Newtonsoft.Json/Schema/JsonSchemaConstants.cs
@@ -36,11 +36,14 @@ namespace Newtonsoft.Json.Schema
public const string PropertiesPropertyName = "properties";
public const string ItemsPropertyName = "items";
public const string RequiredPropertyName = "required";
+ public const string PatternPropertiesPropertyName = "patternProperties";
public const string AdditionalPropertiesPropertyName = "additionalProperties";
public const string RequiresPropertyName = "requires";
public const string IdentityPropertyName = "identity";
public const string MinimumPropertyName = "minimum";
public const string MaximumPropertyName = "maximum";
+ public const string ExclusiveMinimumPropertyName = "exclusiveMinimum";
+ public const string ExclusiveMaximumPropertyName = "exclusiveMaximum";
public const string MinimumItemsPropertyName = "minItems";
public const string MaximumItemsPropertyName = "maxItems";
public const string PatternPropertyName = "pattern";
diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaModel.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaModel.cs
index c817669..0d438b4 100644
--- a/Src/Newtonsoft.Json/Schema/JsonSchemaModel.cs
+++ b/Src/Newtonsoft.Json/Schema/JsonSchemaModel.cs
@@ -40,11 +40,14 @@ namespace Newtonsoft.Json.Schema
public double? DivisibleBy { get; set; }
public double? Minimum { get; set; }
public double? Maximum { get; set; }
+ public bool ExclusiveMinimum { get; set; }
+ public bool ExclusiveMaximum { get; set; }
public int? MinimumItems { get; set; }
public int? MaximumItems { get; set; }
public IList<string> Patterns { get; set; }
public IList<JsonSchemaModel> Items { get; set; }
public IDictionary<string, JsonSchemaModel> Properties { get; set; }
+ public IDictionary<string, JsonSchemaModel> PatternProperties { get; set; }
public JsonSchemaModel AdditionalProperties { get; set; }
public bool AllowAdditionalProperties { get; set; }
public IList<JToken> Enum { get; set; }
@@ -83,6 +86,9 @@ namespace Newtonsoft.Json.Schema
model.Minimum = MathUtils.Max(model.Minimum, schema.Minimum);
model.Maximum = MathUtils.Max(model.Maximum, schema.Maximum);
+ model.ExclusiveMinimum = model.ExclusiveMinimum || (schema.ExclusiveMinimum ?? false);
+ model.ExclusiveMaximum = model.ExclusiveMaximum || (schema.ExclusiveMaximum ?? false);
+
model.MinimumItems = MathUtils.Max(model.MinimumItems, schema.MinimumItems);
model.MaximumItems = MathUtils.Min(model.MaximumItems, schema.MaximumItems);
model.AllowAdditionalProperties = model.AllowAdditionalProperties && schema.AllowAdditionalProperties;
diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs
index 5c7d3b2..ba3c750 100644
--- a/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs
+++ b/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs
@@ -71,13 +71,9 @@ namespace Newtonsoft.Json.Schema
_nodes.Add(currentNode);
- if (schema.Properties != null)
- {
- foreach (KeyValuePair<string, JsonSchema> property in schema.Properties)
- {
- AddProperty(currentNode, property.Key, property.Value);
- }
- }
+ AddProperties(schema.Properties, currentNode.Properties);
+
+ AddProperties(schema.PatternProperties, currentNode.PatternProperties);
if (schema.Items != null)
{
@@ -96,12 +92,23 @@ namespace Newtonsoft.Json.Schema
return currentNode;
}
- public void AddProperty(JsonSchemaNode parentNode, string propertyName, JsonSchema schema)
+ public void AddProperties(IDictionary<string, JsonSchema> source, IDictionary<string, JsonSchemaNode> target)
+ {
+ if (source != null)
+ {
+ foreach (KeyValuePair<string, JsonSchema> property in source)
+ {
+ AddProperty(target, property.Key, property.Value);
+ }
+ }
+ }
+
+ public void AddProperty(IDictionary<string, JsonSchemaNode> target, string propertyName, JsonSchema schema)
{
JsonSchemaNode propertyNode;
- parentNode.Properties.TryGetValue(propertyName, out propertyNode);
+ target.TryGetValue(propertyName, out propertyNode);
- parentNode.Properties[propertyName] = AddSchema(propertyNode, schema);
+ target[propertyName] = AddSchema(propertyNode, schema);
}
public void AddItem(JsonSchemaNode parentNode, int index, JsonSchema schema)
@@ -143,6 +150,13 @@ namespace Newtonsoft.Json.Schema
model.Properties[property.Key] = BuildNodeModel(property.Value);
}
+ foreach (KeyValuePair<string, JsonSchemaNode> property in node.PatternProperties)
+ {
+ if (model.PatternProperties == null)
+ model.PatternProperties = new Dictionary<string, JsonSchemaModel>();
+
+ model.PatternProperties[property.Key] = BuildNodeModel(property.Value);
+ }
for (int i = 0; i < node.Items.Count; i++)
{
if (model.Items == null)
diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaNode.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaNode.cs
index 33f4558..5f1a23c 100644
--- a/Src/Newtonsoft.Json/Schema/JsonSchemaNode.cs
+++ b/Src/Newtonsoft.Json/Schema/JsonSchemaNode.cs
@@ -35,6 +35,7 @@ namespace Newtonsoft.Json.Schema
public string Id { get; private set; }
public ReadOnlyCollection<JsonSchema> Schemas { get; private set; }
public Dictionary<string, JsonSchemaNode> Properties { get; private set; }
+ public Dictionary<string, JsonSchemaNode> PatternProperties { get; private set; }
public List<JsonSchemaNode> Items { get; private set; }
public JsonSchemaNode AdditionalProperties { get; set; }
@@ -42,6 +43,7 @@ namespace Newtonsoft.Json.Schema
{
Schemas = new ReadOnlyCollection<JsonSchema>(new []{ schema });
Properties = new Dictionary<string, JsonSchemaNode>();
+ PatternProperties = new Dictionary<string, JsonSchemaNode>();
Items = new List<JsonSchemaNode>();
Id = GetId(Schemas);
@@ -51,6 +53,7 @@ namespace Newtonsoft.Json.Schema
{
Schemas = new ReadOnlyCollection<JsonSchema>(source.Schemas.Union(new[] { schema }).ToList());
Properties = new Dictionary<string, JsonSchemaNode>(source.Properties);
+ PatternProperties = new Dictionary<string, JsonSchemaNode>(source.PatternProperties);
Items = new List<JsonSchemaNode>(source.Items);
AdditionalProperties = source.AdditionalProperties;
diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs
index c561e5f..eeaa0db 100644
--- a/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs
+++ b/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs
@@ -89,20 +89,13 @@ namespace Newtonsoft.Json.Schema
ReferenceOrWriteSchema(schema.AdditionalProperties);
}
}
- if (schema.Properties != null)
- {
- _writer.WritePropertyName(JsonSchemaConstants.PropertiesPropertyName);
- _writer.WriteStartObject();
- foreach (KeyValuePair<string, JsonSchema> property in schema.Properties)
- {
- _writer.WritePropertyName(property.Key);
- ReferenceOrWriteSchema(property.Value);
- }
- _writer.WriteEndObject();
- }
+ WriteSchemaDictionaryIfNotNull(_writer, JsonSchemaConstants.PropertiesPropertyName, schema.Properties);
+ WriteSchemaDictionaryIfNotNull(_writer, JsonSchemaConstants.PatternPropertiesPropertyName, schema.PatternProperties);
WriteItems(schema);
WritePropertyIfNotNull(_writer, JsonSchemaConstants.MinimumPropertyName, schema.Minimum);
WritePropertyIfNotNull(_writer, JsonSchemaConstants.MaximumPropertyName, schema.Maximum);
+ WritePropertyIfNotNull(_writer, JsonSchemaConstants.ExclusiveMinimumPropertyName, schema.ExclusiveMinimum);
+ WritePropertyIfNotNull(_writer, JsonSchemaConstants.ExclusiveMaximumPropertyName, schema.ExclusiveMaximum);
WritePropertyIfNotNull(_writer, JsonSchemaConstants.MinimumLengthPropertyName, schema.MinimumLength);
WritePropertyIfNotNull(_writer, JsonSchemaConstants.MaximumLengthPropertyName, schema.MaximumLength);
WritePropertyIfNotNull(_writer, JsonSchemaConstants.MinimumItemsPropertyName, schema.MinimumItems);
@@ -153,6 +146,21 @@ namespace Newtonsoft.Json.Schema
_writer.WriteEndObject();
}
+ private void WriteSchemaDictionaryIfNotNull(JsonWriter writer, string propertyName, IDictionary<string, JsonSchema> properties)
+ {
+ if (properties != null)
+ {
+ writer.WritePropertyName(propertyName);
+ writer.WriteStartObject();
+ foreach (KeyValuePair<string, JsonSchema> property in properties)
+ {
+ writer.WritePropertyName(property.Key);
+ ReferenceOrWriteSchema(property.Value);
+ }
+ writer.WriteEndObject();
+ }
+ }
+
private void WriteItems(JsonSchema schema)
{
if (CollectionUtils.IsNullOrEmpty(schema.Items))