using System; using System.Collections.Generic; using System.IO; using System.Xml; using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Geometries; namespace GisSharpBlog.NetTopologySuite.IO.GML2 { /// /// Reads a GML document and creates a representation of the features based or NetTopologySuite model. /// Uses GML 2.1.1 Geometry.xsd schema for base for features. /// public class GMLReader { private IGeometryFactory factory = null; /// /// Geometry builder. /// protected IGeometryFactory Factory { get { return factory; } } /// /// Initialize reader with a standard GeometryFactory. /// public GMLReader() : this(GeometryFactory.Default) { } /// /// Initialize reader with the given GeometryFactory. /// /// public GMLReader(IGeometryFactory factory) { this.factory = factory; } /// /// Read a GML document and returns relative Geometry. /// /// /// public IGeometry Read(XmlDocument document) { XmlReader reader = new XmlTextReader(new StringReader(document.InnerXml)); return Read(reader); } /// /// /// /// /// public IGeometry Read(string xmlText) { XmlReader reader = new XmlTextReader(new StringReader(xmlText)); return Read(reader); } /// /// /// /// /// public IGeometry Read(StringReader stringReader) { XmlReader reader = new XmlTextReader(stringReader); return Read(reader); } /// /// /// /// /// public IGeometry Read(XmlReader reader) { if (reader.NodeType == XmlNodeType.EndElement) throw new ApplicationException("Should never reach here!"); if (IsStartElement(reader, "Point")) return ReadPoint(reader); else if (IsStartElement(reader, "LineString")) return ReadLineString(reader); else if (IsStartElement(reader, "Polygon")) return ReadPolygon(reader); else if (IsStartElement(reader, "MultiPoint")) return ReadMultiPoint(reader); else if (IsStartElement(reader, "MultiLineString")) return ReadMultiLineString(reader); else if (IsStartElement(reader, "MultiPolygon")) return ReadMultiPolygon(reader); else if (IsStartElement(reader, "MultiGeometry")) return ReadGeometryCollection(reader); else { // Go away until something readable is found... reader.Read(); return Read(reader); } } /// /// Reads the coordinate. /// /// The reader. /// protected ICoordinate ReadCoordinate(XmlReader reader) { double x = 0, y = 0; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (IsStartElement(reader, "X")) { reader.Read(); // Jump to X value x = XmlConvert.ToDouble(reader.Value); } else if (IsStartElement(reader, "Y")) { reader.Read(); // Jump to Y value y = XmlConvert.ToDouble(reader.Value); } break; case XmlNodeType.EndElement: if (reader.Name == GMLElements.gmlPrefix + ":coord") return new Coordinate(x, y); break; default: break; } } throw new ArgumentException("ShouldNeverReachHere!"); } /// /// Extract a from a x,y string value. /// /// /// protected ICoordinate ReadCoordinates(string value) { string[] values = value.Split(','); double x = XmlConvert.ToDouble(values[0]); double y = XmlConvert.ToDouble(values[1]); return new Coordinate(x, y); } /// /// /// /// /// protected IPoint ReadPoint(XmlReader reader) { while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (IsStartElement(reader, "coord")) return Factory.CreatePoint(ReadCoordinate(reader)); else if (IsStartElement(reader, "coordinates")) { reader.Read(); // Jump to values string[] coords = reader.Value.Split(' '); if (coords.Length != 1) throw new ApplicationException("Should never reach here!"); ICoordinate c = ReadCoordinates(coords[0]); Factory.CreatePoint(c); } break; default: break; } } throw new ArgumentException("ShouldNeverReachHere!"); } /// /// /// /// /// protected ILineString ReadLineString(XmlReader reader) { List coordinates = new List(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (IsStartElement(reader, "coord")) coordinates.Add(ReadCoordinate(reader)); else if (IsStartElement(reader, "coordinates")) { reader.Read(); // Jump to values string[] coords = reader.Value.Split(' '); foreach (string coord in coords) { if (String.IsNullOrEmpty(coord)) continue; ICoordinate c = ReadCoordinates(coord); coordinates.Add(c); } return Factory.CreateLineString(coordinates.ToArray()); } break; case XmlNodeType.EndElement: return Factory.CreateLineString(coordinates.ToArray()); default: break; } } throw new ArgumentException("ShouldNeverReachHere!"); } /// /// /// /// /// protected ILinearRing ReadLinearRing(XmlReader reader) { return Factory.CreateLinearRing(ReadLineString(reader).Coordinates); } /// /// /// /// /// protected IPolygon ReadPolygon(XmlReader reader) { ILinearRing exterior = null; List interiors = new List(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (IsStartElement(reader, "outerBoundaryIs")) exterior = ReadLinearRing(reader) as LinearRing; else if (IsStartElement(reader, "innerBoundaryIs")) interiors.Add(ReadLinearRing(reader)); break; case XmlNodeType.EndElement: if (reader.Name == GMLElements.gmlPrefix + ":Polygon") return Factory.CreatePolygon(exterior, interiors.ToArray()); break; default: break; } } throw new ArgumentException("ShouldNeverReachHere!"); } /// /// /// /// /// protected IMultiPoint ReadMultiPoint(XmlReader reader) { List points = new List(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (IsStartElement(reader, "pointMember")) points.Add(ReadPoint(reader)); break; case XmlNodeType.EndElement: if (reader.Name == GMLElements.gmlPrefix + ":MultiPoint") return Factory.CreateMultiPoint(points.ToArray()); break; default: break; } } throw new ArgumentException("ShouldNeverReachHere!"); } /// /// /// /// /// protected IMultiLineString ReadMultiLineString(XmlReader reader) { List lines = new List(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (IsStartElement(reader, "lineStringMember")) lines.Add(ReadLineString(reader)); break; case XmlNodeType.EndElement: if (reader.Name == GMLElements.gmlPrefix + ":MultiLineString") return Factory.CreateMultiLineString(lines.ToArray()); break; default: break; } } throw new ArgumentException("ShouldNeverReachHere!"); } /// /// /// /// /// protected IMultiPolygon ReadMultiPolygon(XmlReader reader) { List polygons = new List(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (IsStartElement(reader, "polygonMember")) polygons.Add(ReadPolygon(reader)); break; case XmlNodeType.EndElement: if (reader.Name == GMLElements.gmlPrefix + ":MultiPolygon") return Factory.CreateMultiPolygon(polygons.ToArray()); break; default: break; } } throw new ArgumentException("ShouldNeverReachHere!"); } /// /// /// /// /// protected IGeometryCollection ReadGeometryCollection(XmlReader reader) { List collection = new List(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (IsStartElement(reader, "Point")) collection.Add(ReadPoint(reader)); else if (IsStartElement(reader, "LineString")) collection.Add(ReadLineString(reader)); else if (IsStartElement(reader, "Polygon")) collection.Add(ReadPolygon(reader)); else if (IsStartElement(reader, "MultiPoint")) collection.Add(ReadMultiPoint(reader)); else if (IsStartElement(reader, "MultiLineString")) collection.Add(ReadMultiLineString(reader)); else if (IsStartElement(reader, "MultiPolygon")) collection.Add(ReadMultiPolygon(reader)); else if (IsStartElement(reader, "MultiGeometry")) collection.Add(ReadGeometryCollection(reader)); break; case XmlNodeType.EndElement: if (reader.Name == GMLElements.gmlPrefix + ":MultiGeometry") return Factory.CreateGeometryCollection(collection.ToArray()); break; default: break; } } throw new ArgumentException("ShouldNeverReachHere!"); } /// /// /// /// /// /// private static bool IsStartElement(XmlReader reader, string name) { return reader.IsStartElement(name, GMLElements.gmlNS) || reader.IsStartElement(GMLElements.gmlPrefix + ":" + name); } } }