// Copyright (C) Stichting Deltares 2016. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // All names, logos, and references to "Deltares" are registered trademarks of // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Xml; using System.Xml.Schema; namespace Ringtoets.Common.IO.Readers { /// /// Container for one or more related/nested schema definitions, representing a combined /// XML Schema Definition (XSD). /// public class CombinedXmlSchemaDefinition { private readonly XmlSchemaSet xmlSchemaSet; /// /// Creates a new instance of . /// /// A string representing the main schema definition. /// A containing /// one or more nested schema definitions; the keys should represent unique file names by which /// the schema definitions can be referenced from , the /// values should represent the corresponding schema definition strings. /// Thrown when /// is null. /// Thrown when: /// /// is invalid. /// contains invalid schema definition values. /// , all together with its referenced /// , contains an invalid schema definition. /// contains schema definitions that are not /// referenced by . /// /// public CombinedXmlSchemaDefinition(string mainSchemaDefinition, IDictionary nestedSchemaDefinitions) { CheckSchemaDefinitions(mainSchemaDefinition, nestedSchemaDefinitions); var nestedSchemaDefinitionsResolver = new NestedSchemaDefinitionsResolver(nestedSchemaDefinitions); xmlSchemaSet = new XmlSchemaSet { XmlResolver = nestedSchemaDefinitionsResolver }; CompileSchemaSet(mainSchemaDefinition); if (!nestedSchemaDefinitionsResolver.AllNestedSchemaDefinitionsReferenced) { throw new ArgumentException($"'{nameof(nestedSchemaDefinitions)}' contains one or more schema definitions that are not referenced."); } } /// /// Check the provided schema definitions for not being null, empty or only containing white spaces. /// /// A string representing the main schema definition. /// A containing /// one or more nested schema definitions. /// Thrown when /// is null. /// Thrown when: /// /// is invalid. /// contains invalid schema definition values. /// /// private static void CheckSchemaDefinitions(string mainSchemaDefinition, IDictionary nestedSchemaDefinitions) { if (string.IsNullOrWhiteSpace(mainSchemaDefinition)) { throw new ArgumentException($"'{nameof(mainSchemaDefinition)}' null, empty or only containing white spaces."); } if (nestedSchemaDefinitions == null) { throw new ArgumentNullException(nameof(nestedSchemaDefinitions)); } if (nestedSchemaDefinitions.Values.Any(string.IsNullOrWhiteSpace)) { throw new ArgumentException($"'{nameof(nestedSchemaDefinitions)}' holds a nested schema definition value that equals null, is empty or only contains white spaces."); } } /// /// Compiles the based on the provided main schema definition string. /// /// A string representing the main schema definition. /// Thrown when , /// all together with its referenced nested schema definitions, contains an invalid schema /// definition. private void CompileSchemaSet(string mainSchemaDefinition) { try { xmlSchemaSet.Add(XmlSchema.Read(new StringReader(mainSchemaDefinition), null)); xmlSchemaSet.Compile(); } catch (Exception exception) when (exception is XmlException || exception is XmlSchemaException) { throw new ArgumentException($"'{nameof(mainSchemaDefinition)}' containing invalid schema definition: {exception.Message}", exception); } } /// /// Resolver for nested schema definitions. /// private class NestedSchemaDefinitionsResolver : XmlResolver { private readonly IDictionary nestedSchemaDefinitions; private readonly IDictionary nestedSchemaDefinitionsUsage; /// /// Creates a new instance of . /// /// A containing /// one or more nested schema definitions. public NestedSchemaDefinitionsResolver(IDictionary nestedSchemaDefinitions) { this.nestedSchemaDefinitions = nestedSchemaDefinitions; nestedSchemaDefinitionsUsage = nestedSchemaDefinitions.Keys.ToDictionary(k => k, k => false); } public override ICredentials Credentials { set { throw new NotImplementedException(); } } /// /// Gets whether or not all nested schema definitions are used. /// public bool AllNestedSchemaDefinitionsReferenced { get { return nestedSchemaDefinitionsUsage.Values.All(v => v); } } public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) { string fileName = Path.GetFileName(absoluteUri.ToString()); if (nestedSchemaDefinitions.ContainsKey(fileName)) { nestedSchemaDefinitionsUsage[fileName] = true; return new MemoryStream(Encoding.UTF8.GetBytes(nestedSchemaDefinitions[fileName])); } return null; } } } }