/// <summary> /// Converts a Json Schema string to a <see cref="ModelMetadata"/> /// </summary> /// <param name="modelName">The name of the model.</param> /// <param name="jsonSchema">The Json Schema to be converted</param> /// <returns>An flattened representation of the Json Schema in the form of <see cref="ModelMetadata"/></returns> public ModelMetadata Convert(string modelName, string jsonSchema) { ModelName = modelName; _modelMetadata = new ModelMetadata(); _schema = JsonSchema.FromText(jsonSchema); var schemaUri = _schema.GetKeyword <IdKeyword>().Id; _schemaXsdMetadata = _schemaAnalyzer.AnalyzeSchema(_schema, schemaUri); ProcessSchema(_schema); return(_modelMetadata); }
/// <summary> /// Determines the type of root model the provided schema has. /// </summary> /// <param name="schema">The Json Schema to analyze.</param> protected void DetermineRootModel(JsonSchema schema) { Metadata.HasInlineRoot = true; var allOf = schema.GetKeyword <AllOfKeyword>(); var anyOf = schema.GetKeyword <AnyOfKeyword>(); var oneOf = schema.GetKeyword <OneOfKeyword>(); if (allOf != null && anyOf == null && oneOf == null) { // Only "allOf" Metadata.HasInlineRoot = !(allOf.Schemas.Count == 1 && IsRefSchema(allOf.Schemas[0])); } else if (allOf == null && anyOf != null && oneOf == null) { // Only "anyOf" Metadata.HasInlineRoot = !(anyOf.Schemas.Count == 1 && IsRefSchema(anyOf.Schemas[0])); } else if (allOf == null && anyOf == null && oneOf != null) { // Only "oneOf" Metadata.HasInlineRoot = !(oneOf.Schemas.Count == 1 && IsRefSchema(oneOf.Schemas[0])); } }
public void Constructor_TemplateExists_ShouldSetCorrectValues() { // Arrange JsonSchemaKeywords.RegisterXsdKeywords(); var expectedId = "https://dev.altinn.studio/org/repository/app/model/model.schema.json"; // Act var actualJsonTemplate = new SeresJsonTemplate(new Uri(expectedId), "melding"); // Assert JsonSchema jsonSchema = JsonSchema.FromText(actualJsonTemplate.GetJsonString()); var idKeyword = jsonSchema.GetKeyword <IdKeyword>(); idKeyword.Id.Should().Be(expectedId); var infoKeyword = jsonSchema.GetKeyword <InfoKeyword>(); var value = infoKeyword.Value; value.GetProperty("meldingsnavn").GetString().Should().Be("melding"); value.GetProperty("modellnavn").GetString().Should().Be("melding-modell"); var messageType = jsonSchema.FollowReference(JsonPointer.Parse("#/$defs/melding-modell")).Should().NotBeNull(); }
/// <summary> /// Tries to parse a schema to verify if it an array and returns the item schema if it is. /// For furter reference see https://json-schema.org/understanding-json-schema/reference/array.html /// </summary> /// <param name="schema">The Json Schema to analyze.</param> /// <param name="itemsSchema">If the schema is an array this will return schema for the items in the array; otherwise, null.</param> /// <returns>True if the schema is an array; otherwise, false</returns> protected static bool TryParseAsArray(JsonSchema schema, out JsonSchema itemsSchema) { if (schema.TryGetKeyword(out TypeKeyword typeKeyword) && typeKeyword.Type.HasFlag(SchemaValueType.Array)) { var itemsKeyword = schema.GetKeyword <ItemsKeyword>(); if (itemsKeyword == null) { throw new JsonSchemaConvertException("Schema must have an \"items\" keyword when \"type\" is set to array"); } itemsSchema = itemsKeyword.SingleSchema; return(true); } itemsSchema = null; return(false); }
private static List <(string PropertyName, JsonSchema PropertySchema)> FindSimpleContentProperties(JsonSchema schema) { var properties = new List <(string PropertyName, JsonSchema PropertySchema)>(); if (HasSingleAllOf(schema)) { foreach (var propertiesSchema in schema.GetKeyword <AllOfKeyword>().Schemas.Where(s => s.HasKeyword <PropertiesKeyword>())) { var propertiesKeyword = propertiesSchema.GetKeyword <PropertiesKeyword>(); properties.AddRange(propertiesKeyword.Properties.Select(prop => (prop.Key, prop.Value))); } } else if (schema.TryGetKeyword(out PropertiesKeyword propertiesKeyword)) { properties.AddRange(propertiesKeyword.Properties.Select(prop => (prop.Key, prop.Value))); } return(properties); }
/// <summary> /// Determines if the schema should be represented as a SimpleContentRestriction in the XSD. /// </summary> /// <param name="schema">The Json Schema to analyze.</param> /// <returns>True if it should be represented as a SimpleContentRestriction in the XSD; otherwise, false.</returns> protected bool IsValidSimpleContentRestriction(JsonSchema schema) { if (!HasSingleAllOf(schema)) { return(false); } var allOf = schema.GetKeyword <AllOfKeyword>(); var baseReferenceSchemas = allOf.Schemas.Where(s => s.HasKeyword <RefKeyword>()).ToList(); if (baseReferenceSchemas.Count != 1) { return(false); } var baseReferenceSchema = baseReferenceSchemas[0]; var baseSchema = FollowReference(baseReferenceSchema.GetKeyword <RefKeyword>()); // Make sure base is valid for SimpleContent restriction if (!IsValidSimpleContentExtension(baseSchema) && !IsValidSimpleContentRestriction(baseSchema)) { return(false); } var propertiesSchemas = allOf.Schemas.Where(s => s.HasKeyword <PropertiesKeyword>()).ToList(); // Don't allow extra subschemas not used in the pattern if (propertiesSchemas.Count + 1 != allOf.Schemas.Count) { return(false); } // All restriction properties must match properties from base type(s) var basePropertyNames = new HashSet <string>(); while (!IsValidSimpleType(baseSchema)) { foreach (var(propertyName, _) in FindSimpleContentProperties(baseSchema)) { basePropertyNames.Add(propertyName); } if (!baseSchema.TryGetKeyword(out AllOfKeyword baseAllOf)) { break; } var baseRefSchema = baseAllOf.Schemas .SingleOrDefault(s => s.HasKeyword <RefKeyword>()) ?.GetKeyword <RefKeyword>(); if (baseRefSchema == null) { break; } baseSchema = FollowReference(baseRefSchema); } var hasValueProperty = false; foreach (var(propertyName, propertySchema) in propertiesSchemas.SelectMany(ps => ps.GetKeyword <PropertiesKeyword>().Properties.Select(prop => (prop.Key, prop.Value)))) { if (!basePropertyNames.Contains(propertyName)) { // Can't restrict a property that is not present in base types, this is not a valid simple content restriction return(false); } var propertyTargetSchema = FollowReferencesIfAny(propertySchema); if (!hasValueProperty && propertyName == "value") { // "value" property hasValueProperty = true; // "value" property cannot be an attribute if (propertySchema.HasKeyword <XsdAttributeKeyword>()) { return(false); } } else { // restriction property must be an attribute if (!propertySchema.HasKeyword <XsdAttributeKeyword>()) { return(false); } } if (!IsValidSimpleTypeOrSimpleTypeRestriction(propertyTargetSchema) && !IsPlainRestrictionSchema(propertyTargetSchema)) { return(false); } } return(hasValueProperty); }