├── .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 |
--------------------------------------------------------------------------------