// 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.Xml; using System.Xml.Linq; using System.Xml.Schema; using Core.Common.IO.Exceptions; using Core.Common.Utils; using Core.Common.Utils.Builders; using Core.Common.Utils.Reflection; using Ringtoets.Piping.IO.Properties; using CoreCommonUtilsResources = Core.Common.Utils.Properties.Resources; namespace Ringtoets.Piping.IO.Readers { /// /// This class reads a piping configuration from XML and creates a collection of corresponding . /// public class PipingConfigurationReader { private readonly XDocument xmlDocument; /// /// Creates a new instance of . /// /// The file path to the XML file. /// Thrown when is invalid. /// Thrown when: /// /// points to a file that does not exist. /// points to a file that does not contain valid XML. /// points to a file that does not pass the schema validation. /// /// public PipingConfigurationReader(string xmlFilePath) { IOUtils.ValidateFilePath(xmlFilePath); ValidateFileExists(xmlFilePath); xmlDocument = LoadDocument(xmlFilePath); ValidateToSchema(xmlDocument, xmlFilePath); } /// /// Reads the piping configuration from the XML and creates a collection of corresponding . /// /// A collection of read . public IEnumerable Read() { return ParseReadPipingCalculationItems(xmlDocument.Root?.Elements()); } /// /// Validates whether a file exists at the provided . /// /// The file path to validate. /// Thrown when no existing file is found. private static void ValidateFileExists(string xmlFilePath) { if (!File.Exists(xmlFilePath)) { string message = new FileReaderErrorMessageBuilder(xmlFilePath).Build(CoreCommonUtilsResources.Error_File_does_not_exist); throw new CriticalFileReadException(message); } } /// /// Loads a XML document from the provided . /// /// The file path to load the XML document from. /// Thrown when the XML document cannot be loaded. private static XDocument LoadDocument(string xmlFilePath) { try { return XDocument.Load(xmlFilePath); } catch (Exception exception) when (exception is ArgumentNullException || exception is InvalidOperationException || exception is XmlException || exception is IOException) { string message = new FileReaderErrorMessageBuilder(xmlFilePath).Build(CoreCommonUtilsResources.Error_General_IO_Import_ErrorMessage); throw new CriticalFileReadException(message, exception); } } /// /// Validates the provided XML document based on a predefined XML Schema Definition (XSD). /// /// The XML document to validate. /// The file path the XML document is loaded from. /// Thrown when the provided XML document does not match the predefined XML Schema Definition (XSD). private static void ValidateToSchema(XDocument document, string xmlFilePath) { XmlSchemaSet schema = LoadXmlSchema(); try { document.Validate(schema, null); } catch (XmlSchemaValidationException exception) { string message = new FileReaderErrorMessageBuilder(xmlFilePath).Build(Resources.PipingConfigurationReader_Configuration_contains_no_valid_xml); throw new CriticalFileReadException(message, exception); } } private static IEnumerable ParseReadPipingCalculationItems(IEnumerable elements) { foreach (XElement element in elements) { if (element.Name == "berekening") { yield return ParseReadPipingCalculation(element); } if (element.Name == "folder") { yield return ParseReadPipingCalculationGroup(element); } } } private static ReadPipingCalculationGroup ParseReadPipingCalculationGroup(XElement folderElement) { return new ReadPipingCalculationGroup(folderElement.Attribute("naam")?.Value, ParseReadPipingCalculationItems(folderElement.Elements())); } private static ReadPipingCalculation ParseReadPipingCalculation(XElement calculationElement) { var constructionProperties = new ReadPipingCalculation.ConstructionProperties { Name = calculationElement.Attribute("naam")?.Value, AssessmentLevel = GetDoubleValueFromChildElement(calculationElement, "toetspeil"), HydraulicBoundaryLocation = GetStringValueFromChildElement(calculationElement, "hrlocatie"), SurfaceLine = GetStringValueFromChildElement(calculationElement, "profielschematisatie"), EntryPointL = GetDoubleValueFromChildElement(calculationElement, "intredepunt"), ExitPointL = GetDoubleValueFromChildElement(calculationElement, "uittredepunt"), StochasticSoilModel = GetStringValueFromChildElement(calculationElement, "ondergrondmodel"), StochasticSoilProfile = GetStringValueFromChildElement(calculationElement, "ondergrondschematisatie") }; XElement phreaticLevelExitElement = GetStochastChildElement(calculationElement, "polderpeil"); if (phreaticLevelExitElement != null) { constructionProperties.PhreaticLevelExitMean = GetDoubleValueFromChildElement(phreaticLevelExitElement, "verwachtingswaarde"); constructionProperties.PhreaticLevelExitStandardDeviation = GetDoubleValueFromChildElement(phreaticLevelExitElement, "standaardafwijking"); } XElement dampingFactorExitElement = GetStochastChildElement(calculationElement, "dempingsfactor"); if (dampingFactorExitElement != null) { constructionProperties.DampingFactorExitMean = GetDoubleValueFromChildElement(dampingFactorExitElement, "verwachtingswaarde"); constructionProperties.DampingFactorExitStandardDeviation = GetDoubleValueFromChildElement(dampingFactorExitElement, "standaardafwijking"); } return new ReadPipingCalculation(constructionProperties); } private static double? GetDoubleValueFromChildElement(XElement parentElement, string childElementName) { XElement childElement = parentElement.Elements(childElementName).FirstOrDefault(); return childElement != null ? (double?) Convert.ToDouble(childElement.Value) : null; } private static string GetStringValueFromChildElement(XElement parentElement, string childElementName) { XElement childElement = parentElement.Elements(childElementName).FirstOrDefault(); return childElement?.Value; } private static XElement GetStochastChildElement(XElement parentElement, string stochastName) { return parentElement.Elements("stochast").FirstOrDefault(e => e.Attribute("naam")?.Value == stochastName); } private static XmlSchemaSet LoadXmlSchema() { Stream schemaFile = AssemblyUtils.GetAssemblyResourceStream(typeof(PipingConfigurationReader).Assembly, "Ringtoets.Piping.IO.Readers.XMLPipingConfigurationSchema.xsd"); var xmlSchema = new XmlSchemaSet(); xmlSchema.Add(XmlSchema.Read(schemaFile, null)); return xmlSchema; } } }