├── .gitignore ├── README.md ├── altinn-datamodel-harvester.deps.json ├── appsettings.json ├── app.yaml ├── appsettings.Development.json ├── altinn-datamodel-harvester.csproj.user ├── altinn-datamodel-harvester.csproj ├── Program.cs ├── Properties └── launchSettings.json ├── LICENSE ├── altinn-datamodel-harvester.sln ├── Services ├── Manatee.Json │ ├── FluentBuilderInfoExtension.cs │ ├── FluentBuilderTextsExtension.cs │ ├── InfoKeyword.cs │ └── TextsKeyword.cs ├── AltinnServiceRepository.cs └── XsdToJsonSchema.cs ├── Startup.cs └── Controllers └── SchemaController.cs /.gitignore: -------------------------------------------------------------------------------- 1 | /.vs 2 | /bin 3 | /obj 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # altinn-datamodel-harvester -------------------------------------------------------------------------------- /altinn-datamodel-harvester.deps.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Warning" 5 | } 6 | }, 7 | "AllowedHosts": "*" 8 | } 9 | -------------------------------------------------------------------------------- /app.yaml: -------------------------------------------------------------------------------- 1 | runtime: aspnetcore 2 | env: flex 3 | 4 | # costs 5 | manual_scaling: 6 | instances: 1 7 | resources: 8 | cpu: 1 9 | memory_gb: 4 10 | disk_size_gb: 10 11 | -------------------------------------------------------------------------------- /appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /altinn-datamodel-harvester.csproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Gae 5 | True 6 | True 7 | 8 | -------------------------------------------------------------------------------- /altinn-datamodel-harvester.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace fdkalt 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:62885", 8 | "sslPort": 44393 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "api/v1/convert", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "fdkalt": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "api/v1/convert", 24 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Altinn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /altinn-datamodel-harvester.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2050 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "altinn-datamodel-harvester", "altinn-datamodel-harvester.csproj", "{F4CD1956-65EF-4741-BCC3-02F138906788}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {F4CD1956-65EF-4741-BCC3-02F138906788}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {F4CD1956-65EF-4741-BCC3-02F138906788}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {F4CD1956-65EF-4741-BCC3-02F138906788}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {F4CD1956-65EF-4741-BCC3-02F138906788}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {E8561835-AF2D-4D32-BCD9-9B7F57E5E542} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Services/Manatee.Json/FluentBuilderInfoExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using AltinnCore.Common.Factories.ModelFactory.Manatee.Json; 6 | using Manatee.Json; 7 | 8 | namespace Manatee.Json.Schema 9 | { 10 | /// 11 | /// Extends to aid in construction. 12 | /// 13 | public static class FluentBuilderInfoExtension 14 | { 15 | /// 16 | /// Add a named text to the info keyword. 17 | /// 18 | /// Json Schema to add text to 19 | /// Name for text 20 | /// Actual text 21 | /// schema containing new text 22 | public static JsonSchema Info(this JsonSchema schema, string name, string text) 23 | { 24 | var keyword = schema.OfType().FirstOrDefault(); 25 | 26 | if (keyword == null) 27 | { 28 | keyword = new InfoKeyword(); 29 | schema.Add(keyword); 30 | } 31 | 32 | keyword.Add(name, text); 33 | 34 | return schema; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Services/Manatee.Json/FluentBuilderTextsExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using AltinnCore.Common.Factories.ModelFactory.Manatee.Json; 6 | using Manatee.Json; 7 | 8 | namespace Manatee.Json.Schema 9 | { 10 | /// 11 | /// Extends to aid in construction. 12 | /// 13 | public static class FluentBuilderTextsExtension 14 | { 15 | /// 16 | /// Add a category of texts to the texts keyword. 17 | /// 18 | /// Json Schema to add category of texts to 19 | /// Category for text 20 | /// Name for text 21 | /// Actual text 22 | /// schema containing new category and texts 23 | public static JsonSchema Texts(this JsonSchema schema, string category, string name, string text) 24 | { 25 | var keyword = schema.OfType().FirstOrDefault(); 26 | if (keyword == null) 27 | { 28 | keyword = new TextsKeyword(); 29 | schema.Add(keyword); 30 | } 31 | 32 | if (keyword.ContainsKey(category)) 33 | { 34 | JsonSchema categorySchema = keyword[category]; 35 | categorySchema.OtherData.Add(name, text); 36 | } 37 | else 38 | { 39 | JsonSchema categorySchema = new JsonSchema(); 40 | categorySchema.OtherData.Add(name, text); 41 | keyword.Add(category, categorySchema); 42 | } 43 | 44 | return schema; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.AspNetCore.Mvc; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.DependencyInjection; 10 | using Microsoft.Extensions.Logging; 11 | using Microsoft.Extensions.Options; 12 | 13 | namespace fdkalt 14 | { 15 | public class Startup 16 | { 17 | private readonly IHostingEnvironment _env; 18 | private readonly IConfiguration _config; 19 | private readonly ILoggerFactory _loggerFactory; 20 | 21 | public Startup(IHostingEnvironment env, IConfiguration configuration, ILoggerFactory loggerFactory) 22 | { 23 | Configuration = configuration; 24 | _env = env; 25 | _loggerFactory = loggerFactory; 26 | } 27 | 28 | public IConfiguration Configuration { get; } 29 | 30 | // This method gets called by the runtime. Use this method to add services to the container. 31 | public void ConfigureServices(IServiceCollection services) 32 | { 33 | var logger = _loggerFactory.CreateLogger(); 34 | 35 | if (_env.IsDevelopment()) 36 | { 37 | // Development service configuration 38 | 39 | logger.LogInformation("Development environment"); 40 | } 41 | else 42 | { 43 | // Non-development service configuration 44 | 45 | logger.LogInformation($"Environment: {_env.EnvironmentName}"); 46 | } 47 | services.AddMvc(); 48 | } 49 | 50 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 51 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 52 | { 53 | if (env.IsDevelopment()) 54 | { 55 | app.UseDeveloperExceptionPage(); 56 | } 57 | else 58 | { 59 | app.UseExceptionHandler("/Error"); 60 | } 61 | 62 | app.UseMvc(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Controllers/SchemaController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Net.Http; 6 | using System.Threading.Tasks; 7 | using System.Xml; 8 | using AltinnCore.Common.Factories.ModelFactory; 9 | using Manatee.Json; 10 | using Microsoft.AspNetCore.Authorization; 11 | using Microsoft.AspNetCore.Http; 12 | using Microsoft.AspNetCore.Mvc; 13 | using Microsoft.Extensions.Primitives; 14 | using Microsoft.Net.Http.Headers; 15 | using Newtonsoft.Json; 16 | 17 | namespace Altinn.Service.Controllers 18 | { 19 | /// 20 | /// This controller contains utility operations to convert from xsd to jsonSchema 21 | /// 22 | public class SchemaController : Controller 23 | { 24 | /// 25 | /// Returns the all production schemas in Altinn as JsonSchemas 26 | /// 27 | /// The schemas 28 | [HttpGet] 29 | [Route("api/v1/schemas")] 30 | public async Task Schemas() 31 | { 32 | AltinnServiceRepository repositoryClient = new AltinnServiceRepository(); 33 | 34 | Task> serviceRequestTask = AltinnServiceRepository.ReadAllSchemas(); 35 | 36 | await Task.WhenAll(serviceRequestTask); 37 | 38 | if (serviceRequestTask.Result != null) 39 | { 40 | Manatee.Json.Serialization.JsonSerializer serializer = new Manatee.Json.Serialization.JsonSerializer(); 41 | 42 | JsonValue json = serializer.Serialize(serviceRequestTask.Result); 43 | 44 | return Ok(json.GetIndentedString()); 45 | } 46 | 47 | return NoContent(); 48 | } 49 | 50 | [HttpPost] 51 | [Route("api/v1/convert")] 52 | public async Task Convert() 53 | { 54 | XmlReaderSettings settings = new XmlReaderSettings 55 | { 56 | IgnoreWhitespace = true, 57 | }; 58 | 59 | if (Request.ContentType.Contains("text/xml")) 60 | { 61 | XmlReader doc = XmlReader.Create(Request.Body, settings); 62 | 63 | // XSD to Json Schema 64 | XsdToJsonSchema xsdToJsonSchemaConverter = new XsdToJsonSchema(doc, null); 65 | 66 | Manatee.Json.Serialization.JsonSerializer serializer = new Manatee.Json.Serialization.JsonSerializer(); 67 | 68 | JsonValue json = serializer.Serialize(xsdToJsonSchemaConverter.AsJsonSchema()); 69 | 70 | return Ok(json.GetIndentedString()); 71 | } 72 | 73 | return NotFound("Cannot read body. Needs to be XSD."); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Services/Manatee.Json/InfoKeyword.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using Manatee.Json; 6 | using Manatee.Json.Pointer; 7 | using Manatee.Json.Schema; 8 | using Manatee.Json.Serialization; 9 | 10 | namespace AltinnCore.Common.Factories.ModelFactory.Manatee.Json 11 | { 12 | /// 13 | /// Defines the infos JSON Schema keyword. Based on Manatee.Json.Schema.DefinitionsKeyword 14 | /// 15 | [DebuggerDisplay("Name={Name}; Count={Count}")] 16 | public class InfoKeyword : Dictionary, IJsonSchemaKeyword, IEquatable 17 | { 18 | /// 19 | /// Gets the name of the keyword. 20 | /// 21 | public string Name => "info"; 22 | 23 | /// 24 | /// Gets the versions (drafts) of JSON Schema which support this keyword. 25 | /// 26 | public JsonSchemaVersion SupportedVersions { get; } = JsonSchemaVersion.All; 27 | 28 | /// 29 | /// Gets the a value indicating the sequence in which this keyword will be evaluated. 30 | /// 31 | public int ValidationSequence => 1; 32 | 33 | /// 34 | /// Provides the validation logic for this keyword. 35 | /// 36 | /// The context object. 37 | /// Results object containing a final result and any errors that may have been found. 38 | public SchemaValidationResults Validate(SchemaValidationContext context) 39 | { 40 | return new SchemaValidationResults(Name, context); 41 | } 42 | 43 | /// 44 | /// Used register any subschemas during validation. Enables look-forward compatibility with $ref keywords. 45 | /// 46 | /// The current base URI 47 | public void RegisterSubschemas(Uri baseUri) 48 | { 49 | } 50 | 51 | /// 52 | /// Resolves any subschemas during resolution of a $ref during validation. 53 | /// 54 | /// A to the target schema. 55 | /// The current base URI. 56 | /// The referenced schema, if it exists; otherwise null. 57 | public JsonSchema ResolveSubschema(JsonPointer pointer, Uri baseUri) 58 | { 59 | return null; 60 | } 61 | 62 | /// 63 | /// Builds an object from a . 64 | /// 65 | /// The representation of the object. 66 | /// The instance to use for additional 67 | /// serialization of values. 68 | public void FromJson(JsonValue json, JsonSerializer serializer) 69 | { 70 | throw new NotImplementedException(); 71 | } 72 | 73 | /// 74 | /// Converts an object to a . 75 | /// 76 | /// The instance to use for additional 77 | /// serialization of values. 78 | /// The representation of the object. 79 | public JsonValue ToJson(JsonSerializer serializer) 80 | { 81 | return this.ToDictionary( 82 | kvp => kvp.Key, kvp => serializer.Serialize(kvp.Value)) 83 | .ToJson(); 84 | } 85 | 86 | /// Indicates whether the current object is equal to another object of the same type. 87 | /// true if the current object is equal to the parameter; otherwise, false. 88 | /// An object to compare with this object. 89 | public bool Equals(InfoKeyword other) 90 | { 91 | if (other is null) 92 | { 93 | return false; 94 | } 95 | 96 | if (ReferenceEquals(this, other)) 97 | { 98 | return true; 99 | } 100 | 101 | return GetCollectionHashCode(this).Equals(GetCollectionHashCode(other)); 102 | } 103 | 104 | /// Indicates whether the current object is equal to another object of the same type. 105 | /// true if the current object is equal to the parameter; otherwise, false. 106 | /// An object to compare with this object. 107 | public bool Equals(IJsonSchemaKeyword other) 108 | { 109 | return Equals(other as InfoKeyword); 110 | } 111 | 112 | /// Determines whether the specified object is equal to the current object. 113 | /// true if the specified object is equal to the current object; otherwise, false. 114 | /// The object to compare with the current object. 115 | public override bool Equals(object obj) 116 | { 117 | return Equals(obj as InfoKeyword); 118 | } 119 | 120 | /// Serves as the default hash function. 121 | /// A hash code for the current object. 122 | public override int GetHashCode() 123 | { 124 | return GetCollectionHashCode(this); 125 | } 126 | 127 | /// Calculate hash code for collection. Copied from Manatee.Json.Internal 128 | /// hash code for the collection 129 | /// The object to calculate hash code for. 130 | public static int GetCollectionHashCode(IEnumerable> collection) 131 | { 132 | return collection.OrderBy(kvp => kvp.Key, StringComparer.Ordinal) 133 | .Aggregate(0, (current, kvp) => 134 | { 135 | unchecked 136 | { 137 | var code = (current * 397) ^ kvp.Key.GetHashCode(); 138 | code = (code * 397) ^ (kvp.Value?.GetHashCode() ?? 0); 139 | return code; 140 | } 141 | }); 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /Services/Manatee.Json/TextsKeyword.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using Manatee.Json; 6 | using Manatee.Json.Pointer; 7 | using Manatee.Json.Schema; 8 | using Manatee.Json.Serialization; 9 | 10 | namespace AltinnCore.Common.Factories.ModelFactory.Manatee.Json 11 | { 12 | /// 13 | /// Defines the texts JSON Schema keyword. Based on Manatee.Json.Schema.DefinitionsKeyword 14 | /// 15 | [DebuggerDisplay("Name={Name}; Count={Count}")] 16 | public class TextsKeyword : Dictionary, IJsonSchemaKeyword, IEquatable 17 | { 18 | /// 19 | /// Gets the name of the keyword. 20 | /// 21 | public string Name => "texts"; 22 | 23 | /// 24 | /// Gets the versions (drafts) of JSON Schema which support this keyword. 25 | /// 26 | public JsonSchemaVersion SupportedVersions { get; } = JsonSchemaVersion.All; 27 | 28 | /// 29 | /// Gets the a value indicating the sequence in which this keyword will be evaluated. 30 | /// 31 | public int ValidationSequence => 1; 32 | 33 | /// 34 | /// Provides the validation logic for this keyword. 35 | /// 36 | /// The context object. 37 | /// Results object containing a final result and any errors that may have been found. 38 | public SchemaValidationResults Validate(SchemaValidationContext context) 39 | { 40 | return new SchemaValidationResults(Name, context); 41 | } 42 | 43 | /// 44 | /// Used register any subschemas during validation. Enables look-forward compatibility with $ref keywords. 45 | /// 46 | /// The current base URI 47 | public void RegisterSubschemas(Uri baseUri) 48 | { 49 | foreach (JsonSchema schema in Values) 50 | { 51 | schema.RegisterSubschemas(baseUri); 52 | } 53 | } 54 | 55 | /// 56 | /// Resolves any subschemas during resolution of a $ref during validation. 57 | /// 58 | /// A to the target schema. 59 | /// The current base URI. 60 | /// The referenced schema, if it exists; otherwise null. 61 | public JsonSchema ResolveSubschema(JsonPointer pointer, Uri baseUri) 62 | { 63 | var first = pointer.FirstOrDefault(); 64 | if (first == null) 65 | { 66 | return null; 67 | } 68 | 69 | if (!TryGetValue(first, out var schema)) 70 | { 71 | return null; 72 | } 73 | 74 | return schema.ResolveSubschema(new JsonPointer(pointer.Skip(1)), baseUri); 75 | } 76 | 77 | /// 78 | /// Builds an object from a . 79 | /// 80 | /// The representation of the object. 81 | /// The instance to use for additional 82 | /// serialization of values. 83 | public void FromJson(JsonValue json, JsonSerializer serializer) 84 | { 85 | throw new NotImplementedException(); 86 | } 87 | 88 | /// 89 | /// Converts an object to a . 90 | /// 91 | /// The instance to use for additional 92 | /// serialization of values. 93 | /// The representation of the object. 94 | public JsonValue ToJson(JsonSerializer serializer) 95 | { 96 | return this.ToDictionary( 97 | kvp => kvp.Key, kvp => serializer.Serialize(kvp.Value)) 98 | .ToJson(); 99 | } 100 | 101 | /// Indicates whether the current object is equal to another object of the same type. 102 | /// true if the current object is equal to the parameter; otherwise, false. 103 | /// An object to compare with this object. 104 | public bool Equals(TextsKeyword other) 105 | { 106 | if (other is null) 107 | { 108 | return false; 109 | } 110 | 111 | if (ReferenceEquals(this, other)) 112 | { 113 | return true; 114 | } 115 | 116 | return GetCollectionHashCode(this).Equals(GetCollectionHashCode(other)); 117 | } 118 | 119 | /// Indicates whether the current object is equal to another object of the same type. 120 | /// true if the current object is equal to the parameter; otherwise, false. 121 | /// An object to compare with this object. 122 | public bool Equals(IJsonSchemaKeyword other) 123 | { 124 | return Equals(other as TextsKeyword); 125 | } 126 | 127 | /// Determines whether the specified object is equal to the current object. 128 | /// true if the specified object is equal to the current object; otherwise, false. 129 | /// The object to compare with the current object. 130 | public override bool Equals(object obj) 131 | { 132 | return Equals(obj as TextsKeyword); 133 | } 134 | 135 | /// Serves as the default hash function. 136 | /// A hash code for the current object. 137 | public override int GetHashCode() 138 | { 139 | return GetCollectionHashCode(this); 140 | } 141 | 142 | /// Calculate hash code for collection. Copied from Manatee.Json.Internal 143 | /// hash code for the collection 144 | /// The object to calculate hash code for. 145 | public static int GetCollectionHashCode(IEnumerable> collection) 146 | { 147 | return collection.OrderBy(kvp => kvp.Key, StringComparer.Ordinal) 148 | .Aggregate(0, (current, kvp) => 149 | { 150 | unchecked 151 | { 152 | var code = (current * 397) ^ kvp.Key.GetHashCode(); 153 | code = (code * 397) ^ (kvp.Value?.GetHashCode() ?? 0); 154 | return code; 155 | } 156 | }); 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /Services/AltinnServiceRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.IO.Compression; 6 | using System.Linq; 7 | using System.Net.Http; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Xml; 11 | using System.Xml.Serialization; 12 | using AltinnCore.Common.Factories.ModelFactory; 13 | using Manatee.Json; 14 | using Manatee.Json.Schema; 15 | using Manatee.Json.Serialization; 16 | using Microsoft.Extensions.Logging; 17 | using Newtonsoft.Json; 18 | using JsonSerializer = Manatee.Json.Serialization.JsonSerializer; 19 | 20 | namespace Altinn.Service 21 | { 22 | /// 23 | /// Rest client that asks altinn for the xsds in production 24 | /// 25 | public class AltinnServiceRepository 26 | { 27 | private static HttpClient client = new HttpClient(); 28 | 29 | /// 30 | /// Initializes a new instance of the class. 31 | /// 32 | public AltinnServiceRepository() 33 | { 34 | Console.WriteLine("starting"); 35 | } 36 | 37 | /// 38 | /// Gets all resources in altinn metadata 39 | /// 40 | /// list of the resources 41 | public static async Task> GetResourcesAsync() 42 | { 43 | List resources = null; 44 | 45 | string path = "https://www.altinn.no/api/metadata"; 46 | 47 | HttpResponseMessage response = await client.GetAsync(path); 48 | if (response.IsSuccessStatusCode) 49 | { 50 | string content = await response.Content.ReadAsStringAsync(); 51 | resources = JsonConvert.DeserializeObject>(content); 52 | } 53 | 54 | return resources; 55 | } 56 | 57 | /// 58 | /// Get forms metadata from altinn 59 | /// 60 | /// The resource 61 | /// The form resource 62 | public static async Task GetFormsMetadata(AltinnResource altinnResource) 63 | { 64 | string path = FormTaskUrl(altinnResource); 65 | FormResource result = null; 66 | 67 | HttpResponseMessage response = await client.GetAsync(path); 68 | if (response.IsSuccessStatusCode) 69 | { 70 | string content = await response.Content.ReadAsStringAsync(); 71 | result = JsonConvert.DeserializeObject(content); 72 | } 73 | 74 | return result; 75 | } 76 | 77 | private static string FormTaskUrl(AltinnResource altinnResource) 78 | { 79 | return "https://www.altinn.no/api/metadata/formtask/" + altinnResource.ServiceCode + "/" + altinnResource.ServiceEditionCode; 80 | } 81 | 82 | private static string XsdUrl(AltinnResource altinnResource, AltinnFormMetaData formMetaData) 83 | { 84 | return FormTaskUrl(altinnResource) + "/forms/" + formMetaData.DataFormatID + "/" + formMetaData.DataFormatVersion + "/xsd"; 85 | } 86 | 87 | /// 88 | /// Reads all altinn services resources and returns a list of these 89 | /// 90 | /// the list 91 | public static async Task> ReadAllSchemas() 92 | { 93 | List resources = await GetResourcesAsync(); 94 | 95 | List result = new List(); 96 | Dictionary orgShortnameToOrgnumberMap = BuildOrganizationNumberMap(); 97 | Dictionary serviceCodeToServiceEditionCodeDictionary = new Dictionary(); 98 | 99 | string[] excludeServiceOwnerCodes = { "ACN", "ASF", "TTD" }; 100 | 101 | foreach (AltinnResource resource in resources) 102 | { 103 | if (excludeServiceOwnerCodes.Contains(resource.ServiceOwnerCode)) 104 | { 105 | continue; 106 | } 107 | 108 | List forms = new List(); 109 | 110 | FormResource r = await GetFormsMetadata(resource); 111 | if (r != null && r.FormsMetaData != null && r.FormsMetaData.ToArray() != null) 112 | { 113 | foreach (AltinnFormMetaData form in r.FormsMetaData) 114 | { 115 | form.XsdSchemaUrl = XsdUrl(resource, form); 116 | 117 | form.JsonSchema = Zip(DownloadAndConvertXsdToJsonSchema(form.XsdSchemaUrl)); 118 | forms.Add(form); 119 | } 120 | } 121 | 122 | if (forms.Count > 0) 123 | { 124 | string orgnr = orgShortnameToOrgnumberMap.GetValueOrDefault(resource.ServiceOwnerCode); 125 | 126 | if (string.IsNullOrEmpty(orgnr)) 127 | { 128 | Debug.WriteLine(resource.ServiceOwnerCode + "\t" + resource.ServiceOwnerName); 129 | } 130 | 131 | resource.OrganizationNumber = orgnr; 132 | resource.Forms = forms; 133 | 134 | result.Add(resource); 135 | 136 | RememberHighestServiceEditionCode(serviceCodeToServiceEditionCodeDictionary, resource); 137 | } 138 | } 139 | 140 | List filteredResult = new List(); 141 | 142 | foreach (AltinnResource resource in result) 143 | { 144 | string highestEditionCode = serviceCodeToServiceEditionCodeDictionary.GetValueOrDefault(resource.ServiceCode); 145 | 146 | if (resource.ServiceEditionCode.Equals(highestEditionCode)) 147 | { 148 | filteredResult.Add(resource); 149 | } 150 | } 151 | 152 | return filteredResult; 153 | } 154 | 155 | private static string Zip(JsonSchema jsonSchema) 156 | { 157 | JsonSerializer serializer = new JsonSerializer(); 158 | JsonValue json = serializer.Serialize(jsonSchema); 159 | 160 | byte[] bytes = Encoding.UTF8.GetBytes(json.GetIndentedString()); 161 | using (MemoryStream msi = new MemoryStream(bytes)) 162 | using (MemoryStream mso = new MemoryStream()) 163 | { 164 | using (GZipStream gs = new GZipStream(mso, CompressionMode.Compress)) 165 | { 166 | msi.CopyTo(gs); 167 | } 168 | 169 | return Convert.ToBase64String(mso.ToArray()); 170 | } 171 | } 172 | 173 | private static Dictionary BuildOrganizationNumberMap() 174 | { 175 | Dictionary orgShortnameToOrgnumberMap = new Dictionary(); 176 | 177 | using (StreamReader r = new StreamReader("Services/orgs.json")) 178 | { 179 | string json = r.ReadToEnd(); 180 | List orgs = JsonConvert.DeserializeObject>(json); 181 | foreach (Organization org in orgs) 182 | { 183 | orgShortnameToOrgnumberMap.Add(org.Shortname, org.Orgnr); 184 | } 185 | } 186 | 187 | return orgShortnameToOrgnumberMap; 188 | } 189 | 190 | private static JsonSchema DownloadAndConvertXsdToJsonSchema(string xsdSchemaUrl) 191 | { 192 | XmlReaderSettings settings = new XmlReaderSettings(); 193 | settings.IgnoreWhitespace = true; 194 | 195 | XmlReader doc = XmlReader.Create(xsdSchemaUrl, settings); 196 | 197 | // XSD to Json Schema 198 | XsdToJsonSchema xsdToJsonSchemaConverter = new XsdToJsonSchema(doc, null); 199 | return xsdToJsonSchemaConverter.AsJsonSchema(); 200 | } 201 | 202 | private static void RememberHighestServiceEditionCode(Dictionary serviceCodeToServiceEditionCodeDictionary, AltinnResource resource) 203 | { 204 | string serviceCode = resource.ServiceCode; 205 | string lastHighestServiceEditionCode = serviceCodeToServiceEditionCodeDictionary.GetValueOrDefault(serviceCode); 206 | string currentServiceEditionCode = resource.ServiceEditionCode; 207 | 208 | if (string.IsNullOrEmpty(lastHighestServiceEditionCode)) 209 | { 210 | serviceCodeToServiceEditionCodeDictionary.Add(serviceCode, resource.ServiceEditionCode); 211 | } 212 | else 213 | { 214 | int lastEditionCode = 0; 215 | int currentEditionCode = 0; 216 | 217 | int.TryParse(lastHighestServiceEditionCode, out lastEditionCode); 218 | int.TryParse(currentServiceEditionCode, out currentEditionCode); 219 | 220 | if (currentEditionCode > lastEditionCode) 221 | { 222 | serviceCodeToServiceEditionCodeDictionary.Remove(serviceCode); 223 | serviceCodeToServiceEditionCodeDictionary.Add(serviceCode, resource.ServiceEditionCode); 224 | } 225 | } 226 | } 227 | } 228 | 229 | #pragma warning disable SA1600 // Elements should be documented 230 | public class AltinnResource 231 | { 232 | public string ServiceOwnerCode { get; set; } 233 | 234 | public string OrganizationNumber { get; set; } 235 | 236 | public string ServiceOwnerName { get; set; } 237 | 238 | public string ServiceName { get; set; } 239 | 240 | public string ServiceCode { get; set; } 241 | 242 | public string ServiceEditionCode { get; set; } 243 | 244 | public DateTime ValidFrom { get; set; } 245 | 246 | public DateTime ValidTo { get; set; } 247 | 248 | public string ServiceType { get; set; } 249 | 250 | public string EnterpriseUserEnabled { get; set; } 251 | 252 | public List Forms { get; set; } 253 | } 254 | 255 | public class FormResource 256 | { 257 | public string RestEnabled { get; set; } 258 | 259 | public List FormsMetaData { get; set; } 260 | } 261 | 262 | public class AltinnFormMetaData 263 | { 264 | public string FormID { get; set; } 265 | 266 | public string FormName { get; set; } 267 | 268 | public string FormType { get; set; } 269 | 270 | public string DataFormatID { get; set; } 271 | 272 | public string DataFormatVersion { get; set; } 273 | 274 | public string XsdSchemaUrl { get; set; } 275 | 276 | public string JsonSchema { get; set; } 277 | } 278 | 279 | public class Organization 280 | { 281 | public string Name { get; set; } 282 | 283 | public string Shortname { get; set; } 284 | 285 | public string Orgnr { get; set; } 286 | 287 | public string Url { get; set; } 288 | } 289 | } 290 | -------------------------------------------------------------------------------- /Services/XsdToJsonSchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Globalization; 5 | using System.Text; 6 | using System.Xml; 7 | using System.Xml.Schema; 8 | using AltinnCore.Common.Factories.ModelFactory.Manatee.Json; 9 | using Manatee.Json; 10 | using Manatee.Json.Schema; 11 | using Manatee.Json.Serialization; 12 | using Microsoft.Extensions.Logging; 13 | 14 | namespace AltinnCore.Common.Factories.ModelFactory 15 | { 16 | /// 17 | /// For, like, converting Xsd to JsonSchema 18 | /// 19 | public class XsdToJsonSchema 20 | { 21 | private ILogger _logger; 22 | 23 | private XmlReader xsdReader; 24 | private XmlSchema mainXsd; 25 | private JsonSchema mainJsonSchema; 26 | 27 | private IDictionary itemNames = new Dictionary(); 28 | private IDictionary typeNames = new Dictionary(); 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | /// Reader for the XSD to convert 34 | /// logger 35 | public XsdToJsonSchema(XmlReader xsdReader, ILogger logger = null) 36 | { 37 | this.xsdReader = xsdReader; 38 | this._logger = logger; 39 | 40 | mainXsd = XmlSchema.Read(xsdReader, ValidationCallback); 41 | } 42 | 43 | /// 44 | /// Initializes a new instance of the class. 45 | /// 46 | /// the schema 47 | /// the logger 48 | public XsdToJsonSchema(XmlSchema schema, ILogger logger = null) 49 | { 50 | mainXsd = schema; 51 | this._logger = logger; 52 | } 53 | 54 | /// 55 | /// Perform the actual conversion (to JsonValue) 56 | /// 57 | /// JsonValue for root of Json Schema representation of schema 58 | public JsonValue AsJsonValue() 59 | { 60 | return new JsonSerializer().Serialize(AsJsonSchema()); 61 | } 62 | 63 | /// 64 | /// Perform the actual conversion (to JsonSchema) 65 | /// 66 | /// Json Schema representation of schema 67 | public JsonSchema AsJsonSchema() 68 | { 69 | // Set up Json Schema object 70 | mainJsonSchema = new JsonSchema(); 71 | mainJsonSchema.Schema("http://json-schema.org/schema#"); 72 | mainJsonSchema.Id("schema.json"); // Guid.NewGuid().ToString()); 73 | AddTypeObject(mainJsonSchema); 74 | 75 | XmlSchemaObjectEnumerator enumerator = mainXsd.Items.GetEnumerator(); 76 | while (enumerator.MoveNext()) 77 | { 78 | XmlSchemaObject item = enumerator.Current; 79 | GetItemName(item); // Will register name for top-level item first, so other items with conflicting name will not become duplicates 80 | 81 | if (item is XmlSchemaElement) 82 | { 83 | bool isRequired; 84 | JsonSchema itemSchema = ParseTopLevelElement((XmlSchemaElement)item, out isRequired); 85 | if (itemSchema != null) 86 | { 87 | mainJsonSchema.Property(GetItemName(item).Name, itemSchema); 88 | } 89 | } 90 | } 91 | 92 | enumerator = mainXsd.Items.GetEnumerator(); 93 | while (enumerator.MoveNext()) 94 | { 95 | XmlSchemaObject item = enumerator.Current; 96 | 97 | bool isRequired; 98 | object parsedObject = Parse(item, out isRequired); 99 | if (parsedObject == null) 100 | { 101 | } 102 | else if (parsedObject is JsonSchema) 103 | { 104 | JsonSchema parsedSchema = (JsonSchema)parsedObject; 105 | if (!(item is XmlSchemaElement) && parsedSchema != null) 106 | { 107 | AddDefinition(item, parsedSchema); 108 | } 109 | } 110 | else 111 | { 112 | throw new NotImplementedException(); 113 | } 114 | } 115 | 116 | return mainJsonSchema; 117 | } 118 | 119 | private object Parse(XmlSchemaObject item, out bool isRequired) 120 | { 121 | isRequired = false; 122 | 123 | if (item is XmlSchemaElement) 124 | { 125 | return ParseElement((XmlSchemaElement)item, out isRequired); 126 | } 127 | else if (item is XmlSchemaComplexType) 128 | { 129 | return ParseComplexType((XmlSchemaComplexType)item); 130 | } 131 | else if (item is XmlSchemaSimpleType) 132 | { 133 | JsonSchema simpleTypeSchema = new JsonSchema(); 134 | AppendSimpleType((XmlSchemaSimpleType)item, simpleTypeSchema); 135 | return simpleTypeSchema; 136 | } 137 | else if (item is XmlSchemaAnnotation) 138 | { 139 | AppendAnnotation((XmlSchemaAnnotation)item, mainJsonSchema); 140 | return null; 141 | } 142 | else if (item is XmlSchemaGroup || item is XmlSchemaAttributeGroup || item is XmlSchemaAttribute) 143 | { 144 | // Do nothing. xsd:group and top-level xsd:attribute are expanded in place 145 | return null; 146 | } 147 | else 148 | { 149 | throw new NotImplementedException(); 150 | } 151 | } 152 | 153 | private JsonSchema ParseTopLevelElement(XmlSchemaElement item, out bool isRequired) 154 | { 155 | return ParseElement(item, true, out isRequired); 156 | } 157 | 158 | private JsonSchema ParseElement(XmlSchemaElement item, out bool isRequired) 159 | { 160 | return ParseElement(item, false, out isRequired); 161 | } 162 | 163 | private JsonSchema ParseElement(XmlSchemaElement item, bool isFirstPass, out bool isRequired) 164 | { 165 | XmlQualifiedName elementName = GetItemName(item); // This will become either .Name of .RefName.Name 166 | 167 | isRequired = false; 168 | 169 | JsonSchema elementSchema = new JsonSchema(); 170 | 171 | if (item.Annotation != null) 172 | { 173 | AppendAnnotated(item, elementSchema); 174 | } 175 | 176 | if (item.Constraints.Count > 0) 177 | { 178 | throw new NotImplementedException(); 179 | } 180 | 181 | if (item.DefaultValue != null) 182 | { 183 | LogInfo(elementName.ToString() + ": Ignoring Default value \"" + item.DefaultValue + "\""); 184 | } 185 | 186 | if (item.ElementSchemaType != null) 187 | { 188 | throw new NotImplementedException(); 189 | } 190 | 191 | if (item.ElementType != null) 192 | { 193 | throw new NotImplementedException(); 194 | } 195 | 196 | if (item.Final != XmlSchemaDerivationMethod.None) 197 | { 198 | LogInfo(elementName.ToString() + ": Ignoring Final value"); 199 | } 200 | 201 | if (item.FixedValue != null) 202 | { 203 | LogInfo(elementName.ToString() + ": Ignoring Fixed value \"" + item.FixedValue + "\""); 204 | } 205 | 206 | if (item.IsAbstract) 207 | { 208 | LogInfo(elementName.ToString() + ": Ignoring Abstract"); 209 | } 210 | 211 | if (!item.IsNillable) 212 | { 213 | // ToDo 214 | } 215 | 216 | if (item.MinOccurs >= 1 || 217 | (item.MinOccursString != null && Convert.ToUInt32(item.MinOccursString, CultureInfo.InvariantCulture) >= 1)) 218 | { 219 | isRequired = true; 220 | } 221 | 222 | /* item.MaxOccursString is handled when appending type info */ 223 | 224 | if (!item.RefName.IsEmpty) 225 | { 226 | AppendType(FindObject(elementName), item, elementSchema); // Elementname is already set to refName here 227 | } 228 | 229 | if (item.SchemaType != null) 230 | { 231 | if (isFirstPass) 232 | { 233 | AppendType(item, elementSchema); 234 | } 235 | else 236 | { 237 | if (item.SchemaType is XmlSchemaComplexType) 238 | { 239 | XmlQualifiedName complexTypeName = GetItemName(item.SchemaType); 240 | JsonSchema complexTypeSchema = ParseComplexType((XmlSchemaComplexType)item.SchemaType); 241 | AddDefinition(item.SchemaType, complexTypeSchema); 242 | AppendTypeFromNameInternal(complexTypeName, elementSchema); 243 | } 244 | else if (item.SchemaType is XmlSchemaSimpleType) 245 | { 246 | XmlQualifiedName simpleTypeName = GetItemName(item.SchemaType); 247 | JsonSchema simpleTypeSchema = new JsonSchema(); 248 | AppendSimpleType((XmlSchemaSimpleType)item.SchemaType, simpleTypeSchema); 249 | AddDefinition(item.SchemaType, simpleTypeSchema); 250 | } 251 | else 252 | { 253 | throw new NotImplementedException(); 254 | } 255 | } 256 | } 257 | 258 | if (!item.SchemaTypeName.IsEmpty) 259 | { 260 | AppendType(item, elementSchema); 261 | } 262 | 263 | return elementSchema; 264 | } 265 | 266 | private JsonSchema ParseComplexType(XmlSchemaComplexType item) 267 | { 268 | JsonSchema complexTypeSchema = new JsonSchema(); 269 | List requiredList = new List(); 270 | 271 | if (item.Annotation != null) 272 | { 273 | AppendAnnotated(item, complexTypeSchema); 274 | } 275 | 276 | if (item.AnyAttribute != null) 277 | { 278 | TagAnyAttribute(complexTypeSchema); 279 | } 280 | 281 | if (item.Attributes.Count > 0) 282 | { 283 | foreach (XmlSchemaAttribute attribute in item.Attributes) 284 | { 285 | bool isRequired; 286 | JsonSchema attributeSchema = ParseAttribute(attribute, out isRequired); 287 | if (attributeSchema != null) 288 | { 289 | XmlQualifiedName name = GetItemName(attribute); 290 | complexTypeSchema.Property(name.Name, attributeSchema); 291 | if (isRequired) 292 | { 293 | requiredList.Add(name); 294 | } 295 | } 296 | } 297 | } 298 | 299 | if (item.BaseSchemaType != null) 300 | { 301 | throw new NotImplementedException(); 302 | } 303 | 304 | if (item.BaseXmlSchemaType != null) 305 | { 306 | throw new NotImplementedException(); 307 | } 308 | 309 | if (item.ContentModel != null) 310 | { 311 | if (item.ContentModel is XmlSchemaComplexContent) 312 | { 313 | AppendComplexContent((XmlSchemaComplexContent)item.ContentModel, complexTypeSchema, requiredList); 314 | } 315 | else if (item.ContentModel is XmlSchemaSimpleContent) 316 | { 317 | AppendSimpleContent((XmlSchemaSimpleContent)item.ContentModel, complexTypeSchema, requiredList); 318 | } 319 | else 320 | { 321 | throw new NotImplementedException(); 322 | } 323 | } 324 | 325 | if (item.Particle != null) 326 | { 327 | AppendParticle(item.Particle, complexTypeSchema, requiredList); 328 | } 329 | 330 | if (requiredList.Count > 0) 331 | { 332 | complexTypeSchema.Required(RequiredListToArray(requiredList)); 333 | } 334 | 335 | return complexTypeSchema; 336 | } 337 | 338 | private void AppendSimpleType(XmlSchemaSimpleType item, JsonSchema appendToSchema) 339 | { 340 | if (item.Annotation != null) 341 | { 342 | AppendAnnotated(item, appendToSchema); 343 | } 344 | 345 | if (item.BaseSchemaType != null) 346 | { 347 | throw new NotImplementedException(); 348 | } 349 | 350 | if (item.BaseXmlSchemaType != null) 351 | { 352 | throw new NotImplementedException(); 353 | } 354 | 355 | if (item.Content != null) 356 | { 357 | XmlSchemaSimpleTypeContent simpleTypeContent = item.Content; 358 | if (simpleTypeContent is XmlSchemaSimpleTypeRestriction) 359 | { 360 | XmlSchemaSimpleTypeRestriction simpleTypeRestriction = (XmlSchemaSimpleTypeRestriction)simpleTypeContent; 361 | 362 | if (simpleTypeRestriction.Facets != null && simpleTypeRestriction.Facets.Count > 0) 363 | { 364 | List enumList = new List(); 365 | 366 | foreach (XmlSchemaFacet facet in simpleTypeRestriction.Facets) 367 | { 368 | if (facet is XmlSchemaEnumerationFacet) 369 | { 370 | enumList.Add(new JsonValue(facet.Value)); 371 | } 372 | else if (facet is XmlSchemaMinInclusiveFacet) 373 | { 374 | try 375 | { 376 | SetMinimum(appendToSchema, Convert.ToDouble(facet.Value, CultureInfo.InvariantCulture)); 377 | } 378 | catch (Exception) 379 | { 380 | LogError("Minimum: Could not convert " + facet.Value + " to number"); 381 | } 382 | } 383 | else if (facet is XmlSchemaMaxInclusiveFacet) 384 | { 385 | try 386 | { 387 | SetMaximum(appendToSchema, Convert.ToDouble(facet.Value, CultureInfo.InvariantCulture)); 388 | } 389 | catch (Exception) 390 | { 391 | LogError("Maximum: Could not convert " + facet.Value + " to number"); 392 | } 393 | } 394 | else if (facet is XmlSchemaMinLengthFacet) 395 | { 396 | try 397 | { 398 | appendToSchema.MinLength(Convert.ToUInt32(facet.Value, CultureInfo.InvariantCulture)); 399 | } 400 | catch (Exception) 401 | { 402 | LogError("MinLength: Could not convert " + facet.Value + " to number"); 403 | } 404 | } 405 | else if (facet is XmlSchemaMaxLengthFacet) 406 | { 407 | try 408 | { 409 | appendToSchema.MaxLength(Convert.ToUInt32(facet.Value, CultureInfo.InvariantCulture)); 410 | } 411 | catch (Exception) 412 | { 413 | LogError("MaxLength: Could not convert " + facet.Value + " to number"); 414 | } 415 | } 416 | else if (facet is XmlSchemaLengthFacet) 417 | { 418 | try 419 | { 420 | appendToSchema.MinLength(Convert.ToUInt32(facet.Value, CultureInfo.InvariantCulture)); 421 | } 422 | catch (Exception) 423 | { 424 | LogError("MinLength: Could not convert " + facet.Value + " to number"); 425 | } 426 | 427 | try 428 | { 429 | appendToSchema.MaxLength(Convert.ToUInt32(facet.Value, CultureInfo.InvariantCulture)); 430 | } 431 | catch (Exception) 432 | { 433 | LogError("MaxLength: Could not convert " + facet.Value + " to number"); 434 | } 435 | } 436 | else if (facet is XmlSchemaPatternFacet) 437 | { 438 | appendToSchema.Pattern(facet.Value); 439 | } 440 | else if (facet is XmlSchemaTotalDigitsFacet) 441 | { 442 | try 443 | { 444 | uint digits = Convert.ToUInt32(facet.Value, CultureInfo.InvariantCulture); 445 | long maxValue = 0; 446 | for (int i = 0; i < digits; i++) 447 | { 448 | maxValue = (maxValue * 10) + 9; 449 | } 450 | 451 | SetMinimum(appendToSchema, -maxValue); 452 | SetMaximum(appendToSchema, maxValue); 453 | } 454 | catch (Exception) 455 | { 456 | LogError("totalDigits: Could not convert " + facet.Value + " to number"); 457 | } 458 | } 459 | else if (facet is XmlSchemaFractionDigitsFacet) 460 | { 461 | // Use pattern? 462 | } 463 | else if (facet is XmlSchemaMinExclusiveFacet) 464 | { 465 | try 466 | { 467 | appendToSchema.ExclusiveMinimum(Convert.ToDouble(facet.Value, CultureInfo.InvariantCulture)); 468 | } 469 | catch (Exception) 470 | { 471 | LogError("ExclusiveMinimum: Could not convert " + facet.Value + " to number"); 472 | } 473 | } 474 | else if (facet is XmlSchemaMaxExclusiveFacet) 475 | { 476 | try 477 | { 478 | appendToSchema.ExclusiveMaximum(Convert.ToDouble(facet.Value, CultureInfo.InvariantCulture)); 479 | } 480 | catch (Exception) 481 | { 482 | LogError("ExclusiveMaximum: Could not convert " + facet.Value + " to number"); 483 | } 484 | } 485 | else 486 | { 487 | throw new NotImplementedException(); 488 | } 489 | } 490 | 491 | if (enumList.Count > 0) 492 | { 493 | appendToSchema.Enum(enumList.ToArray()); 494 | } 495 | } 496 | 497 | AppendTypeFromSchemaTypeInternal(simpleTypeRestriction.BaseType, simpleTypeRestriction.BaseTypeName, appendToSchema); 498 | } 499 | else if (simpleTypeContent is XmlSchemaSimpleTypeList) 500 | { 501 | XmlSchemaSimpleTypeList simpleTypeListItem = (XmlSchemaSimpleTypeList)simpleTypeContent; 502 | 503 | if (simpleTypeListItem.ItemType != null) 504 | { 505 | XmlQualifiedName simpleTypeName = GetItemName(simpleTypeListItem.ItemType); 506 | JsonSchema simpleTypeSchema = new JsonSchema(); 507 | AppendSimpleType((XmlSchemaSimpleType)simpleTypeListItem.ItemType, simpleTypeSchema); 508 | } 509 | else if (!simpleTypeListItem.ItemTypeName.IsEmpty) 510 | { 511 | appendToSchema.Type(JsonSchemaType.Array); 512 | appendToSchema.OtherData.Add("@xsdType", new JsonValue("XmlList")); 513 | 514 | JsonSchema[] itemsSchemas = new JsonSchema[1]; 515 | itemsSchemas[0] = new JsonSchema(); 516 | 517 | AppendTypeFromSchemaTypeInternal(simpleTypeListItem.ItemType, simpleTypeListItem.ItemTypeName, itemsSchemas[0]); 518 | appendToSchema.Items(itemsSchemas); 519 | } 520 | else 521 | { 522 | throw new ArgumentException(); 523 | } 524 | } 525 | else 526 | { 527 | throw new NotImplementedException(); 528 | } 529 | } 530 | 531 | if (item.Datatype != null) 532 | { 533 | throw new NotImplementedException(); 534 | } 535 | } 536 | 537 | private JsonSchema ParseAttribute(XmlSchemaAttribute attribute, out bool isRequired) 538 | { 539 | isRequired = false; 540 | JsonSchema attributeSchema = new JsonSchema(); 541 | 542 | if (attribute != null && !attribute.RefName.IsEmpty) 543 | { 544 | XmlSchemaObject refAttribute = FindObject(attribute.RefName); 545 | if (refAttribute == null) 546 | { 547 | AppendTypeFromNameInternal(null, attributeSchema); // Unknown type. (Will default to string) 548 | } 549 | else if (refAttribute is XmlSchemaAttribute) 550 | { 551 | attributeSchema = ParseAttribute((XmlSchemaAttribute)refAttribute, out isRequired); 552 | } 553 | else 554 | { 555 | throw new ArgumentException(); 556 | } 557 | } 558 | 559 | TagType(attributeSchema, "XmlAttribute"); 560 | 561 | if (attribute.Annotation != null) 562 | { 563 | AppendAnnotated(attribute, attributeSchema); 564 | } 565 | 566 | if (attribute.AttributeSchemaType != null) 567 | { 568 | throw new NotImplementedException(); 569 | } 570 | 571 | if (attribute.AttributeType != null) 572 | { 573 | throw new NotImplementedException(); 574 | } 575 | 576 | if (attribute.FixedValue != null) 577 | { 578 | SetConst(attributeSchema, new JsonValue(attribute.FixedValue)); 579 | } 580 | 581 | if (!attribute.QualifiedName.IsEmpty) 582 | { 583 | throw new NotImplementedException(); 584 | } 585 | 586 | if (attribute.SchemaType != null) 587 | { 588 | AppendSimpleType(attribute.SchemaType, attributeSchema); 589 | } 590 | 591 | if (!attribute.SchemaTypeName.IsEmpty) 592 | { 593 | AppendTypeFromNameInternal(attribute.SchemaTypeName, attributeSchema); 594 | } 595 | 596 | isRequired = attribute.Use == XmlSchemaUse.Required; 597 | 598 | return attributeSchema; 599 | } 600 | 601 | private JsonSchema ParseAny(XmlSchemaAny item, out bool isRequired) 602 | { 603 | isRequired = false; 604 | 605 | JsonSchema anySchema = new JsonSchema(); 606 | anySchema.OtherData.Add("@xsdType", new JsonValue("XmlAny")); 607 | 608 | if (item.Annotation != null) 609 | { 610 | AppendAnnotated(item, anySchema); 611 | } 612 | 613 | if (item.MinOccurs >= 1 || 614 | (item.MinOccursString != null && Convert.ToUInt32(item.MinOccursString, CultureInfo.InvariantCulture) >= 1)) 615 | { 616 | isRequired = true; 617 | } 618 | 619 | if (item.MaxOccursString != null) 620 | { 621 | // This is handled when appending type info 622 | } 623 | 624 | AppendType(item, anySchema); 625 | 626 | return anySchema; 627 | } 628 | 629 | private JsonSchema ParseParticle(XmlSchemaParticle item, out bool isRequired) 630 | { 631 | JsonSchema particleSchema = new JsonSchema(); 632 | 633 | isRequired = false; 634 | 635 | if (item is XmlSchemaElement) 636 | { 637 | return ParseElement((XmlSchemaElement)item, out isRequired); 638 | } 639 | else if (item is XmlSchemaChoice) 640 | { 641 | throw new NotImplementedException(); 642 | /* 643 | List oneOfSchemaList = new List(); 644 | foreach (XmlSchemaObject choiceItem in ((XmlSchemaChoice)item).Items) 645 | { 646 | JsonSchema oneOfSchema = new JsonSchema(); 647 | AddType(choiceItem, oneOfSchema); 648 | oneOfSchemaList.Add(oneOfSchema); 649 | } 650 | 651 | resultSchema.OneOf(oneOfSchemaList.ToArray()); 652 | */ 653 | } 654 | else if (item is XmlSchemaGroupRef) 655 | { 656 | throw new NotImplementedException(); 657 | 658 | // ExpandAndCopyGroupRef((XmlSchemaGroupRef)item, resultSchema, requiredList); 659 | } 660 | else 661 | { 662 | throw new NotImplementedException(); 663 | } 664 | } 665 | 666 | private void AppendParticle(XmlSchemaParticle particle, JsonSchema appendToSchema, List requiredList) 667 | { 668 | if (particle == null) 669 | { 670 | } 671 | else if (particle is XmlSchemaSequence) 672 | { 673 | foreach (XmlSchemaParticle item in ((XmlSchemaSequence)particle).Items) 674 | { 675 | AppendParticleProperty(item, appendToSchema, requiredList); 676 | } 677 | } 678 | else if (particle is XmlSchemaGroupRef) 679 | { 680 | ExpandAndAppendGroupRef((XmlSchemaGroupRef)particle, appendToSchema, requiredList); 681 | } 682 | else 683 | { 684 | throw new NotImplementedException(); 685 | } 686 | } 687 | 688 | private void AppendParticleProperty(XmlSchemaParticle item, JsonSchema appendToSchema, List requiredList) 689 | { 690 | if (item is XmlSchemaElement) 691 | { 692 | XmlQualifiedName elementName = GetItemName(item); 693 | bool isRequired; 694 | JsonSchema elementSchema = ParseElement((XmlSchemaElement)item, out isRequired); 695 | appendToSchema.Property(elementName.Name, elementSchema); 696 | 697 | if (isRequired) 698 | { 699 | requiredList.Add(elementName); 700 | } 701 | } 702 | else if (item is XmlSchemaChoice) 703 | { 704 | List oneOfSchemaList = new List(); 705 | foreach (XmlSchemaObject choiceItem in ((XmlSchemaChoice)item).Items) 706 | { 707 | JsonSchema choiceSchema = new JsonSchema(); 708 | XmlQualifiedName itemQName = GetItemName(choiceItem); 709 | JsonSchema refSchema = new JsonSchema(); 710 | 711 | if (choiceItem is XmlSchemaSequence) 712 | { 713 | // special case handling SKD ... 1) 928 | { 929 | appendToSchema.Type(JsonSchemaType.Array); 930 | decimal minOccurs = referencedFromItem is XmlSchemaParticle ? ((XmlSchemaParticle)referencedFromItem).MinOccurs : elementItem.MinOccurs; 931 | string maxOccursString = referencedFromItem is XmlSchemaParticle ? ((XmlSchemaParticle)referencedFromItem).MaxOccursString : elementItem.MaxOccursString; 932 | appendToSchema.MinItems(Convert.ToUInt32(minOccurs, CultureInfo.InvariantCulture)); 933 | if (!"unbounded".Equals(maxOccursString)) 934 | { 935 | appendToSchema.MaxItems(Convert.ToUInt32(maxOccurs, CultureInfo.InvariantCulture)); 936 | } 937 | 938 | JsonSchema[] itemsSchemas = new JsonSchema[1]; 939 | itemsSchemas[0] = new JsonSchema(); 940 | 941 | AppendTypeFromSchemaTypeInternal(elementItem.SchemaType, elementItem.SchemaTypeName, itemsSchemas[0]); 942 | appendToSchema.Items(itemsSchemas); 943 | } 944 | else 945 | { 946 | AppendTypeFromSchemaTypeInternal(elementItem.SchemaType, elementItem.SchemaTypeName, appendToSchema); 947 | } 948 | } 949 | else if (item is XmlSchemaType) 950 | { 951 | throw new NotImplementedException(); 952 | 953 | // AddDefinition(resultSchema, ObjectName(item), GenerateSchemaType((XmlSchemaType)item)); 954 | /* 955 | XmlSchemaType itemSchemaType = (XmlSchemaType)item; 956 | if (itemSchemaType.BaseSchemaType != null) 957 | { 958 | throw new NotImplementedException(); 959 | 960 | // AddTypeFromSchemaTypeInternal(itemSchemaType.BaseSchemaType, qname, elementName, resultSchema); 961 | } 962 | else 963 | { 964 | throw new NotImplementedException(); 965 | } 966 | */ 967 | } 968 | else if (item is XmlSchemaSimpleTypeRestriction) 969 | { 970 | XmlSchemaSimpleTypeRestriction simpleTypeRestriction = (XmlSchemaSimpleTypeRestriction)item; 971 | AppendTypeFromSchemaTypeInternal(simpleTypeRestriction.BaseType, simpleTypeRestriction.BaseTypeName, appendToSchema); 972 | } 973 | else if (item is XmlSchemaSequence) 974 | { 975 | List requiredList = new List(); 976 | AppendParticle((XmlSchemaSequence)item, appendToSchema, requiredList); 977 | 978 | if (requiredList.Count > 0) 979 | { 980 | appendToSchema.Required(RequiredListToArray(requiredList)); 981 | } 982 | } 983 | else if (item is XmlSchemaAny) 984 | { 985 | XmlSchemaAny anyItem = (XmlSchemaAny)item; 986 | decimal maxOccurs = referencedFromItem is XmlSchemaParticle ? ((XmlSchemaParticle)referencedFromItem).MaxOccurs : anyItem.MaxOccurs; 987 | if (maxOccurs > 1) 988 | { 989 | appendToSchema.Type(JsonSchemaType.Array); 990 | decimal minOccurs = referencedFromItem is XmlSchemaParticle ? ((XmlSchemaParticle)referencedFromItem).MinOccurs : anyItem.MinOccurs; 991 | string maxOccursString = referencedFromItem is XmlSchemaParticle ? ((XmlSchemaParticle)referencedFromItem).MaxOccursString : anyItem.MaxOccursString; 992 | appendToSchema.MinItems(Convert.ToUInt32(minOccurs, CultureInfo.InvariantCulture)); 993 | if (!"unbounded".Equals(maxOccursString)) 994 | { 995 | appendToSchema.MaxItems(Convert.ToUInt32(maxOccurs, CultureInfo.InvariantCulture)); 996 | } 997 | 998 | JsonSchema[] itemsSchemas = new JsonSchema[1]; 999 | itemsSchemas[0] = new JsonSchema(); 1000 | 1001 | AppendTypeFromSchemaTypeInternal(null, XmlQualifiedName.Empty, itemsSchemas[0]); 1002 | appendToSchema.Items(itemsSchemas); 1003 | } 1004 | else 1005 | { 1006 | AppendTypeFromSchemaTypeInternal(null, XmlQualifiedName.Empty, appendToSchema); 1007 | } 1008 | } 1009 | else 1010 | { 1011 | throw new NotImplementedException(); 1012 | } 1013 | } 1014 | 1015 | private bool HasDefinition(XmlQualifiedName name) 1016 | { 1017 | return mainJsonSchema.Definitions() != null && mainJsonSchema.Definitions().ContainsKey(name.Name); 1018 | } 1019 | 1020 | private void AddDefinition(XmlSchemaObject item, JsonSchema definition) 1021 | { 1022 | XmlQualifiedName name = GetItemName(item); 1023 | if (!HasDefinition(name)) 1024 | { 1025 | mainJsonSchema.Definition(name.Name, definition); 1026 | } 1027 | else 1028 | { 1029 | throw new XmlSchemaException(); 1030 | } 1031 | } 1032 | 1033 | private void AppendDefinition(JsonSchema appendToSchema, XmlSchemaObject item, JsonSchema definitionSchema) 1034 | { 1035 | if (appendToSchema == mainJsonSchema) 1036 | { 1037 | AddDefinition(item, definitionSchema); 1038 | } 1039 | else 1040 | { 1041 | AddTypeObject(appendToSchema); 1042 | appendToSchema.Property(GetItemName(item).Name, definitionSchema); 1043 | } 1044 | } 1045 | 1046 | private void ExpandAndAppendGroupRef(XmlSchemaGroupRef groupRefItem, JsonSchema appendToSchema, List requiredList) 1047 | { 1048 | XmlSchemaObject groupObject = FindObject(groupRefItem.RefName); 1049 | if (groupObject != null) 1050 | { 1051 | if (groupObject is XmlSchemaGroup) 1052 | { 1053 | AppendParticle(((XmlSchemaGroup)groupObject).Particle, appendToSchema, requiredList); 1054 | } 1055 | else 1056 | { 1057 | throw new NotImplementedException(); 1058 | } 1059 | } 1060 | } 1061 | 1062 | private void ExpandAndAppendAttributeGroupRef(XmlSchemaAttributeGroupRef groupRefItem, JsonSchema appendToSchema, List requiredList) 1063 | { 1064 | XmlSchemaObject refItem = FindObject(groupRefItem.RefName); 1065 | if (refItem != null) 1066 | { 1067 | if (refItem is XmlSchemaAttributeGroup) 1068 | { 1069 | XmlSchemaAttributeGroup attributeGroup = (XmlSchemaAttributeGroup)refItem; 1070 | 1071 | if (attributeGroup.Annotation != null) 1072 | { 1073 | AppendAnnotated(attributeGroup, appendToSchema); 1074 | } 1075 | 1076 | if (attributeGroup.AnyAttribute != null) 1077 | { 1078 | TagAnyAttribute(appendToSchema); 1079 | } 1080 | 1081 | if (attributeGroup.Attributes.Count > 0) 1082 | { 1083 | AppendAttributes(attributeGroup.Attributes, appendToSchema, requiredList); 1084 | } 1085 | 1086 | if (attributeGroup.RedefinedAttributeGroup != null) 1087 | { 1088 | throw new NotImplementedException(); 1089 | } 1090 | } 1091 | else 1092 | { 1093 | throw new NotImplementedException(); 1094 | } 1095 | } 1096 | } 1097 | 1098 | private void AppendComplexContent(XmlSchemaComplexContent item, JsonSchema appendToSchema, List requiredList) 1099 | { 1100 | if (item.Annotation != null) 1101 | { 1102 | AppendAnnotated(item, appendToSchema); 1103 | } 1104 | 1105 | if (item.Content != null) 1106 | { 1107 | AppendContent(item.Content, appendToSchema, requiredList); 1108 | } 1109 | } 1110 | 1111 | private void AppendSimpleContent(XmlSchemaSimpleContent item, JsonSchema appendToSchema, List requiredList) 1112 | { 1113 | if (item.Annotation != null) 1114 | { 1115 | AppendAnnotated(item, appendToSchema); 1116 | } 1117 | 1118 | if (item.Content != null) 1119 | { 1120 | AppendContent(item.Content, appendToSchema, requiredList); 1121 | } 1122 | } 1123 | 1124 | private void AppendAttributes(XmlSchemaObjectCollection attributes, JsonSchema appendToSchema, List requiredList) 1125 | { 1126 | foreach (XmlSchemaObject attribute in attributes) 1127 | { 1128 | if (attribute is XmlSchemaAttribute) 1129 | { 1130 | XmlSchemaAttribute schemaAttribute = (XmlSchemaAttribute)attribute; 1131 | bool isRequired; 1132 | JsonSchema attributeSchema = ParseAttribute(schemaAttribute, out isRequired); 1133 | if (attributeSchema != null) 1134 | { 1135 | XmlQualifiedName name = GetItemName(schemaAttribute); 1136 | appendToSchema.Property(name.Name, attributeSchema); 1137 | if (isRequired) 1138 | { 1139 | requiredList.Add(name); 1140 | } 1141 | } 1142 | } 1143 | else if (attribute is XmlSchemaAttributeGroupRef) 1144 | { 1145 | ExpandAndAppendAttributeGroupRef((XmlSchemaAttributeGroupRef)attribute, appendToSchema, requiredList); 1146 | } 1147 | else 1148 | { 1149 | throw new NotImplementedException(); 1150 | } 1151 | } 1152 | } 1153 | 1154 | private void AppendValueAttribute(XmlSchemaObject item, JsonSchema appendToSchema, List requiredList) 1155 | { 1156 | if (item is XmlSchemaSimpleContentExtension) 1157 | { 1158 | XmlSchemaSimpleContentExtension simpleContentExtension = (XmlSchemaSimpleContentExtension)item; 1159 | if (!simpleContentExtension.BaseTypeName.IsEmpty) 1160 | { 1161 | JsonSchema valueAttributeSchema = new JsonSchema(); 1162 | AppendTypeFromNameInternal(simpleContentExtension.BaseTypeName, valueAttributeSchema); 1163 | TagType(valueAttributeSchema, "XmlSimpleContentExtension"); 1164 | appendToSchema.Property("value", valueAttributeSchema); 1165 | requiredList.Add(new XmlQualifiedName("value", mainXsd.TargetNamespace)); 1166 | } 1167 | } 1168 | else 1169 | { 1170 | throw new NotImplementedException(); 1171 | } 1172 | } 1173 | 1174 | private void AppendContent(XmlSchemaContent item, JsonSchema appendToSchema, List requiredList) 1175 | { 1176 | if (item is XmlSchemaSimpleContentExtension) 1177 | { 1178 | XmlSchemaSimpleContentExtension contentExtensionItem = (XmlSchemaSimpleContentExtension)item; 1179 | if (contentExtensionItem.Annotation != null) 1180 | { 1181 | AppendAnnotated(item, appendToSchema); 1182 | } 1183 | 1184 | if (contentExtensionItem.Attributes.Count > 0) 1185 | { 1186 | AppendAttributes(contentExtensionItem.Attributes, appendToSchema, requiredList); 1187 | AppendValueAttribute(contentExtensionItem, appendToSchema, requiredList); 1188 | } 1189 | else if (!contentExtensionItem.BaseTypeName.IsEmpty) 1190 | { 1191 | AppendTypeFromNameInternal(contentExtensionItem.BaseTypeName, appendToSchema); 1192 | } 1193 | } 1194 | else if (item is XmlSchemaComplexContentExtension) 1195 | { 1196 | XmlSchemaComplexContentExtension contentExtensionItem = (XmlSchemaComplexContentExtension)item; 1197 | 1198 | bool isInherit = !contentExtensionItem.BaseTypeName.IsEmpty; 1199 | List allOfList = new List(); 1200 | JsonSchema definitionSchema = new JsonSchema(); 1201 | 1202 | if (contentExtensionItem.Annotation != null) 1203 | { 1204 | AppendAnnotated(item, appendToSchema); 1205 | } 1206 | 1207 | if (contentExtensionItem.Attributes.Count > 0) 1208 | { 1209 | foreach (XmlSchemaAttribute attribute in contentExtensionItem.Attributes) 1210 | { 1211 | bool isRequired; 1212 | JsonSchema attributeSchema = ParseAttribute(attribute, out isRequired); 1213 | if (attributeSchema != null) 1214 | { 1215 | XmlQualifiedName name = GetItemName(attribute); 1216 | appendToSchema.Property(name.Name, attributeSchema); 1217 | if (isRequired) 1218 | { 1219 | requiredList.Add(name); 1220 | } 1221 | } 1222 | } 1223 | } 1224 | 1225 | if (!contentExtensionItem.BaseTypeName.IsEmpty) 1226 | { 1227 | JsonSchema inheritFromSchema = new JsonSchema(); 1228 | AppendTypeFromNameInternal(contentExtensionItem.BaseTypeName, inheritFromSchema); 1229 | allOfList.Add(inheritFromSchema); 1230 | } 1231 | 1232 | if (contentExtensionItem.Particle != null) 1233 | { 1234 | JsonSchema usingSchema = isInherit ? new JsonSchema() : definitionSchema; 1235 | List particleRequiredList = new List(); 1236 | 1237 | AppendParticle(contentExtensionItem.Particle, usingSchema, particleRequiredList); 1238 | 1239 | if (particleRequiredList.Count > 0) 1240 | { 1241 | usingSchema.Required(RequiredListToArray(particleRequiredList)); 1242 | } 1243 | 1244 | if (isInherit) 1245 | { 1246 | allOfList.Add(usingSchema); 1247 | } 1248 | } 1249 | 1250 | if (allOfList.Count > 0) 1251 | { 1252 | AddTypeObject(appendToSchema); 1253 | appendToSchema.AllOf(allOfList.ToArray()); 1254 | } 1255 | 1256 | if (definitionSchema.Count > 0) 1257 | { 1258 | AppendDefinition(appendToSchema, contentExtensionItem, definitionSchema); 1259 | } 1260 | } 1261 | else if (item is XmlSchemaSimpleContentRestriction) 1262 | { 1263 | XmlSchemaSimpleContentRestriction contentRestrictionItem = (XmlSchemaSimpleContentRestriction)item; 1264 | 1265 | bool isInherit = !contentRestrictionItem.BaseTypeName.IsEmpty; 1266 | List allOfList = new List(); 1267 | 1268 | if (contentRestrictionItem.BaseType != null) 1269 | { 1270 | throw new NotImplementedException(); 1271 | } 1272 | 1273 | if (!contentRestrictionItem.BaseTypeName.IsEmpty) 1274 | { 1275 | JsonSchema inheritFromSchema = new JsonSchema(); 1276 | AppendTypeFromNameInternal(contentRestrictionItem.BaseTypeName, inheritFromSchema); 1277 | allOfList.Add(inheritFromSchema); 1278 | } 1279 | 1280 | if (contentRestrictionItem.Annotation != null) 1281 | { 1282 | AppendAnnotated(item, appendToSchema); 1283 | } 1284 | 1285 | if (contentRestrictionItem.AnyAttribute != null) 1286 | { 1287 | TagAnyAttribute(appendToSchema); 1288 | } 1289 | 1290 | if (contentRestrictionItem.Attributes.Count > 0) 1291 | { 1292 | JsonSchema usingSchema = isInherit ? new JsonSchema() : appendToSchema; 1293 | List usingRequiredList = isInherit ? new List() : requiredList; 1294 | 1295 | AppendAttributes(contentRestrictionItem.Attributes, usingSchema, usingRequiredList); 1296 | 1297 | if (isInherit) 1298 | { 1299 | if (usingRequiredList.Count > 0) 1300 | { 1301 | usingSchema.Required(RequiredListToArray(usingRequiredList)); 1302 | } 1303 | 1304 | allOfList.Add(usingSchema); 1305 | } 1306 | } 1307 | 1308 | if (contentRestrictionItem.Facets.Count > 0) 1309 | { 1310 | throw new NotImplementedException(); 1311 | } 1312 | 1313 | if (allOfList.Count > 0) 1314 | { 1315 | AddTypeObject(appendToSchema); 1316 | appendToSchema.AllOf(allOfList.ToArray()); 1317 | } 1318 | } 1319 | else if (item is XmlSchemaComplexContentRestriction) 1320 | { 1321 | throw new NotImplementedException(); 1322 | } 1323 | else 1324 | { 1325 | throw new NotImplementedException(); 1326 | } 1327 | } 1328 | 1329 | private void AddTypeObject(JsonSchema appendToSchema) 1330 | { 1331 | if (!appendToSchema.Exists(e => "type".Equals(e.Name))) 1332 | { 1333 | appendToSchema.Type(JsonSchemaType.Object); 1334 | } 1335 | } 1336 | 1337 | private void SetMinimum(JsonSchema appendToSchema, double value) 1338 | { 1339 | IJsonSchemaKeyword existingItem = appendToSchema.Find(e => "minimum".Equals(e.Name)); 1340 | if (existingItem is MinimumKeyword) 1341 | { 1342 | value = Math.Max(value, ((MinimumKeyword)existingItem).Value); 1343 | appendToSchema.RemoveAll(e => "minimum".Equals(e.Name)); 1344 | } 1345 | 1346 | appendToSchema.Minimum(value); 1347 | } 1348 | 1349 | private void SetMaximum(JsonSchema appendToSchema, double value) 1350 | { 1351 | IJsonSchemaKeyword existingItem = appendToSchema.Find(e => "maximum".Equals(e.Name)); 1352 | if (existingItem is MaximumKeyword) 1353 | { 1354 | value = Math.Min(value, ((MaximumKeyword)existingItem).Value); 1355 | appendToSchema.RemoveAll(e => "maximum".Equals(e.Name)); 1356 | } 1357 | 1358 | appendToSchema.Maximum(value); 1359 | } 1360 | 1361 | private void TagType(JsonSchema appendToSchema, string value) 1362 | { 1363 | Tag(appendToSchema, "@xsdType", value); 1364 | } 1365 | 1366 | private void TagAnyAttribute(JsonSchema appendToSchema) 1367 | { 1368 | Tag(appendToSchema, "@xsdAnyAttribute", true); 1369 | } 1370 | 1371 | private void Tag(JsonSchema appendToSchema, string type, object value) 1372 | { 1373 | appendToSchema.OtherData.Remove(type); 1374 | 1375 | if (value is string) 1376 | { 1377 | appendToSchema.OtherData.Add(type, new JsonValue((string)value)); 1378 | } 1379 | else if (value is bool) 1380 | { 1381 | appendToSchema.OtherData.Add(type, new JsonValue((bool)value)); 1382 | } 1383 | else 1384 | { 1385 | throw new NotImplementedException(); 1386 | } 1387 | } 1388 | 1389 | private void SetConst(JsonSchema appendToSchema, JsonValue value) 1390 | { 1391 | appendToSchema.RemoveAll(e => "const".Equals(e.Name)); 1392 | appendToSchema.Const(value); 1393 | } 1394 | 1395 | private XmlSchemaObject FindObject(XmlQualifiedName name) 1396 | { 1397 | XmlSchemaObjectEnumerator enumerator = mainXsd.Items.GetEnumerator(); 1398 | while (enumerator.MoveNext()) 1399 | { 1400 | XmlSchemaObject xmlSchemaObject = enumerator.Current; 1401 | 1402 | XmlQualifiedName objectName = XmlQualifiedName.Empty; 1403 | if (xmlSchemaObject is XmlSchemaGroup) 1404 | { 1405 | XmlSchemaGroup groupItem = (XmlSchemaGroup)xmlSchemaObject; 1406 | objectName = QualifiedNameOrName(groupItem.QualifiedName, groupItem.Name, groupItem); 1407 | } 1408 | else if (xmlSchemaObject is XmlSchemaElement) 1409 | { 1410 | XmlSchemaElement elementItem = (XmlSchemaElement)xmlSchemaObject; 1411 | objectName = QualifiedNameOrName(elementItem.QualifiedName, elementItem.Name, elementItem); 1412 | } 1413 | else if (xmlSchemaObject is XmlSchemaType) 1414 | { 1415 | XmlSchemaType typeItem = (XmlSchemaType)xmlSchemaObject; 1416 | objectName = QualifiedNameOrName(typeItem.QualifiedName, typeItem.Name, typeItem); 1417 | } 1418 | else if (xmlSchemaObject is XmlSchemaAttribute) 1419 | { 1420 | XmlSchemaAttribute attributeItem = (XmlSchemaAttribute)xmlSchemaObject; 1421 | objectName = QualifiedNameOrName(attributeItem.QualifiedName, attributeItem.Name, attributeItem); 1422 | } 1423 | else if (xmlSchemaObject is XmlSchemaAttributeGroup) 1424 | { 1425 | XmlSchemaAttributeGroup groupItem = (XmlSchemaAttributeGroup)xmlSchemaObject; 1426 | objectName = QualifiedNameOrName(groupItem.QualifiedName, groupItem.Name, groupItem); 1427 | } 1428 | else if (xmlSchemaObject is XmlSchemaAnnotation) 1429 | { 1430 | // No name 1431 | } 1432 | else 1433 | { 1434 | throw new NotImplementedException(); 1435 | } 1436 | 1437 | if (name == objectName) 1438 | { 1439 | return xmlSchemaObject; 1440 | } 1441 | } 1442 | 1443 | LogInfo("FindObject: Couldn't find \"" + name.ToString() + "\""); 1444 | return null; 1445 | } 1446 | 1447 | private string GetNamespaceForItem(XmlSchemaObject item) 1448 | { 1449 | if (item == null) 1450 | { 1451 | return null; 1452 | } 1453 | 1454 | if (itemNames.ContainsKey(item)) 1455 | { 1456 | return itemNames[item].Namespace; 1457 | } 1458 | 1459 | XmlQualifiedName xmlQualifiedName = XmlQualifiedName.Empty; 1460 | 1461 | if (item is XmlSchemaElement) 1462 | { 1463 | xmlQualifiedName = ((XmlSchemaElement)item).QualifiedName; 1464 | } 1465 | else if (item is XmlSchemaAttribute) 1466 | { 1467 | xmlQualifiedName = ((XmlSchemaAttribute)item).QualifiedName; 1468 | } 1469 | else if (item is XmlSchemaType) 1470 | { 1471 | xmlQualifiedName = ((XmlSchemaType)item).QualifiedName; 1472 | } 1473 | else if (item is XmlSchemaGroup) 1474 | { 1475 | xmlQualifiedName = ((XmlSchemaGroup)item).QualifiedName; 1476 | } 1477 | 1478 | if (!xmlQualifiedName.IsEmpty) 1479 | { 1480 | return xmlQualifiedName.Namespace; 1481 | } 1482 | else if (item.Parent != mainXsd) 1483 | { 1484 | return GetNamespaceForItem(item.Parent); 1485 | } 1486 | else 1487 | { 1488 | return mainXsd.TargetNamespace; 1489 | } 1490 | } 1491 | 1492 | private XmlQualifiedName QualifiedNameOrName(XmlQualifiedName qualifiedName, string name, XmlSchemaObject item) 1493 | { 1494 | if (!qualifiedName.IsEmpty) 1495 | { 1496 | return qualifiedName; 1497 | } 1498 | else if (name != null) 1499 | { 1500 | return new XmlQualifiedName(name, GetNamespaceForItem(item)); 1501 | } 1502 | else 1503 | { 1504 | return XmlQualifiedName.Empty; 1505 | } 1506 | } 1507 | 1508 | private XmlQualifiedName GetItemName(XmlSchemaObject item) 1509 | { 1510 | if (item == null) 1511 | { 1512 | return XmlQualifiedName.Empty; 1513 | } 1514 | 1515 | if (itemNames.ContainsKey(item)) 1516 | { 1517 | return itemNames[item]; 1518 | } 1519 | 1520 | if (item is XmlSchemaElement) 1521 | { 1522 | XmlSchemaElement elementItem = (XmlSchemaElement)item; 1523 | XmlQualifiedName name = QualifiedNameOrName(elementItem.QualifiedName, elementItem.Name, elementItem); 1524 | if (name.IsEmpty && !elementItem.RefName.IsEmpty) 1525 | { 1526 | XmlSchemaObject refObject = FindObject(elementItem.RefName); 1527 | name = GetItemName(refObject); 1528 | } 1529 | 1530 | return RegisterItemName(item, name); 1531 | } 1532 | else if (item is XmlSchemaAttribute) 1533 | { 1534 | XmlSchemaAttribute attributeItem = (XmlSchemaAttribute)item; 1535 | XmlQualifiedName name = QualifiedNameOrName(attributeItem.QualifiedName, attributeItem.Name, attributeItem); 1536 | if (name.IsEmpty && !attributeItem.RefName.IsEmpty) 1537 | { 1538 | XmlSchemaObject refObject = FindObject(attributeItem.RefName); 1539 | if (refObject == null) 1540 | { 1541 | return attributeItem.RefName; 1542 | } 1543 | 1544 | name = GetItemName(refObject); 1545 | } 1546 | 1547 | return RegisterItemName(item, name); 1548 | } 1549 | else if (item is XmlSchemaType) 1550 | { 1551 | XmlSchemaType typeItem = (XmlSchemaType)item; 1552 | XmlQualifiedName name = QualifiedNameOrName(typeItem.QualifiedName, typeItem.Name, typeItem); 1553 | if (name.IsEmpty) 1554 | { 1555 | name = GetItemName(item.Parent); 1556 | 1557 | if (typeNames.Values.Contains(name)) 1558 | { 1559 | name = GenerateAnonymousTypeName((XmlSchemaType)item); 1560 | } 1561 | } 1562 | 1563 | return RegisterItemName(item, name); 1564 | } 1565 | else if (item is XmlSchemaGroup) 1566 | { 1567 | XmlSchemaGroup groupItem = (XmlSchemaGroup)item; 1568 | XmlQualifiedName name = QualifiedNameOrName(groupItem.QualifiedName, groupItem.Name, groupItem); 1569 | return RegisterItemName(item, name); 1570 | } 1571 | else if (item is XmlSchemaAttributeGroup) 1572 | { 1573 | XmlSchemaAttributeGroup attributeGroupItem = (XmlSchemaAttributeGroup)item; 1574 | XmlQualifiedName name = QualifiedNameOrName(attributeGroupItem.QualifiedName, attributeGroupItem.Name, attributeGroupItem); 1575 | return RegisterItemName(item, name); 1576 | } 1577 | else 1578 | { 1579 | return RegisterItemName(item, XmlQualifiedName.Empty); 1580 | } 1581 | } 1582 | 1583 | private XmlQualifiedName RegisterItemName(XmlSchemaObject item, XmlQualifiedName name) 1584 | { 1585 | if (item == null) 1586 | { 1587 | return null; 1588 | } 1589 | 1590 | if (name.IsEmpty) 1591 | { 1592 | name = GetItemName(item.Parent); 1593 | } 1594 | 1595 | if (name != null && !name.IsEmpty) 1596 | { 1597 | itemNames[item] = name; 1598 | 1599 | if (item is XmlSchemaType) 1600 | { 1601 | typeNames[item] = name; 1602 | } 1603 | } 1604 | 1605 | return name; 1606 | } 1607 | 1608 | private XmlQualifiedName GenerateAnonymousTypeName(XmlSchemaType item) 1609 | { 1610 | if (itemNames.ContainsKey(item)) 1611 | { 1612 | return itemNames[item]; 1613 | } 1614 | 1615 | XmlQualifiedName tmpName = QualifiedNameOrName(item.QualifiedName, item.Name, item); 1616 | if (tmpName.IsEmpty) 1617 | { 1618 | tmpName = GetItemName(item.Parent); 1619 | 1620 | if (tmpName.IsEmpty) 1621 | { 1622 | throw new XmlSchemaException(); 1623 | } 1624 | } 1625 | 1626 | XmlQualifiedName newName; 1627 | 1628 | // string typeNamePart = tmpName.Substring(0, 1).ToUpper() + tmpName.Substring(1); //Use this to force first letter uppercase 1629 | string typeNamePart = tmpName.Name; 1630 | 1631 | int i = 0; 1632 | while (true) 1633 | { 1634 | i++; 1635 | 1636 | string typeName = typeNamePart; 1637 | if (i > 1) 1638 | { 1639 | typeName += i.ToString(); 1640 | } 1641 | 1642 | // Is name unused? 1643 | newName = new XmlQualifiedName(typeName, tmpName.Namespace); 1644 | if (!itemNames.Values.Contains(newName) && 1645 | !HasDefinition(newName)) 1646 | { 1647 | break; 1648 | } 1649 | } 1650 | 1651 | return RegisterItemName(item, newName); 1652 | } 1653 | 1654 | private JsonSchemaType JsonSchemaTypeFromString(string type) 1655 | { 1656 | switch (type.ToLower()) 1657 | { 1658 | case "array": return JsonSchemaType.Array; 1659 | case "boolean": return JsonSchemaType.Boolean; 1660 | case "integer": return JsonSchemaType.Integer; 1661 | case "null": return JsonSchemaType.Null; 1662 | case "number": return JsonSchemaType.Number; 1663 | case "object": return JsonSchemaType.Object; 1664 | case "string": return JsonSchemaType.String; 1665 | default: return JsonSchemaType.NotDefined; 1666 | } 1667 | } 1668 | 1669 | private string[] RequiredListToArray(List requiredList) 1670 | { 1671 | List requiredArrayList = new List(); 1672 | foreach (XmlQualifiedName name in requiredList) 1673 | { 1674 | requiredArrayList.Add(name.Name); 1675 | } 1676 | 1677 | return requiredArrayList.ToArray(); 1678 | } 1679 | 1680 | private XmlAttribute GetAttribute(XmlAttributeCollection attributes, string name, string ns) 1681 | { 1682 | XmlAttribute bestMatch = null; 1683 | foreach (XmlAttribute attribute in attributes) 1684 | { 1685 | if (attribute.LocalName.Equals(name)) 1686 | { 1687 | if (attribute.NamespaceURI.Equals(ns)) 1688 | { 1689 | bestMatch = attribute; 1690 | } 1691 | else if (attribute.NamespaceURI == string.Empty && bestMatch == null) 1692 | { 1693 | bestMatch = attribute; 1694 | } 1695 | else 1696 | { 1697 | throw new NotImplementedException(); 1698 | } 1699 | } 1700 | } 1701 | 1702 | return bestMatch; 1703 | } 1704 | 1705 | private bool IsTopLevel(XmlSchemaObject item) 1706 | { 1707 | return item.Parent == mainXsd; 1708 | } 1709 | 1710 | private void LogInfo(string msg) 1711 | { 1712 | if (_logger != null) 1713 | { 1714 | _logger.LogInformation(msg); 1715 | } 1716 | 1717 | Trace.WriteLine("Info: " + msg); 1718 | } 1719 | 1720 | private void LogError(string msg) 1721 | { 1722 | if (_logger != null) 1723 | { 1724 | _logger.LogError(msg); 1725 | } 1726 | 1727 | Trace.WriteLine("Error: " + msg); 1728 | } 1729 | 1730 | private static void ValidationCallback(object sender, ValidationEventArgs args) 1731 | { 1732 | throw new NotImplementedException(); 1733 | } 1734 | 1735 | /// 1736 | /// Returns a sanitized name. It removes - in names since these are not allowed in C#. Hence, 1737 | /// Inntekt-grp-22384 will become Inntektgrp22384 1738 | /// 1739 | /// the name to sanitize 1740 | /// the santized name 1741 | public static string SanitizeName(string name) 1742 | { 1743 | return name.Replace("-", string.Empty); 1744 | } 1745 | } 1746 | } 1747 | --------------------------------------------------------------------------------