// Copyright (C) Stichting Deltares 2017. 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.Collections.ObjectModel; using System.Globalization; using System.IO; using System.Xml; using System.Xml.Linq; using System.Xml.Schema; using System.Xml.XPath; using Core.Common.Base.Geometry; using Ringtoets.MacroStabilityInwards.IO.Builders; using Ringtoets.MacroStabilityInwards.IO.Exceptions; using Ringtoets.MacroStabilityInwards.IO.Properties; using Ringtoets.MacroStabilityInwards.Primitives; namespace Ringtoets.MacroStabilityInwards.IO.SoilProfile { /// /// This class is responsible for reading an array of bytes and interpret this as an XML document, which contains information about /// the geometry of a . /// internal class SoilLayer2DReader { private const string outerLoopElementName = "OuterLoop"; private const string innerLoopElementName = "InnerLoop"; private const string endPointElementName = "EndPoint"; private const string headPointElementName = "HeadPoint"; private const string geometryCurveElementName = "GeometryCurve"; private const string xElementName = "X"; private const string zElementName = "Z"; private readonly XmlSchemaSet schema; /// /// Constructs an instance of . /// /// Thrown when the XML-schema /// could not be loaded. internal SoilLayer2DReader() { schema = LoadXmlSchema(); } /// /// Reads a new using the as the source of the /// geometry for a . /// /// An of which contains the information /// of a in an XML document. /// A new with information taken from the XML document. /// Thrown when is null. /// Thrown when: /// /// is not valid XML. /// does not pass schema validation. /// /// /// internal SoilLayer2D Read(byte[] geometry) { if (geometry == null) { throw new ArgumentNullException(nameof(geometry), Resources.SoilLayer2DReader_Geometry_is_null); } try { return Read(XDocument.Load(new MemoryStream(geometry))); } catch (XmlException e) { throw new SoilLayerConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml, e); } } /// /// Reads a new using the as the source of the /// geometry for a . /// /// An which contains the information of a /// in an XML document. /// A new with information taken from the XML document. /// Thrown when is null. /// Thrown when: /// /// is not valid XML. /// does not pass schema validation. /// /// /// internal SoilLayer2D Read(XDocument geometry) { ValidateToSchema(geometry); return ParseLayer(geometry); } /// /// Validates the to the . /// /// The to validate. /// Thrown when the validation failed. /// private void ValidateToSchema(XDocument document) { try { document.Validate(schema, null); } catch (XmlSchemaValidationException e) { throw new SoilLayerConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml, e); } } private static XmlSchemaSet LoadXmlSchema() { var xmlSchemaSet = new XmlSchemaSet(); xmlSchemaSet.Add(XmlSchema.Read(new StringReader(Resources.XmlGeometrySchema), null)); return xmlSchemaSet; } /// /// Parses the XML element to create a 2D soil layer. /// /// The geometry. /// XML for inner or outer geometry loops is invalid. private SoilLayer2D ParseLayer(XDocument geometry) { var soilLayer = new SoilLayer2D(); XElement xmlOuterLoop = geometry.XPathSelectElement(string.Format("//{0}", outerLoopElementName)); IEnumerable xmlInnerLoops = geometry.XPathSelectElements(string.Format("//{0}", innerLoopElementName)); if (xmlOuterLoop != null) { soilLayer.OuterLoop = ParseGeometryLoop(xmlOuterLoop); } foreach (XElement loop in xmlInnerLoops) { soilLayer.AddInnerLoop(ParseGeometryLoop(loop)); } return soilLayer; } /// /// Parses the XML element to create a collection of describing /// a geometric loop. /// /// The geometric loop element. /// XML for any geometry curve is invalid. private IEnumerable ParseGeometryLoop(XElement loop) { var loops = new Collection(); IEnumerable curves = loop.XPathSelectElements(string.Format("//{0}", geometryCurveElementName)); foreach (XElement curve in curves) { loops.Add(ParseGeometryCurve(curve)); } return loops; } /// /// Parses the XML element to create a . /// /// The geometry curve element. /// XML for geometry curve is invalid. private Segment2D ParseGeometryCurve(XElement curve) { XElement headDefinition = curve.Element(headPointElementName); XElement endDefinition = curve.Element(endPointElementName); if (headDefinition != null && endDefinition != null) { return new Segment2D( ParsePoint(headDefinition), ParsePoint(endDefinition) ); } throw new SoilLayerConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml); } /// /// Parses the XML element to create a . /// /// The 2D point element. /// Thrown when any of the following occurs: /// /// A coordinate value cannot be parsed. /// XML for 2D point is invalid. /// private Point2D ParsePoint(XElement point) { XElement xElement = point.Element(xElementName); XElement yElement = point.Element(zElementName); if (xElement != null && yElement != null) { try { double x = double.Parse(xElement.Value, CultureInfo.InvariantCulture); double y = double.Parse(yElement.Value, CultureInfo.InvariantCulture); return new Point2D(x, y); } catch (ArgumentNullException e) { throw new SoilLayerConversionException(Resources.SoilLayer2DReader_Could_not_parse_point_location, e); } catch (FormatException e) { throw new SoilLayerConversionException(Resources.SoilLayer2DReader_Could_not_parse_point_location, e); } catch (OverflowException e) { throw new SoilLayerConversionException(Resources.SoilLayer2DReader_Could_not_parse_point_location, e); } } throw new SoilLayerConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml); } } }