Index: Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilLayer2DReader.cs =================================================================== diff -u -rd2b5b334c49948fa49297a1d24c13bc98aa6ee1e -r0047bcf51f94a295f3e4854f9b93594ad01a9e70 --- Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilLayer2DReader.cs (.../SoilLayer2DReader.cs) (revision d2b5b334c49948fa49297a1d24c13bc98aa6ee1e) +++ Ringtoets/Piping/src/Ringtoets.Piping.IO/SoilProfile/SoilLayer2DReader.cs (.../SoilLayer2DReader.cs) (revision 0047bcf51f94a295f3e4854f9b93594ad01a9e70) @@ -1,8 +1,12 @@ 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 Ringtoets.Piping.Data; using Ringtoets.Piping.IO.Builders; using Ringtoets.Piping.IO.Properties; @@ -23,212 +27,171 @@ private const string xElementName = "X"; private const string zElementName = "Z"; - private readonly XmlTextReader xmlTextReader; + private readonly XmlSchemaSet schema; /// - /// Constructs a new , which uses the as the source of the + /// 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 array of which contains the information of a - /// in an XML document. - /// Thrown when is null. - internal SoilLayer2DReader(byte[] geometry) + /// 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 validate to the schema. + /// + /// + internal SoilLayer2D Read(byte[] geometry) { + if (geometry == null) + { + throw new ArgumentNullException("geometry", Resources.SoilLayer2DReader_Geometry_is_null); + } try { - xmlTextReader = new XmlTextReader(new MemoryStream(geometry)); + return Read(XDocument.Load(new MemoryStream(geometry))); } - catch (ArgumentNullException e) + catch (XmlException e) { throw new SoilLayer2DConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml, e); } } /// - /// Reads the XML document and from this obtains the required information and constructs a based - /// on this information. + /// 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: /// - /// Reading from the XML document of the failed. - /// The segments do not form a loop for either the inner or outer loop. + /// is not valid XML. + /// does not validate to the schema. /// /// - internal SoilLayer2D Read() + internal SoilLayer2D Read(XDocument geometry) { + ValidateToSchema(geometry); + + return ParseLayer(geometry); + } + + private SoilLayer2D ParseLayer(XDocument geometry) + { var pipingSoilLayer = new SoilLayer2D(); - try + var xmlOuterLoop = geometry.XPathSelectElement(string.Format("//{0}", outerLoopElementName)); + var xmlInnerLoops = geometry.XPathSelectElements(string.Format("//{0}", innerLoopElementName)); + + if (xmlOuterLoop != null) { - while (xmlTextReader.Read()) - { - List outerLoop; - List innerLoop; - if (TryParseLoop(outerLoopElementName, out outerLoop)) - { - pipingSoilLayer.OuterLoop = outerLoop; - } - if (TryParseLoop(innerLoopElementName, out innerLoop)) - { - pipingSoilLayer.AddInnerLoop(innerLoop); - } - } + pipingSoilLayer.OuterLoop = ParseGeometryLoop(xmlOuterLoop); } - catch (XmlException e) + foreach (XElement loop in xmlInnerLoops) { - throw new SoilLayer2DConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml, e); + pipingSoilLayer.AddInnerLoop(ParseGeometryLoop(loop)); } - catch (ArgumentException e) - { - throw new SoilLayer2DConversionException(e.Message, e); - } - return pipingSoilLayer; } /// - /// Tries to parse the element with the given , which the reader should be currently pointing at, as a loop. + /// Adds the validation schema for the geometry to the . /// - /// The name of the element which the reader should be currently pointing at. - /// The result of parsing the element as a loop. null if the current element's name does not match . - /// True if the reader currently points to an element with name . False otherwise. - /// Thrown when not both HeadPoint and EndPoint are defined in - /// the GeometryCurve XML element. - private bool TryParseLoop(string elementName, out List loop) + /// The to add the validation schema to. + /// Thrown when: + /// + /// The validation schema could not be correctly loaded. + /// The validation failed. + /// + /// + private void ValidateToSchema(XDocument document) { - loop = null; - - if (IsElementWithName(elementName)) + try { - loop = new List(); - - if (!IsEmptyElement()) - { - while (xmlTextReader.Read() && !IsEndElementWithName(elementName)) - { - Segment2D segment; - if (TryParseSegment(out segment)) - { - loop.Add(segment); - } - } - } - return true; + document.Validate(schema, null); } - return false; + catch (InvalidOperationException e) + { + throw new SoilLayer2DConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml, e); + } + catch (XmlSchemaValidationException e) + { + throw new SoilLayer2DConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml, e); + } } - /// - /// Tries to parse a GeometryCurve XML element to a . - /// - /// The segment reference in which to put the parsed . - /// true if a segment could be parsed. false otherwise. - /// Thrown when not both HeadPoint and EndPoint are defined in - /// the GeometryCurve XML element. - private bool TryParseSegment(out Segment2D segment) + private XmlSchemaSet LoadXmlSchema() { - segment = null; - if (IsElementWithName(geometryCurveElementName) || IsElementWithName(endPointElementName)) + var schemaFile = GetType().Assembly.GetManifestResourceStream("Ringtoets.Piping.IO.SoilProfile.XmlGeometrySchema.xsd"); + if (schemaFile == null) { - var points = new Point2D[2]; - var index = 0; - while (xmlTextReader.Read() && !IsEndElementWithName(geometryCurveElementName)) - { - Point2D point; - if (TryParsePoint(out point)) - { - points[index] = point; - index++; - } - } - try - { - segment = new Segment2D(points[0], points[1]); - return true; - } - catch (ArgumentNullException e) - { - throw new SoilLayer2DConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml, e); - } + throw new SoilLayer2DConversionException(Resources.SoilLayer2DReader_Schema_file_could_not_be_loaded); } - return false; + try + { + var xmlSchema = new XmlSchemaSet(); + xmlSchema.Add(XmlSchema.Read(schemaFile, null)); + return xmlSchema; + } + catch (XmlSchemaException e) + { + throw new SoilLayer2DConversionException(Resources.SoilLayer2DReader_Schema_file_could_not_be_loaded, e); + } } - /// - /// Finds out whether the element which the reader is currently pointing at is empty. - /// - /// True if the element is empty. False otherwise. - private bool IsEmptyElement() + private IEnumerable ParseGeometryLoop(XElement loop) { - return xmlTextReader.IsEmptyElement; + var loops = new Collection(); + var curves = loop.XPathSelectElements(string.Format("//{0}", geometryCurveElementName)); + + foreach (XElement curve in curves) + { + loops.Add(ParseGeometryCurve(curve)); + } + return loops; } - /// - /// Tries to parse the element which the reader is currently pointing at as a point. - /// - /// The result of parsing the element as a point. null if current element is not a head or end point. - /// True if the reader currently points to an element with name or . False otherwise. - private bool TryParsePoint(out Point2D point) + private Segment2D ParseGeometryCurve(XElement curve) { - point = null; - - if (IsElementWithName(headPointElementName) || IsElementWithName(endPointElementName)) + var headDefinition = curve.Element(headPointElementName); + var endDefinition = curve.Element(endPointElementName); + if (headDefinition != null && endDefinition != null) { - var pointValues = ReadChildValues(); - point = new Point2D - { - X = double.Parse(pointValues[xElementName], CultureInfo.InvariantCulture), - Y = double.Parse(pointValues[zElementName], CultureInfo.InvariantCulture) - }; - return true; + return new Segment2D( + ParsePoint(headDefinition), + ParsePoint(endDefinition) + ); } - return false; + throw new SoilLayer2DConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml); } - /// - /// Reads the name and values for the children of the current element and puts them in a name indexed dictionary. - /// - /// A . For each entry, key is equal to child element name and value is equal to the value of the child element's text node. - private Dictionary ReadChildValues() + private Point2D ParsePoint(XElement point) { - string elementName = xmlTextReader.Name; - var nodeSibblings = new Dictionary(); - - while (xmlTextReader.Read() && !IsEndElementWithName(elementName)) + var x = point.Element(xElementName); + var y = point.Element(zElementName); + if (x != null && y != null) { - if (xmlTextReader.NodeType == XmlNodeType.Element) + return new Point2D { - nodeSibblings[xmlTextReader.Name] = xmlTextReader.ReadString(); - } + X = double.Parse(x.Value, CultureInfo.InvariantCulture), + Y = double.Parse(y.Value, CultureInfo.InvariantCulture) + }; } - - return nodeSibblings; + throw new SoilLayer2DConversionException(Resources.SoilLayer2DReader_Geometry_contains_no_valid_xml); } - - /// - /// Checks whether the element the reader is currently pointing at is of type and has a name equal to . - /// - /// The name which the element should have. - /// True if the current element has type and its name is equal to . - private bool IsElementWithName(string name) - { - var isElement = xmlTextReader.NodeType == XmlNodeType.Element; - var isPoint = xmlTextReader.Name == name; - - return isElement && isPoint; - } - /// - /// Checks whether the element the reader is currently pointing at is of type and has a name equal to . - /// - /// The name which the end element should have. - /// True if the current element has type and its name is equal to . - private bool IsEndElementWithName(string name) - { - var isElement = xmlTextReader.NodeType == XmlNodeType.EndElement; - var isPoint = xmlTextReader.Name == name; - - return isElement && isPoint; - } } } \ No newline at end of file