Example #1
0
    public static JsonSchemaModel Create(IList<JsonSchema> schemata)
    {
      JsonSchemaModel model = new JsonSchemaModel();

      foreach (JsonSchema schema in schemata)
      {
        Combine(model, schema);
      }

      return model;
    }
Example #2
0
    private static void Combine(JsonSchemaModel model, JsonSchema schema)
    {
      // Version 3 of the Draft JSON Schema has the default value of Not Required
      model.Required = model.Required || (schema.Required ?? false);
      model.Type = model.Type & (schema.Type ?? JsonSchemaType.Any);

      model.MinimumLength = MathUtils.Max(model.MinimumLength, schema.MinimumLength);
      model.MaximumLength = MathUtils.Min(model.MaximumLength, schema.MaximumLength);

      // not sure what is the best way to combine divisibleBy
      model.DivisibleBy = MathUtils.Max(model.DivisibleBy, schema.DivisibleBy);

      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.PositionalItemsValidation = model.PositionalItemsValidation || schema.PositionalItemsValidation;
      model.AllowAdditionalProperties = model.AllowAdditionalProperties && schema.AllowAdditionalProperties;
      model.AllowAdditionalItems = model.AllowAdditionalItems && schema.AllowAdditionalItems;
      model.UniqueItems = model.UniqueItems || schema.UniqueItems;
      if (schema.Enum != null)
      {
        if (model.Enum == null)
          model.Enum = new List<JToken>();

        model.Enum.AddRangeDistinct(schema.Enum, JToken.EqualityComparer);
      }
      model.Disallow = model.Disallow | (schema.Disallow ?? JsonSchemaType.None);

      if (schema.Pattern != null)
      {
        if (model.Patterns == null)
          model.Patterns = new List<string>();

        model.Patterns.AddDistinct(schema.Pattern);
      }
    }
Example #3
0
    private bool ValidateObject(JsonSchemaModel schema)
    {
      if (schema == null)
        return true;

      return (TestType(schema, JsonSchemaType.Object));
    }
Example #4
0
    private bool ValidateArray(JsonSchemaModel schema)
    {
      if (schema == null)
        return true;

      return (TestType(schema, JsonSchemaType.Array));
    }
Example #5
0
    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;
    }
Example #6
0
    private void ValidatePropertyName(JsonSchemaModel schema)
    {
      if (schema == null)
        return;

      string propertyName = Convert.ToString(_reader.Value, CultureInfo.InvariantCulture);

      if (_currentScope.RequiredProperties.ContainsKey(propertyName))
        _currentScope.RequiredProperties[propertyName] = true;

      if (!schema.AllowAdditionalProperties)
      {
        bool propertyDefinied = IsPropertyDefinied(schema, propertyName);

        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;
    }
Example #7
0
    private void ValidateFloat(JsonSchemaModel schema)
    {
      if (schema == null)
        return;

      if (!TestType(schema, JsonSchemaType.Float))
        return;

      ValidateNotDisallowed(schema);
      
      double value = Convert.ToDouble(_reader.Value, CultureInfo.InvariantCulture);

      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)
      {
        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)
      {
        double remainder = FloatingPointRemainder(value, schema.DivisibleBy.Value);

        if (!IsZero(remainder))
          RaiseError("Float {0} is not evenly divisible by {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.DivisibleBy), schema);
      }
    }
Example #8
0
    private void ValidateInteger(JsonSchemaModel schema)
    {
      if (schema == null)
        return;

      if (!TestType(schema, JsonSchemaType.Integer))
        return;

      ValidateNotDisallowed(schema);
      
      object value = _reader.Value;

      if (schema.Maximum != null)
      {
        if (JValue.Compare(JTokenType.Integer, value, schema.Maximum) > 0)
          RaiseError("Integer {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Maximum), schema);
        if (schema.ExclusiveMaximum && JValue.Compare(JTokenType.Integer, value, schema.Maximum) == 0)
          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 (JValue.Compare(JTokenType.Integer, value, schema.Minimum) < 0)
          RaiseError("Integer {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Minimum), schema);
        if (schema.ExclusiveMinimum && JValue.Compare(JTokenType.Integer, value, schema.Minimum) == 0)
          RaiseError("Integer {0} equals minimum value of {1} and exclusive minimum is true.".FormatWith(CultureInfo.InvariantCulture, value, schema.Minimum), schema);
      }

      if (schema.DivisibleBy != null)
      {
        bool notDivisible;
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE40 || PORTABLE)
        if (value is BigInteger)
        {
          // not that this will lose any decimal point on DivisibleBy
          // so manually raise an error if DivisibleBy is not an integer and value is not zero
          BigInteger i = (BigInteger)value;
          bool divisibleNonInteger = !Math.Abs(schema.DivisibleBy.Value - Math.Truncate(schema.DivisibleBy.Value)).Equals(0);
          if (divisibleNonInteger)
            notDivisible = i != 0;
          else
            notDivisible = i % new BigInteger(schema.DivisibleBy.Value) != 0;
        }
        else
#endif
        notDivisible = !IsZero(Convert.ToInt64(value, CultureInfo.InvariantCulture) % schema.DivisibleBy.Value);

        if (notDivisible)
          RaiseError("Integer {0} is not evenly divisible by {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.DivisibleBy), schema);
      }
    }
Example #9
0
    private void ValidateBoolean(JsonSchemaModel schema)
    {
      if (schema == null)
        return;

      if (!TestType(schema, JsonSchemaType.Boolean))
        return;

      ValidateNotDisallowed(schema);
    }
Example #10
0
    private void ValidateEndArray(JsonSchemaModel schema)
    {
      if (schema == null)
        return;

      int arrayItemCount = _currentScope.ArrayItemCount;

      if (schema.MaximumItems != null && arrayItemCount > schema.MaximumItems)
        RaiseError("Array item count {0} exceeds maximum count of {1}.".FormatWith(CultureInfo.InvariantCulture, arrayItemCount, schema.MaximumItems), schema);

      if (schema.MinimumItems != null && arrayItemCount < schema.MinimumItems)
        RaiseError("Array item count {0} is less than minimum count of {1}.".FormatWith(CultureInfo.InvariantCulture, arrayItemCount, schema.MinimumItems), schema);
    }
Example #11
0
    private void ValidateEndObject(JsonSchemaModel schema)
    {
      if (schema == null)
        return;

      Dictionary<string, bool> requiredProperties = _currentScope.RequiredProperties;

      if (requiredProperties != null)
      {
        List<string> unmatchedRequiredProperties =
          requiredProperties.Where(kv => !kv.Value).Select(kv => kv.Key).ToList();

        if (unmatchedRequiredProperties.Count > 0)
          RaiseError("Required properties are missing from object: {0}.".FormatWith(CultureInfo.InvariantCulture, string.Join(", ", unmatchedRequiredProperties.ToArray())), schema);
      }
    }
Example #12
0
    private void ValidateCurrentToken()
    {
      // first time validate has been called. build model
      if (_model == null)
      {
        JsonSchemaModelBuilder builder = new JsonSchemaModelBuilder();
        _model = builder.Build(_schema);

        if (!JsonWriter.IsStartToken(_reader.TokenType))
          Push(new SchemaScope(JTokenType.None, CurrentMemberSchemas));
      }

      switch (_reader.TokenType)
      {
        case JsonToken.StartObject:
          ProcessValue();
          IList<JsonSchemaModel> objectSchemas = CurrentMemberSchemas.Where(ValidateObject).ToList();
          Push(new SchemaScope(JTokenType.Object, objectSchemas));
          WriteToken(CurrentSchemas);
          break;
        case JsonToken.StartArray:
          ProcessValue();
          IList<JsonSchemaModel> arraySchemas = CurrentMemberSchemas.Where(ValidateArray).ToList();
          Push(new SchemaScope(JTokenType.Array, arraySchemas));
          WriteToken(CurrentSchemas);
          break;
        case JsonToken.StartConstructor:
          ProcessValue();
          Push(new SchemaScope(JTokenType.Constructor, null));
          WriteToken(CurrentSchemas);
          break;
        case JsonToken.PropertyName:
          WriteToken(CurrentSchemas);
          foreach (JsonSchemaModel schema in CurrentSchemas)
          {
            ValidatePropertyName(schema);
          }
          break;
        case JsonToken.Raw:
          ProcessValue();
          break;
        case JsonToken.Integer:
          ProcessValue();
          WriteToken(CurrentMemberSchemas);
          foreach (JsonSchemaModel schema in CurrentMemberSchemas)
          {
            ValidateInteger(schema);
          }
          break;
        case JsonToken.Float:
          ProcessValue();
          WriteToken(CurrentMemberSchemas);
          foreach (JsonSchemaModel schema in CurrentMemberSchemas)
          {
            ValidateFloat(schema);
          }
          break;
        case JsonToken.String:
          ProcessValue();
          WriteToken(CurrentMemberSchemas);
          foreach (JsonSchemaModel schema in CurrentMemberSchemas)
          {
            ValidateString(schema);
          }
          break;
        case JsonToken.Boolean:
          ProcessValue();
          WriteToken(CurrentMemberSchemas);
          foreach (JsonSchemaModel schema in CurrentMemberSchemas)
          {
            ValidateBoolean(schema);
          }
          break;
        case JsonToken.Null:
          ProcessValue();
          WriteToken(CurrentMemberSchemas);
          foreach (JsonSchemaModel schema in CurrentMemberSchemas)
          {
            ValidateNull(schema);
          }
          break;
        case JsonToken.EndObject:
          WriteToken(CurrentSchemas);
          foreach (JsonSchemaModel schema in CurrentSchemas)
          {
            ValidateEndObject(schema);
          }
          Pop();
          break;
        case JsonToken.EndArray:
          WriteToken(CurrentSchemas);
          foreach (JsonSchemaModel schema in CurrentSchemas)
          {
            ValidateEndArray(schema);
          }
          Pop();
          break;
        case JsonToken.EndConstructor:
          WriteToken(CurrentSchemas);
          Pop();
          break;
        case JsonToken.Undefined:
        case JsonToken.Date:
        case JsonToken.Bytes:
          // these have no equivalent in JSON schema
          WriteToken(CurrentMemberSchemas);
          break;
        case JsonToken.None:
          // no content, do nothing
          break;
        default:
          throw new ArgumentOutOfRangeException();
      }
    }
Example #13
0
    private void ValidateNotDisallowed(JsonSchemaModel schema)
    {
      if (schema == null)
        return;

      JsonSchemaType? currentNodeType = GetCurrentNodeSchemaType();
      if (currentNodeType != null)
      {
        if (JsonSchemaGenerator.HasFlag(schema.Disallow, currentNodeType.Value))
          RaiseError("Type {0} is disallowed.".FormatWith(CultureInfo.InvariantCulture, currentNodeType), schema);
      }
    }
Example #14
0
    private void RaiseError(string message, JsonSchemaModel schema)
    {
      IJsonLineInfo lineInfo = this;

      string exceptionMessage = (lineInfo.HasLineInfo())
                                  ? message + " Line {0}, position {1}.".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition)
                                  : message;

      OnValidationEvent(new JsonSchemaException(exceptionMessage, null, Path, lineInfo.LineNumber, lineInfo.LinePosition));
    }
Example #15
0
    private bool TestType(JsonSchemaModel currentSchema, JsonSchemaType currentType)
    {
      if (!JsonSchemaGenerator.HasFlag(currentSchema.Type, currentType))
      {
        RaiseError("Invalid type. Expected {0} but got {1}.".FormatWith(CultureInfo.InvariantCulture, currentSchema.Type, currentType), currentSchema);
        return false;
      }

      return true;
    }
Example #16
0
      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);
      }
Example #17
0
    private void ValidateString(JsonSchemaModel schema)
    {
      if (schema == null)
        return;

      if (!TestType(schema, JsonSchemaType.String))
        return;

      ValidateNotDisallowed(schema);

      string value = _reader.Value.ToString();

      if (schema.MaximumLength != null && value.Length > schema.MaximumLength)
        RaiseError("String '{0}' exceeds maximum length of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.MaximumLength), schema);

      if (schema.MinimumLength != null && value.Length < schema.MinimumLength)
        RaiseError("String '{0}' is less than minimum length of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.MinimumLength), schema);

      if (schema.Patterns != null)
      {
        foreach (string pattern in schema.Patterns)
        {
          if (!Regex.IsMatch(value, pattern))
            RaiseError("String '{0}' does not match regex pattern '{1}'.".FormatWith(CultureInfo.InvariantCulture, value, pattern), schema);
        }
      }
    }