예제 #1
0
        private void validate(ValidationState state, Schema schema, IJson instance, string parentTag = null)
        {
            if (schema.Nullable == true && instance.IsNull())
            {
                return;
            }

            switch (schema.Form())
            {
            case Form.Ref:
                state.SchemaTokens.Add(new List <string>()
                {
                    "definitions", schema.Ref
                });

                if (state.SchemaTokens.Count == MaxDepth)
                {
                    throw new MaxDepthExceededException();
                }

                validate(state, state.Root.Definitions[schema.Ref], instance);
                state.SchemaTokens.RemoveAt(state.SchemaTokens.Count - 1);

                break;

            case Form.Type:
                state.PushSchemaToken("type");

                switch (schema.Type)
                {
                case Type.Boolean:
                    if (!instance.IsBoolean())
                    {
                        state.PushError();
                    }

                    break;

                case Type.Float32:
                case Type.Float64:
                    if (!instance.IsNumber())
                    {
                        state.PushError();
                    }

                    break;

                case Type.Int8:
                    validateInt(state, instance, -128, 127);
                    break;

                case Type.Uint8:
                    validateInt(state, instance, 0, 255);
                    break;

                case Type.Int16:
                    validateInt(state, instance, -32768, 32767);
                    break;

                case Type.Uint16:
                    validateInt(state, instance, 0, 65535);
                    break;

                case Type.Int32:
                    validateInt(state, instance, -2147483648, 2147483647);
                    break;

                case Type.Uint32:
                    validateInt(state, instance, 0, 4294967295L);
                    break;

                case Type.String:
                    if (!instance.IsString())
                    {
                        state.PushError();
                    }

                    break;

                case Type.Timestamp:
                    if (instance.IsString())
                    {
                        try {
                            DateTime.ParseExact(
                                instance.AsString(),
                                "yyyy-MM-dd'T'HH:mm:ss.FFFFFFFK",
                                CultureInfo.InvariantCulture
                                );
                        }
                        catch (FormatException)
                        {
                            state.PushError();
                        }
                    }
                    else
                    {
                        state.PushError();
                    }

                    break;
                }

                state.PopSchemaToken();
                break;

            case Form.Enum:
                state.PushSchemaToken("enum");

                if (!instance.IsString() || !schema.Enum.Contains(instance.AsString()))
                {
                    state.PushError();
                }

                state.PopSchemaToken();
                break;

            case Form.Elements:
                state.PushSchemaToken("elements");

                if (instance.IsArray())
                {
                    IList <IJson> list = instance.AsArray();
                    for (int i = 0; i < list.Count; i++)
                    {
                        state.PushInstanceToken(i.ToString());
                        validate(state, schema.Elements, list[i]);
                        state.PopInstanceToken();
                    }
                }
                else
                {
                    state.PushError();
                }

                state.PopSchemaToken();
                break;

            case Form.Properties:
                if (!instance.IsObject())
                {
                    if (schema.Properties != null)
                    {
                        state.PushSchemaToken("properties");
                    }
                    else
                    {
                        state.PushSchemaToken("optionalProperties");
                    }

                    state.PushError();
                    state.PopSchemaToken();
                    return;
                }

                IDictionary <string, IJson> obj = instance.AsObject();

                if (schema.Properties != null)
                {
                    state.PushSchemaToken("properties");

                    foreach (var entry in schema.Properties)
                    {
                        state.PushSchemaToken(entry.Key);

                        if (obj.ContainsKey(entry.Key))
                        {
                            state.PushInstanceToken(entry.Key);
                            validate(state, entry.Value, obj[entry.Key]);
                            state.PopInstanceToken();
                        }
                        else
                        {
                            state.PushError();
                        }

                        state.PopSchemaToken();
                    }

                    state.PopSchemaToken();
                }

                if (schema.OptionalProperties != null)
                {
                    state.PushSchemaToken("optionalProperties");

                    foreach (var entry in schema.OptionalProperties)
                    {
                        state.PushSchemaToken(entry.Key);

                        if (obj.ContainsKey(entry.Key))
                        {
                            state.PushInstanceToken(entry.Key);
                            validate(state, entry.Value, obj[entry.Key]);
                            state.PopInstanceToken();
                        }

                        state.PopSchemaToken();
                    }

                    state.PopSchemaToken();
                }

                if (schema.AdditionalProperties != true)
                {
                    foreach (string key in obj.Keys)
                    {
                        if (schema.Properties != null && schema.Properties.ContainsKey(key))
                        {
                            continue;
                        }

                        if (schema.OptionalProperties != null && schema.OptionalProperties.ContainsKey(key))
                        {
                            continue;
                        }

                        if (key == parentTag)
                        {
                            continue;
                        }

                        state.PushInstanceToken(key);
                        state.PushError();
                        state.PopInstanceToken();
                    }
                }

                break;

            case Form.Values:
                state.PushSchemaToken("values");

                if (instance.IsObject())
                {
                    foreach (var entry in instance.AsObject())
                    {
                        state.PushInstanceToken(entry.Key);
                        validate(state, schema.Values, entry.Value);
                        state.PopInstanceToken();
                    }
                }
                else
                {
                    state.PushError();
                }

                state.PopSchemaToken();
                break;

            case Form.Discriminator:
                if (!instance.IsObject())
                {
                    state.PushSchemaToken("discriminator");
                    state.PushError();
                    state.PopSchemaToken();
                    break;
                }

                obj = instance.AsObject();

                if (!obj.ContainsKey(schema.Discriminator))
                {
                    state.PushSchemaToken("discriminator");
                    state.PushError();
                    state.PopSchemaToken();
                    break;
                }

                if (!obj[schema.Discriminator].IsString())
                {
                    state.PushSchemaToken("discriminator");
                    state.PushInstanceToken(schema.Discriminator);
                    state.PushError();
                    state.PopInstanceToken();
                    state.PopSchemaToken();
                    break;
                }

                if (!schema.Mapping.ContainsKey(obj[schema.Discriminator].AsString()))
                {
                    state.PushSchemaToken("mapping");
                    state.PushInstanceToken(schema.Discriminator);
                    state.PushError();
                    state.PopInstanceToken();
                    state.PopSchemaToken();
                    break;
                }

                state.PushSchemaToken("mapping");
                state.PushSchemaToken(obj[schema.Discriminator].AsString());
                validate(
                    state,
                    schema.Mapping[obj[schema.Discriminator].AsString()],
                    instance,
                    schema.Discriminator
                    );
                state.PopSchemaToken();
                state.PopSchemaToken();

                break;
            }
        }