Пример #1
0
        public static bool FindSchema(Action <JSchema> setSchema, JSchema schema, Uri rootSchemaId, Uri reference, JSchemaReader schemaReader, ref JSchemaDiscovery discovery)
        {
            // todo, better way to get parts from Uri
            string[] parts = reference.ToString().Split('/');

            bool resolvedSchema;

            if (parts.Length > 0 && (parts[0] == "#" || parts[0] == rootSchemaId + "#"))
            {
                schemaReader._schemaStack.Push(schema);

                parts = parts.Skip(1).ToArray();

                object current = schema;
                foreach (string part in parts)
                {
                    string unescapedPart = UnescapeReference(part);

                    if (current is JSchema)
                    {
                        JSchema s = current as JSchema;

                        schemaReader._schemaStack.Push(s);

                        switch (unescapedPart)
                        {
                        case Constants.PropertyNames.Properties:
                            current = s._properties;
                            break;

                        case Constants.PropertyNames.Items:
                            current = s._items;
                            break;

                        case Constants.PropertyNames.AdditionalProperties:
                            current = s.AdditionalProperties;
                            break;

                        case Constants.PropertyNames.AdditionalItems:
                            current = s.AdditionalItems;
                            break;

                        case Constants.PropertyNames.Not:
                            current = s.Not;
                            break;

                        case Constants.PropertyNames.OneOf:
                            current = s._oneOf;
                            break;

                        case Constants.PropertyNames.AllOf:
                            current = s._allOf;
                            break;

                        case Constants.PropertyNames.AnyOf:
                            current = s._anyOf;
                            break;

                        case Constants.PropertyNames.Enum:
                            current = s._enum;
                            break;

                        case Constants.PropertyNames.PatternProperties:
                            current = s._patternProperties;
                            break;

                        case Constants.PropertyNames.Dependencies:
                            current = s._dependencies;
                            break;

                        default:
                            JToken t;
                            s.ExtensionData.TryGetValue(unescapedPart, out t);
                            current = t;
                            break;
                        }
                    }
                    else if (current is JToken)
                    {
                        JToken resolvedToken;

                        JToken t = (JToken)current;
                        if (t is JObject)
                        {
                            resolvedToken = t[unescapedPart];
                        }
                        else if (t is JArray || t is JConstructor)
                        {
                            int index;
                            if (int.TryParse(unescapedPart, NumberStyles.None, CultureInfo.InvariantCulture, out index))
                            {
                                if (index > t.Count() || index < 0)
                                {
                                    resolvedToken = null;
                                }
                                else
                                {
                                    resolvedToken = t[index];
                                }
                            }
                            else
                            {
                                resolvedToken = null;
                            }
                        }
                        else
                        {
                            resolvedToken = null;
                        }

                        if (resolvedToken != null)
                        {
                            JSchemaAnnotation annotation = resolvedToken.Annotation <JSchemaAnnotation>();
                            if (annotation != null)
                            {
                                current = annotation.Schema;
                            }
                            else
                            {
                                current = resolvedToken;
                            }
                        }
                        else
                        {
                            current = null;
                        }
                    }
                    else if (current is IDictionary)
                    {
                        IDictionary d = (IDictionary)current;

                        current = d[unescapedPart];
                    }
                    else if (current is IList)
                    {
                        IList l = (IList)current;

                        int index;
                        if (int.TryParse(unescapedPart, NumberStyles.None, CultureInfo.InvariantCulture, out index))
                        {
                            if (index > l.Count || index < 0)
                            {
                                current = null;
                            }
                            else
                            {
                                current = l[index];
                            }
                        }
                        else
                        {
                            current = null;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                if (current is JToken)
                {
                    JToken t = (JToken)current;

                    JSchemaAnnotation annotation = t.Annotation <JSchemaAnnotation>();
                    if (annotation != null)
                    {
                        setSchema(annotation.Schema);
                        resolvedSchema = true;
                    }
                    else
                    {
                        JSchema inlineSchema = schemaReader.ReadInlineSchema(setSchema, t);

                        string path = reference.OriginalString;
                        if (path.StartsWith("#/", StringComparison.Ordinal))
                        {
                            path = path.Substring(2, path.Length - 2);
                        }

                        discovery.Discover(inlineSchema, rootSchemaId, path);

                        resolvedSchema = true;
                    }
                }
                else
                {
                    JSchema s = current as JSchema;
                    if (s != null)
                    {
                        setSchema(s);
                        resolvedSchema = true;

                        // schema is a reference schema and needs to be resolved
                        if (s.Reference != null)
                        {
                            schemaReader.AddDeferedSchema(setSchema, s);
                        }
                    }
                    else
                    {
                        resolvedSchema = false;
                    }
                }

                schemaReader._schemaStack.Clear();
            }
            else
            {
                discovery.Discover(schema, null);

                Uri resolvedReference = ResolveSchemaId(rootSchemaId, reference);

                // default Uri comparison ignores fragments
                // use firstordefault to handle duplicates
                KnownSchema knownSchema = discovery.KnownSchemas.FirstOrDefault(s => s.Id.OriginalString.TrimEnd('#') == resolvedReference.OriginalString.TrimEnd('#'));

                if (knownSchema != null)
                {
                    resolvedSchema = true;
                    setSchema(knownSchema.Schema);
                }
                else
                {
                    int hashIndex = resolvedReference.OriginalString.IndexOf('#');
                    if (hashIndex != -1)
                    {
                        Uri path     = new Uri(resolvedReference.OriginalString.Substring(0, hashIndex), UriKind.RelativeOrAbsolute);
                        Uri fragment = new Uri(resolvedReference.OriginalString.Substring(hashIndex), UriKind.RelativeOrAbsolute);

                        // default Uri comparison ignores fragments
                        // there could be duplicated ids. use FirstOrDefault to get first schema with an id
                        knownSchema = discovery.KnownSchemas.FirstOrDefault(s => s.Id.OriginalString.TrimEnd('#') == path.OriginalString);

                        if (knownSchema != null)
                        {
                            // don't attempt to find a schema in the same schema again
                            // avoids stackoverflow
                            if (knownSchema.Schema != schema ||
                                !UriComparer.Instance.Equals(rootSchemaId, path) ||
                                !UriComparer.Instance.Equals(reference, fragment))
                            {
                                resolvedSchema = FindSchema(setSchema, knownSchema.Schema, path, fragment, schemaReader, ref discovery);
                            }
                            else
                            {
                                resolvedSchema = false;
                            }
                        }
                        else
                        {
                            resolvedSchema = false;
                        }
                    }
                    else
                    {
                        resolvedSchema = false;
                    }
                }
            }
            return(resolvedSchema);
        }
Пример #2
0
        private void DiscoverInternal(JSchema schema, string latestPath, bool isDefinitionSchema = false)
        {
            if (schema.Reference != null)
            {
                return;
            }

            // give schemas that are dependencies a special state so they are written as a dependency and not inline
            KnownSchemaState resolvedSchemaState = (_state == KnownSchemaState.InlinePending && isDefinitionSchema)
                ? KnownSchemaState.DefinitionPending
                : _state;

            string scopePath     = latestPath;
            Uri    schemaKnownId = GetSchemaIdAndNewScopeId(schema, ref scopePath, out Uri newScopeId);

            if (_knownSchemas.Contains(schema))
            {
                KnownSchema alreadyDiscoveredSchema = _knownSchemas[schema];

                // schema was previously discovered but exists in definitions
                if (alreadyDiscoveredSchema.State == KnownSchemaState.InlinePending &&
                    resolvedSchemaState == KnownSchemaState.DefinitionPending &&
                    _rootSchema != schema)
                {
                    int existingKnownSchemaIndex = _knownSchemas.IndexOf(alreadyDiscoveredSchema);

                    _knownSchemas[existingKnownSchemaIndex] = new KnownSchema(schemaKnownId, schema, resolvedSchemaState);
                }

                return;
            }

            // check whether a schema with the resolved id is already known
            // this will be hit when a schema contains duplicate ids or references a schema with a duplicate id
            bool existingSchema = _knownSchemas.GetById(schemaKnownId) != null;

            // add schema to known schemas whether duplicate or not to avoid multiple errors
            // the first schema with a duplicate id will be used
            _knownSchemas.Add(new KnownSchema(schemaKnownId, schema, resolvedSchemaState));

            if (existingSchema)
            {
                if (ValidationErrors != null)
                {
                    ValidationError error = ValidationError.CreateValidationError($"Duplicate schema id '{schemaKnownId.OriginalString}' encountered.", ErrorType.Id, schema, null, schemaKnownId, null, schema, schema.Path);
                    ValidationErrors.Add(error);
                }
            }

            _pathStack.Add(new SchemaPath(newScopeId, scopePath));

            // discover should happen in the same order as writer except extension data (e.g. definitions)
            if (schema._extensionData != null)
            {
                foreach (KeyValuePair <string, JToken> valuePair in schema._extensionData)
                {
                    DiscoverTokenSchemas(schema, EscapePath(valuePair.Key), valuePair.Value);
                }
            }

            DiscoverSchema(Constants.PropertyNames.AdditionalProperties, schema.AdditionalProperties);
            DiscoverSchema(Constants.PropertyNames.AdditionalItems, schema.AdditionalItems);
            DiscoverDictionarySchemas(Constants.PropertyNames.Properties, schema._properties);
            DiscoverDictionarySchemas(Constants.PropertyNames.PatternProperties, schema._patternProperties);
            DiscoverDictionarySchemas(Constants.PropertyNames.Dependencies, schema._dependencies);
            if (schema.ItemsPositionValidation)
            {
                DiscoverArraySchemas(Constants.PropertyNames.Items, schema._items);
            }
            else if (schema._items != null && schema._items.Count > 0)
            {
                DiscoverSchema(Constants.PropertyNames.Items, schema._items[0]);
            }
            DiscoverArraySchemas(Constants.PropertyNames.AllOf, schema._allOf);
            DiscoverArraySchemas(Constants.PropertyNames.AnyOf, schema._anyOf);
            DiscoverArraySchemas(Constants.PropertyNames.OneOf, schema._oneOf);
            DiscoverSchema(Constants.PropertyNames.Not, schema.Not);
            DiscoverSchema(Constants.PropertyNames.PropertyNamesSchema, schema.PropertyNames);
            DiscoverSchema(Constants.PropertyNames.Contains, schema.Contains);
            DiscoverSchema(Constants.PropertyNames.If, schema.If);
            DiscoverSchema(Constants.PropertyNames.Then, schema.Then);
            DiscoverSchema(Constants.PropertyNames.Else, schema.Else);

            _pathStack.RemoveAt(_pathStack.Count - 1);
        }
        public static bool FindSchema(Action <JSchema> setSchema, JSchema schema, Uri rootSchemaId, Uri reference, JSchemaReader schemaReader)
        {
            // todo, better way to get parts from Uri
            string[] parts = reference.ToString().Split('/');

            bool resolvedSchema;

            if (parts.Length > 0 && (parts[0] == "#" || parts[0] == rootSchemaId + "#"))
            {
                schemaReader._schemaStack.Push(schema);

                parts = parts.Skip(1).ToArray();

                object current = schema;
                foreach (string part in parts)
                {
                    string unescapedPart = UnescapeReference(part);

                    if (current is JSchema)
                    {
                        JSchema s = current as JSchema;

                        schemaReader._schemaStack.Push(s);

                        switch (unescapedPart)
                        {
                        case Constants.PropertyNames.Properties:
                            current = s._properties;
                            break;

                        case Constants.PropertyNames.Items:
                            current = s._items;
                            break;

                        case Constants.PropertyNames.AdditionalProperties:
                            current = s.AdditionalProperties;
                            break;

                        case Constants.PropertyNames.AdditionalItems:
                            current = s.AdditionalItems;
                            break;

                        case Constants.PropertyNames.Not:
                            current = s.Not;
                            break;

                        case Constants.PropertyNames.OneOf:
                            current = s._oneOf;
                            break;

                        case Constants.PropertyNames.AllOf:
                            current = s._allOf;
                            break;

                        case Constants.PropertyNames.AnyOf:
                            current = s._anyOf;
                            break;

                        case Constants.PropertyNames.Enum:
                            current = s._enum;
                            break;

                        case Constants.PropertyNames.PatternProperties:
                            current = s._patternProperties;
                            break;

                        default:
                            JToken t;
                            s.ExtensionData.TryGetValue(unescapedPart, out t);
                            current = t;
                            break;
                        }
                    }
                    else if (current is JToken)
                    {
                        JToken resolvedToken;

                        JToken t = (JToken)current;
                        if (t is JObject)
                        {
                            resolvedToken = t[unescapedPart];
                        }
                        else if (t is JArray || t is JConstructor)
                        {
                            int index;
                            if (int.TryParse(unescapedPart, NumberStyles.None, CultureInfo.InvariantCulture, out index))
                            {
                                if (index > t.Count() || index < 0)
                                {
                                    resolvedToken = null;
                                }
                                else
                                {
                                    resolvedToken = t[index];
                                }
                            }
                            else
                            {
                                resolvedToken = null;
                            }
                        }
                        else
                        {
                            resolvedToken = null;
                        }

                        if (resolvedToken != null)
                        {
                            JSchemaAnnotation annotation = resolvedToken.Annotation <JSchemaAnnotation>();
                            if (annotation != null)
                            {
                                current = annotation.Schema;
                            }
                            else
                            {
                                current = resolvedToken;
                            }
                        }
                        else
                        {
                            current = null;
                        }
                    }
                    else if (current is IDictionary)
                    {
                        IDictionary d = (IDictionary)current;

                        current = d[unescapedPart];
                    }
                    else if (current is IList)
                    {
                        IList l = (IList)current;

                        int index;
                        if (int.TryParse(unescapedPart, NumberStyles.None, CultureInfo.InvariantCulture, out index))
                        {
                            if (index > l.Count || index < 0)
                            {
                                current = null;
                            }
                            else
                            {
                                current = l[index];
                            }
                        }
                        else
                        {
                            current = null;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                if (current is JToken)
                {
                    JToken t = (JToken)current;

                    JSchemaAnnotation annotation = t.Annotation <JSchemaAnnotation>();
                    if (annotation != null)
                    {
                        setSchema(annotation.Schema);
                        resolvedSchema = true;
                    }
                    else
                    {
                        schemaReader.ReadInlineSchema(setSchema, t);
                        resolvedSchema = true;
                    }
                }
                else
                {
                    var s = current as JSchema;
                    if (s != null)
                    {
                        setSchema(s);
                        resolvedSchema = true;
                    }
                    else
                    {
                        resolvedSchema = false;
                    }
                }

                schemaReader._schemaStack.Clear();
            }
            else
            {
                JSchemaDiscovery discovery = new JSchemaDiscovery();
                discovery.Discover(schema, null);

                Uri resolvedReference = ResolveSchemaId(rootSchemaId, reference);

                // default Uri comparison ignores fragments
                KnownSchema knownSchema = discovery.KnownSchemas.SingleOrDefault(s => s.Id.OriginalString.TrimEnd('#') == resolvedReference.OriginalString.TrimEnd('#'));

                if (knownSchema != null)
                {
                    resolvedSchema = true;
                    setSchema(knownSchema.Schema);
                }
                else
                {
                    int hashIndex = resolvedReference.OriginalString.IndexOf('#');
                    if (hashIndex != -1)
                    {
                        Uri path     = new Uri(resolvedReference.OriginalString.Substring(0, hashIndex), UriKind.RelativeOrAbsolute);
                        Uri fragment = new Uri(resolvedReference.OriginalString.Substring(hashIndex), UriKind.RelativeOrAbsolute);

                        // default Uri comparison ignores fragments
                        knownSchema = discovery.KnownSchemas.SingleOrDefault(s => s.Id.OriginalString.TrimEnd('#') == path.OriginalString);

                        if (knownSchema != null)
                        {
                            resolvedSchema = FindSchema(setSchema, knownSchema.Schema, path, fragment, schemaReader);
                        }
                        else
                        {
                            resolvedSchema = false;
                        }
                    }
                    else
                    {
                        resolvedSchema = false;
                    }
                }
            }
            return(resolvedSchema);
        }
        public static bool FindSchema(Action <JSchema> setSchema, JSchema schema, Uri rootSchemaId, Uri reference, JSchemaReader schemaReader, ref JSchemaDiscovery discovery)
        {
            // todo, better way to get parts from Uri
            string[] parts = reference.ToString().Split('/');

            bool resolvedSchema;

            if (parts.Length > 0 && (parts[0] == "#" || parts[0] == rootSchemaId + "#"))
            {
                schemaReader._schemaStack.Add(schema);

                JSchema parent  = schema;
                object  current = schema;
                for (int i = 1; i != parts.Length; ++i)
                {
                    string unescapedPart = UnescapeReference(parts[i]);

                    JSchema s = current as JSchema;
                    if (s != null)
                    {
                        schemaReader._schemaStack.Add(s);

                        parent  = s;
                        current = GetCurrentFromSchema(s, unescapedPart);
                    }
                    else if (current is JToken)
                    {
                        current = GetCurrentFromToken((JToken)current, unescapedPart);
                    }
                    else if (current is IDictionary <string, JSchema> )
                    {
                        IDictionary <string, JSchema> d = (IDictionary <string, JSchema>)current;

                        JSchema temp;
                        d.TryGetValue(unescapedPart, out temp);
                        current = temp;
                    }
                    else if (current is IList <JSchema> )
                    {
                        IList <JSchema> l = (IList <JSchema>)current;
                        int             index;

                        // if the schema collection is items then implicitly get first item if there is no position validation
                        if (ReferenceEquals(parent._items, l) && !parent.ItemsPositionValidation)
                        {
                            if (l.Count > 0)
                            {
                                current = GetCurrentFromSchema(l[0], unescapedPart);
                            }
                            else
                            {
                                current = null;
                            }
                        }
                        else if (int.TryParse(unescapedPart, NumberStyles.None, CultureInfo.InvariantCulture, out index))
                        {
                            if (index > l.Count || index < 0)
                            {
                                current = null;
                            }
                            else
                            {
                                current = l[index];
                            }
                        }
                        else
                        {
                            current = null;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                JToken t = current as JToken;
                if (t != null)
                {
                    JSchemaAnnotation annotation = t.Annotation <JSchemaAnnotation>();
                    if (annotation != null)
                    {
                        setSchema(annotation.Schema);
                        resolvedSchema = true;
                    }
                    else
                    {
                        JSchema inlineSchema = schemaReader.ReadInlineSchema(setSchema, t);

                        string path = reference.OriginalString;
                        if (path.StartsWith("#/", StringComparison.Ordinal))
                        {
                            path = path.Substring(2, path.Length - 2);
                        }

                        discovery.Discover(inlineSchema, rootSchemaId, path);

                        resolvedSchema = true;
                    }
                }
                else
                {
                    JSchema s = current as JSchema;
                    if (s != null)
                    {
                        setSchema(s);
                        resolvedSchema = true;

                        // schema is a reference schema and needs to be resolved
                        if (s.Reference != null)
                        {
                            schemaReader.AddDeferedSchema(null, setSchema, s);
                        }
                    }
                    else
                    {
                        resolvedSchema = false;
                    }
                }

                schemaReader._schemaStack.Clear();
            }
            else
            {
                discovery.Discover(schema, null);

                Uri resolvedReference = ResolveSchemaId(rootSchemaId, reference);

                // use firstordefault to handle duplicates
                KnownSchema knownSchema = discovery.KnownSchemas.FirstOrDefault(s => UriComparer.Instance.Equals(s.Id, resolvedReference));

                if (knownSchema != null)
                {
                    resolvedSchema = true;
                    setSchema(knownSchema.Schema);
                }
                else
                {
                    int hashIndex = resolvedReference.OriginalString.IndexOf('#');
                    if (hashIndex != -1)
                    {
                        Uri path     = new Uri(resolvedReference.OriginalString.Substring(0, hashIndex), UriKind.RelativeOrAbsolute);
                        Uri fragment = new Uri(resolvedReference.OriginalString.Substring(hashIndex), UriKind.RelativeOrAbsolute);

                        // there could be duplicated ids. use FirstOrDefault to get first schema with an id
                        knownSchema = discovery.KnownSchemas.FirstOrDefault(s => UriComparer.Instance.Equals(s.Id, path));

                        if (knownSchema != null)
                        {
                            // don't attempt to find a schema in the same schema again
                            // avoids stackoverflow
                            if (knownSchema.Schema != schema ||
                                !UriComparer.Instance.Equals(rootSchemaId, path) ||
                                !UriComparer.Instance.Equals(reference, fragment))
                            {
                                resolvedSchema = FindSchema(setSchema, knownSchema.Schema, path, fragment, schemaReader, ref discovery);
                            }
                            else
                            {
                                resolvedSchema = false;
                            }
                        }
                        else
                        {
                            resolvedSchema = false;
                        }
                    }
                    else
                    {
                        // special case
                        // look in the root schema's definitions for a definition with the same property name and id as reference
                        JToken definitions;
                        if (schema.ExtensionData.TryGetValue(Constants.PropertyNames.Definitions, out definitions))
                        {
                            JObject definitionsObject = definitions as JObject;
                            if (definitionsObject != null)
                            {
                                JProperty matchingProperty = definitionsObject.Properties().FirstOrDefault(p => TryCompare(p.Name, resolvedReference));

                                JObject o = matchingProperty?.Value as JObject;
                                if (o != null && TryCompare((string)o["id"], resolvedReference))
                                {
                                    JSchema inlineSchema = schemaReader.ReadInlineSchema(setSchema, o);

                                    discovery.Discover(inlineSchema, rootSchemaId, Constants.PropertyNames.Definitions + "/" + resolvedReference.OriginalString);

                                    resolvedSchema = true;
                                }
                                else
                                {
                                    resolvedSchema = false;
                                }
                            }
                            else
                            {
                                resolvedSchema = false;
                            }
                        }
                        else
                        {
                            resolvedSchema = false;
                        }
                    }
                }
            }

            return(resolvedSchema);
        }