using System; using System.Collections.ObjectModel; using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.IO; using System.Net; using System.Text; using System.Xml; using System.Xml.Schema; using GeoAPI.Geometries; using Common.Logging; namespace SharpMap.Web.Wms { /// /// Class for requesting and parsing a WMS servers capabilities /// [Serializable] public class Client : IClient { static ILog logger = LogManager.GetLogger(typeof(Client)); private XmlNamespaceManager _nsmgr; #region WMS Data structures #region Nested type: WmsLayerStyle /// /// Structure for storing information about a WMS Layer Style /// public struct WmsLayerStyle { /// /// Abstract /// public string Abstract; /// /// Legend /// public WmsStyleLegend LegendUrl; /// /// Name /// public string Name; /// /// Style Sheet Url /// public WmsOnlineResource StyleSheetUrl; /// /// Title /// public string Title; } #endregion #region Nested type: WmsOnlineResource /// /// Structure for storing info on an Online Resource /// public struct WmsOnlineResource { /// /// URI of online resource /// public string OnlineResource; /// /// Type of online resource (Ex. request method 'Get' or 'Post') /// public string Type; } #endregion #region Nested type: WmsServerLayer /// /// Structure for holding information about a WMS Layer /// public struct WmsServerLayer { /// /// Abstract /// public string Abstract; /// /// Collection of child layers /// public WmsServerLayer[] ChildLayers; /// /// Coordinate Reference Systems supported by layer /// public string[] CRS; /// /// Keywords /// public string[] Keywords; /// /// Latitudal/longitudal extent of this layer /// public Envelope LatLonBoundingBox; /// /// Extent of this layer in spatial reference system /// public List SRIDBoundingBoxes; /// /// Unique name of this layer used for requesting layer /// public string Name; /// /// Specifies whether this layer is queryable using GetFeatureInfo requests /// public bool Queryable; /// /// List of styles supported by layer /// public WmsLayerStyle[] Style; /// /// Layer title /// public string Title; } #endregion #region Nested type: WmsStyleLegend /// /// Structure for storing WMS Legend information /// public struct WmsStyleLegend { /// /// Online resource for legend style /// public WmsOnlineResource OnlineResource; /// /// Size of legend /// public Size Size; } #endregion #endregion #region Properties private string[] _exceptionFormats; private Collection _getMapOutputFormats; private WmsOnlineResource[] _getMapRequests; private Collection _getCapabilitiesOutputFormats; private WmsOnlineResource[] _getCapabilitiesRequests; private Collection _getFeatureInfoOutputFormats; private WmsOnlineResource[] _getFeatureInfoRequests; private Collection _describeLayerOutputFormats; private WmsOnlineResource[] _describeLayerRequests; private Collection _getLegendGraphicOutputFormats; private WmsOnlineResource[] _getLegendGraphicRequests; private Collection _getStylesOutputFormats; private WmsOnlineResource[] _getStylesRequests; private Collection _putStylesOutputFormats; private WmsOnlineResource[] _putStylesRequests; private WmsServerLayer _layer; private Capabilities.WmsServiceDescription _serviceDescription; private string _version; private XmlDocument _xmlDoc; private string _baseUrl; private string _capabilitiesUrl; private IWebProxy _proxy; private int _timeOut; private ICredentials _credentials = null; private XmlNode _vendorSpecificCapabilities; /// /// Timeout of webrequest in milliseconds. /// public int TimeOut { get { return _timeOut; } set { _timeOut = value; } } /// /// public ICredentials Credentials { get { return _credentials; } set { _credentials = value; } } /// /// Gets the service description /// public Capabilities.WmsServiceDescription ServiceDescription { get { return _serviceDescription; } } /// /// Gets the version of the WMS server (ex. "1.3.0") /// public string Version { get { return _version; } set { _version = value; } } /// /// [Obsolete("Deprecated, use Version property instead.")] public string WmsVersion { get { return _version; } } /// /// Gets the available GetMap request methods and Online Resource URI /// public WmsOnlineResource[] GetCapabilitiesRequests { get { return _getCapabilitiesRequests; } } /// /// Gets a list of available image mime type formats /// public Collection GetCapabilitiesOutputFormats { get { return _getCapabilitiesOutputFormats; } } /// /// Gets the available GetFeatureInfo request methods and Online Resource URI /// public WmsOnlineResource[] GetFeatureInfoRequests { get { return _getFeatureInfoRequests; } } /// /// Gets a list of available image mime type formats /// public Collection GetFeatureInfoOutputFormats { get { return _getFeatureInfoOutputFormats; } } /// /// Gets the available DescribeLayer request methods and Online Resource URI /// public WmsOnlineResource[] DescribeLayerRequests { get { return _describeLayerRequests; } } /// /// Gets a list of available image mime type formats /// public Collection DescribeLayerOutputFormats { get { return _describeLayerOutputFormats; } } /// /// Gets the available GetLegendGraphic request methods and Online Resource URI /// public WmsOnlineResource[] GetLegendGraphicRequests { get { return _getLegendGraphicRequests; } } /// /// Gets a list of available image mime type formats /// public Collection GetLegendGraphicOutputFormats { get { return _getLegendGraphicOutputFormats; } } /// /// Gets the available GetLegendGraphic request methods and Online Resource URI /// public WmsOnlineResource[] GetStylesRequests { get { return _getStylesRequests; } } /// /// Gets a list of available image mime type formats /// public Collection GetStylesOutputFormats { get { return _getStylesOutputFormats; } } /// /// Gets the available GetLegendGraphic request methods and Online Resource URI /// public WmsOnlineResource[] PutStylesRequests { get { return _putStylesRequests; } } /// /// Gets a list of available image mime type formats /// public Collection PutStylesOutputFormats { get { return _putStylesOutputFormats; } } /// /// Gets a list of available image mime type formats /// public Collection GetMapOutputFormats { get { return _getMapOutputFormats; } } /// /// Gets a list of available exception mime type formats /// public string[] ExceptionFormats { get { return _exceptionFormats; } } /// /// Exposes the capabilitie's VendorSpecificCapabilities as XmlNode object. External modules /// could use this to parse the vendor specific capabilities for their specific purpose. /// public XmlNode VendorSpecificCapabilities { get { return _vendorSpecificCapabilities; } } /// /// Gets the available GetMap request methods and Online Resource URI /// public WmsOnlineResource[] GetMapRequests { get { return _getMapRequests; } } /// /// Gets the hierarchical layer structure /// public WmsServerLayer Layer { get { return _layer; } } /// /// /// public IWebProxy Proxy { get { return _proxy;} set {_proxy = value;} } /// /// Gets or sets the base URL for the server without any OGC specific name=value pairs /// public string BaseUrl { get{return _baseUrl;} set { _capabilitiesUrl = CreateCapabilitiesUrl(_baseUrl); _baseUrl = value; } } /// /// Gets the entire XML document as text /// public string CapabilitiesUrl { get { return _capabilitiesUrl; } } /// /// Gets the entire XML document as text /// public string GetXmlAsText { get { StringWriter sw = new StringWriter(); XmlTextWriter xw = new XmlTextWriter(sw); XmlDoc.WriteTo(xw); return sw.ToString(); } } /// /// Gets the entire XML document as byte[] /// public byte[] GetXmlAsByteArray { get { StringWriter sw = new StringWriter(); XmlTextWriter xw = new XmlTextWriter(sw); XmlDoc.WriteTo(xw); byte[] baData = System.Text.Encoding.UTF8.GetBytes(sw.ToString()); return baData; } } /// /// public XmlDocument XmlDoc { get { return _xmlDoc; } } #endregion #region Constructors /// /// Just instantiate, no parameters /// public Client() {} /// /// Initializes WMS server and parses the Capabilities request /// /// URL of wms server public Client(string url) : this(url, null, 10000, null, "") { } /// /// This Initializes WMS server and parses the Capabilities request /// /// URL of wms server /// Proxy to use public Client(string url, IWebProxy proxy) : this(url, proxy, 10000, null, "") { } /// /// This Initializes WMS server and parses the Capabilities request /// /// URL of wms server /// Proxy to use /// public Client(string url, IWebProxy proxy, int timeOut) : this(url, proxy, timeOut, null, "") { } /// /// Initializes WMS server and parses the Capabilities request /// /// URL of wms server /// Proxy to use /// Credentials for authenticating against remote WMS-server public Client(string url, IWebProxy proxy, ICredentials credentials) : this(url, proxy, 10000, credentials, "") { } /// /// Initializes WMS server and parses the Capabilities request /// /// URL of wms server /// Proxy to use /// Web request timeout /// Credentials for authenticating against remote WMS-server public Client(string url, IWebProxy proxy, int timeOut, ICredentials credentials) : this(url, proxy, timeOut, credentials, "") { } /// /// Initializes WMS server and parses the Capabilities request /// /// URL of wms server /// Proxy to use /// Web request timeout /// public Client(string url, IWebProxy proxy, int timeOut, string version) : this(url, proxy, timeOut, null, version) { } /// /// Initializes WMS server and parses the Capabilities request /// /// URL of wms server /// Proxy to use /// Web request timeout /// /// public Client(string url, IWebProxy proxy, int timeOut, ICredentials credentials, string version) { _baseUrl = url; _proxy = proxy; _timeOut = timeOut; _version = version; _credentials = credentials; _capabilitiesUrl = CreateCapabilitiesUrl(url); _xmlDoc = GetRemoteXml(); ParseVersion(); ParseCapabilities(); } /// /// Hydrates Client object based on byte array version of XML document /// /// byte array version of capabilities document public Client(byte[] byteXml) { Stream stream = new MemoryStream(byteXml); var r = new XmlTextReader(stream); r.XmlResolver = null; _xmlDoc = new XmlDocument(); XmlDoc.XmlResolver = null; XmlDoc.Load(r); stream.Close(); _nsmgr = new XmlNamespaceManager(XmlDoc.NameTable); _baseUrl = ""; _proxy = null; _timeOut = 10000; _version = ""; _credentials = null; ParseVersion(); ParseCapabilities(); } #endregion #region Methods /// /// Downloads the service description from WMS service /// /// XmlDocument from . /// Thrown if the result is not interpretable. public XmlDocument GetRemoteXml() { Stream stream; try { var myRequest = WebRequest.Create(_capabilitiesUrl); myRequest.Credentials = _credentials ?? CredentialCache.DefaultCredentials; myRequest.Timeout = _timeOut; if (_proxy != null) myRequest.Proxy = _proxy; var myResponse = myRequest.GetResponse(); if (myResponse.ContentLength == 0) throw new ApplicationException("Empty web response"); stream = myResponse.GetResponseStream(); if (stream == null) throw new ApplicationException("No response stream"); } catch (Exception ex) { throw new ApplicationException("Could not download capabilities document from the server. The server may not be available right now.\n" + ex.Message, ex); } try { var xmlTextReader = new XmlTextReader(_capabilitiesUrl, stream); xmlTextReader.XmlResolver = null; _xmlDoc = new XmlDocument(); _xmlDoc.XmlResolver = null; _xmlDoc.Load(xmlTextReader); _nsmgr = new XmlNamespaceManager(_xmlDoc.NameTable); return _xmlDoc; } catch (Exception ex) { throw new ApplicationException("Could not convert the capabilities file into an XML document. Do you have illegal characters in the document.", ex); } finally { stream.Close(); } } /// /// Parses a servicedescription and stores the data in the ServiceDescription property /// public void ParseCapabilities() { if (_xmlDoc.DocumentElement.Attributes["version"] != null) { _version = _xmlDoc.DocumentElement.Attributes["version"].Value; if (_version != "1.0.0" && _version != "1.1.0" && _version != "1.1.1" && _version != "1.3.0") throw new ApplicationException("WMS Version " + _version + " is not currently supported"); _nsmgr.AddNamespace(String.Empty, "http://www.opengis.net/wms"); if (_version == "1.3.0") { _nsmgr.AddNamespace("sm", "http://www.opengis.net/wms"); } else _nsmgr.AddNamespace("sm", ""); _nsmgr.AddNamespace("xlink", "http://www.w3.org/1999/xlink"); _nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); } else throw (new ApplicationException("No service version number was found in the capabilities XML file!")); XmlNode xnService = _xmlDoc.DocumentElement.SelectSingleNode("sm:Service", _nsmgr); XmlNode xnCapability = _xmlDoc.DocumentElement.SelectSingleNode("sm:Capability", _nsmgr); if (xnService != null) ParseServiceDescription(xnService); else throw (new ApplicationException("No service tag found in the capabilities XML file!")); if (xnCapability != null) ParseCapability(xnCapability); else throw (new ApplicationException("No capability tag found in the capabilities XML file!")); } /// /// Parses service description node /// /// private void ParseServiceDescription(XmlNode xnlServiceDescription) { XmlNode node = xnlServiceDescription.SelectSingleNode("sm:Title", _nsmgr); _serviceDescription.Title = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode("sm:OnlineResource/@xlink:href", _nsmgr); _serviceDescription.OnlineResource = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode("sm:Abstract", _nsmgr); _serviceDescription.Abstract = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode("sm:Fees", _nsmgr); _serviceDescription.Fees = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode("sm:AccessConstraints", _nsmgr); _serviceDescription.AccessConstraints = (node != null ? node.InnerText : null); XmlNodeList xnlKeywords = xnlServiceDescription.SelectNodes("sm:KeywordList/sm:Keyword", _nsmgr); if (xnlKeywords != null) { _serviceDescription.Keywords = new string[xnlKeywords.Count]; for (int i = 0; i < xnlKeywords.Count; i++) ServiceDescription.Keywords[i] = xnlKeywords[i].InnerText; } //Contact information _serviceDescription.ContactInformation = new Capabilities.WmsContactInformation(); node = xnlServiceDescription.SelectSingleNode("sm:ContactInformation/sm:ContactAddress/sm:Address", _nsmgr); _serviceDescription.ContactInformation.Address.Address = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode("sm:ContactInformation/sm:ContactAddress/sm:AddressType", _nsmgr); _serviceDescription.ContactInformation.Address.AddressType = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode("sm:ContactInformation/sm:ContactAddress/sm:City", _nsmgr); _serviceDescription.ContactInformation.Address.City = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode("sm:ContactInformation/sm:ContactAddress/sm:Country", _nsmgr); _serviceDescription.ContactInformation.Address.Country = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode("sm:ContactInformation/sm:ContactAddress/sm:PostCode", _nsmgr); _serviceDescription.ContactInformation.Address.PostCode = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode("sm:ContactInformation/sm:ContactElectronicMailAddress", _nsmgr); _serviceDescription.ContactInformation.Address.StateOrProvince = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode("sm:ContactInformation/sm:ContactElectronicMailAddress", _nsmgr); _serviceDescription.ContactInformation.ElectronicMailAddress = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode("sm:ContactInformation/sm:ContactFacsimileTelephone", _nsmgr); _serviceDescription.ContactInformation.FacsimileTelephone = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode( "sm:ContactInformation/sm:ContactPersonPrimary/sm:ContactOrganization", _nsmgr); _serviceDescription.ContactInformation.PersonPrimary.Organisation = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode( "sm:ContactInformation/sm:ContactPersonPrimary/sm:ContactPerson", _nsmgr); _serviceDescription.ContactInformation.PersonPrimary.Person = (node != null ? node.InnerText : null); node = xnlServiceDescription.SelectSingleNode("sm:ContactInformation/sm:ContactVoiceTelephone", _nsmgr); _serviceDescription.ContactInformation.VoiceTelephone = (node != null ? node.InnerText : null); } /// /// Parses capability node /// /// private void ParseCapability(XmlNode xnCapability) { XmlNode xnRequest = xnCapability.SelectSingleNode("sm:Request", _nsmgr); if (xnRequest == null) throw (new Exception("Request parameter not specified in Service Description")); ParseRequest(xnRequest); XmlNode xnLayer = xnCapability.SelectSingleNode("sm:Layer", _nsmgr); if (xnLayer == null) throw (new Exception("No layer tag found in Service Description")); _layer = ParseLayer(xnLayer); XmlNode xnException = xnCapability.SelectSingleNode("sm:Exception", _nsmgr); if (xnException != null) ParseExceptions(xnException); _vendorSpecificCapabilities = xnCapability.SelectSingleNode("sm:VendorSpecificCapabilities", _nsmgr); } /// /// Parses valid exceptions /// /// private void ParseExceptions(XmlNode xnlExceptionNode) { XmlNodeList xnlFormats = xnlExceptionNode.SelectNodes("sm:Format", _nsmgr); if (xnlFormats != null) { _exceptionFormats = new string[xnlFormats.Count]; for (int i = 0; i < xnlFormats.Count; i++) { _exceptionFormats[i] = xnlFormats[i].InnerText; } } } /// /// Parses request node /// /// private void ParseRequest(XmlNode xmlRequestNode) { //GetMap XmlNode xnGetMap = xmlRequestNode.SelectSingleNode("sm:GetMap", _nsmgr); ParseRequestTypeBlock(xnGetMap, ref _getMapRequests, ref _getMapOutputFormats); //GetCapabilities XmlNode xnGetCapabilities = xmlRequestNode.SelectSingleNode("sm:GetCapabilities", _nsmgr); ParseRequestTypeBlock(xnGetCapabilities, ref _getCapabilitiesRequests, ref _getCapabilitiesOutputFormats); //GetFeatureInfo XmlNode xnGetFeatureInfo = xmlRequestNode.SelectSingleNode("sm:GetFeatureInfo", _nsmgr); ParseRequestTypeBlock(xnGetFeatureInfo, ref _getFeatureInfoRequests, ref _getFeatureInfoOutputFormats); //DescribeLayer XmlNode xnDescribeLayer = xmlRequestNode.SelectSingleNode("sm:DescribeLayer", _nsmgr); ParseRequestTypeBlock(xnDescribeLayer, ref _describeLayerRequests, ref _describeLayerOutputFormats); //GetLegendGraphic XmlNode xnGetLegendGraphic = xmlRequestNode.SelectSingleNode("sm:GetLegendGraphic", _nsmgr); ParseRequestTypeBlock(xnGetLegendGraphic, ref _getLegendGraphicRequests, ref _getLegendGraphicOutputFormats); //GetStyles XmlNode xnGetStyles = xmlRequestNode.SelectSingleNode("sm:GetStyles", _nsmgr); ParseRequestTypeBlock(xnGetStyles, ref _getStylesRequests, ref _getStylesOutputFormats); //PutStyles XmlNode xnPutStyles = xmlRequestNode.SelectSingleNode("sm:PutStyles", _nsmgr); ParseRequestTypeBlock(xnPutStyles, ref _putStylesRequests, ref _putStylesOutputFormats); } /// /// Parses GetMap request nodes /// private void ParseRequestTypeBlock(XmlNode requestNodes, ref WmsOnlineResource[] requestResources, ref Collection outputFormats ) { if (requestNodes != null) { XmlNode xnlHttp = requestNodes.SelectSingleNode("sm:DCPType/sm:HTTP", _nsmgr); if (xnlHttp != null && xnlHttp.HasChildNodes) { requestResources = new WmsOnlineResource[xnlHttp.ChildNodes.Count]; for (int i = 0; i < xnlHttp.ChildNodes.Count; i++) { WmsOnlineResource wor = new WmsOnlineResource(); wor.Type = xnlHttp.ChildNodes[i].Name; XmlNode or = xnlHttp.ChildNodes[i].SelectSingleNode("sm:OnlineResource", _nsmgr); if (or == null || or.Attributes == null) throw new ApplicationException("Online resource not set"); wor.OnlineResource = or.Attributes["xlink:href"].InnerText; requestResources[i] = wor; } } outputFormats = new Collection(); XmlNodeList xnlFormats = requestNodes.SelectNodes("sm:Format", _nsmgr); if (xnlFormats != null) for (int i = 0; i < xnlFormats.Count; i++) outputFormats.Add(xnlFormats[i].InnerText); } else { requestResources = null; outputFormats = null; } } /// /// Iterates through the layer nodes recursively /// /// /// private WmsServerLayer ParseLayer(XmlNode xmlLayer) { WmsServerLayer layer = new WmsServerLayer(); XmlNode node = xmlLayer.SelectSingleNode("sm:Name", _nsmgr); layer.Name = (node != null ? node.InnerText : null); node = xmlLayer.SelectSingleNode("sm:Title", _nsmgr); layer.Title = (node != null ? node.InnerText : null); node = xmlLayer.SelectSingleNode("sm:Abstract", _nsmgr); layer.Abstract = (node != null ? node.InnerText : null); if (xmlLayer.Attributes != null) { XmlAttribute attr = xmlLayer.Attributes["queryable"]; layer.Queryable = (attr != null && attr.InnerText == "1"); } else layer.Queryable = false; layer.SRIDBoundingBoxes = new List(); XmlNodeList xnlKeywords = xmlLayer.SelectNodes("sm:KeywordList/sm:Keyword", _nsmgr); if (xnlKeywords != null) { layer.Keywords = new string[xnlKeywords.Count]; for (int i = 0; i < xnlKeywords.Count; i++) layer.Keywords[i] = xnlKeywords[i].InnerText; } XmlNodeList xnlCrs = null; if(_version == "1.1.0" || _version == "1.1.1") xnlCrs = xmlLayer.SelectNodes("sm:SRS", _nsmgr); // <--I think this needs to be version specific else xnlCrs = xmlLayer.SelectNodes("sm:CRS", _nsmgr); if (xnlCrs != null) { layer.CRS = new string[xnlCrs.Count]; for (int i = 0; i < xnlCrs.Count; i++) layer.CRS[i] = xnlCrs[i].InnerText; } XmlNodeList xnlStyle = xmlLayer.SelectNodes("sm:Style", _nsmgr); if (xnlStyle != null) { layer.Style = new WmsLayerStyle[xnlStyle.Count]; for (int i = 0; i < xnlStyle.Count; i++) { node = xnlStyle[i].SelectSingleNode("sm:Name", _nsmgr); layer.Style[i].Name = (node != null ? node.InnerText : null); node = xnlStyle[i].SelectSingleNode("sm:Title", _nsmgr); layer.Style[i].Title = (node != null ? node.InnerText : null); node = xnlStyle[i].SelectSingleNode("sm:Abstract", _nsmgr); layer.Style[i].Abstract = (node != null ? node.InnerText : null); node = xnlStyle[i].SelectSingleNode("sm:LegendUrl", _nsmgr); if (node != null && node.Attributes != null) { layer.Style[i].LegendUrl = new WmsStyleLegend(); layer.Style[i].LegendUrl.Size = new Size( int.Parse(node.Attributes["width"].InnerText), int.Parse(node.Attributes["height"].InnerText)); layer.Style[i].LegendUrl.OnlineResource.OnlineResource = node.SelectSingleNode("sm:OnlineResource", _nsmgr).Attributes["xlink:href"].InnerText; layer.Style[i].LegendUrl.OnlineResource.Type = node.SelectSingleNode("sm:Format", _nsmgr).InnerText; } node = xnlStyle[i].SelectSingleNode("sm:StyleSheetURL", _nsmgr); if (node != null) { layer.Style[i].StyleSheetUrl = new WmsOnlineResource(); layer.Style[i].StyleSheetUrl.OnlineResource = node.SelectSingleNode("sm:OnlineResource", _nsmgr).Attributes["xlink:href"].InnerText; //layer.Style[i].StyleSheetUrl.OnlineResource = node.SelectSingleNode("sm:Format", nsmgr).InnerText; } } } XmlNodeList xnlLayers = xmlLayer.SelectNodes("sm:Layer", _nsmgr); if (xnlLayers != null) { layer.ChildLayers = new WmsServerLayer[xnlLayers.Count]; for (int i = 0; i < xnlLayers.Count; i++) layer.ChildLayers[i] = ParseLayer(xnlLayers[i]); } //LatLonBoundingBox is specific for WMS 1.1.1 servers node = xmlLayer.SelectSingleNode("sm:LatLonBoundingBox", _nsmgr); if (node != null) { double minx = WebUtilities.ParseNodeAsDouble(node.Attributes["minx"], -180.0); double miny = WebUtilities.ParseNodeAsDouble(node.Attributes["miny"], -90.0); double maxx = WebUtilities.ParseNodeAsDouble(node.Attributes["maxx"], 180.0); double maxy = WebUtilities.ParseNodeAsDouble(node.Attributes["maxy"], 90.0); layer.LatLonBoundingBox = new Envelope(minx, maxx, miny, maxy); } else { //EX_GeographicBoundingBox is specific for WMS 1.3.0 servers node = xmlLayer.SelectSingleNode("sm:EX_GeographicBoundingBox", _nsmgr); if (node != null) { //EX_GeographicBoundingBox is specific for WMS1.3.0 servers so this will be parsed if LatLonBoundingBox is null double minx = WebUtilities.ParseNodeAsDouble(node.SelectSingleNode("sm:westBoundLongitude", _nsmgr), -180.0); double miny = WebUtilities.ParseNodeAsDouble(node.SelectSingleNode("sm:southBoundLatitude", _nsmgr), -90.0); double maxx = WebUtilities.ParseNodeAsDouble(node.SelectSingleNode("sm:eastBoundLongitude", _nsmgr), 180.0); double maxy = WebUtilities.ParseNodeAsDouble(node.SelectSingleNode("sm:northBoundLatitude", _nsmgr), 90.0); layer.LatLonBoundingBox = new Envelope(minx, maxx, miny, maxy); } else { //Not sure what to do in this case. PDD. layer.LatLonBoundingBox = null; } } //if the layer has a specific spatial reference system, the boundingbox in this reference system should be parsed and placed in //the SRIDboundingbox XmlNodeList bboxes = xmlLayer.SelectNodes("sm:BoundingBox", _nsmgr); foreach (XmlNode bbox in bboxes) { double minx; double miny; double maxx; double maxy; int epsg; if (!WebUtilities.TryParseNodeAsDouble(bbox.Attributes["minx"], out minx)) continue; if (!WebUtilities.TryParseNodeAsDouble(bbox.Attributes["miny"], out miny)) continue; if (!WebUtilities.TryParseNodeAsDouble(bbox.Attributes["maxx"], out maxx)) continue; if (!WebUtilities.TryParseNodeAsDouble(bbox.Attributes["maxy"], out maxy)) continue; if (!WebUtilities.TryParseNodeAsEpsg(WebUtilities.FindEpsgNode(bbox), out epsg)) continue; layer.SRIDBoundingBoxes.Add(new SpatialReferencedBoundingBox(minx, miny, maxx, maxy, epsg)); } return layer; } /// /// /// public void ValidateXml() { try { // Now create StringWriter object to get data from xml document. var sw = new StringWriter(); var xw = new XmlTextWriter(sw); _xmlDoc.WriteTo(xw); var settings = new XmlReaderSettings(); switch (_version) { case "1.1.0": //settings.ProhibitDtd = false; settings.DtdProcessing = DtdProcessing.Parse; settings.ValidationType = ValidationType.DTD; break; case "1.1.1": //settings.ProhibitDtd = false; settings.DtdProcessing = DtdProcessing.Parse; settings.ValidationType = ValidationType.DTD; break; case "1.3.0": settings.Schemas.Add("http://www.opengis.net/wms", "http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd"); settings.ValidationType = ValidationType.Schema; break; default: if (logger.IsInfoEnabled) logger.Info("Invalid selection: " + _version); break; } settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings; settings.ValidationEventHandler += new ValidationEventHandler(delegate(object sender, ValidationEventArgs args) { throw new ApplicationException("Could not validate the WMS capabilities file completely. Here is the validation error message..." + args.Message); }); //TextReader, XMLReader, URL, Stream var xmlStream = (TextReader)new StringReader(sw.ToString()); var reader = XmlReader.Create(xmlStream, settings); while (reader.Read()); } catch (Exception ex) { throw new ApplicationException("Could not validate the WMS capabilities file for this version of the capabilities file. Here is the validation error message..." + ex.Message, ex); } } /// /// /// /// /// public string CreateCapabilitiesUrl(string url) { var strReq = new StringBuilder(url); if (!url.Contains("?")) strReq.Append("?"); if (!strReq.ToString().EndsWith("&") && !strReq.ToString().EndsWith("?")) strReq.Append("&"); if (!url.ToLower().Contains("service=wms")) strReq.AppendFormat("SERVICE=WMS&"); if (!url.ToLower().Contains("request=getcapabilities")) strReq.AppendFormat("REQUEST=GetCapabilities&"); //If version is NOT set at this point then add to query string if(_version != "") strReq.AppendFormat("VERSION=" + _version + "&"); return strReq.ToString(); } /// /// Just parse the version number and add to the version property /// public void ParseVersion() { if (_xmlDoc.DocumentElement != null) { if (_xmlDoc.DocumentElement.Attributes["version"] != null) { _version = _xmlDoc.DocumentElement.Attributes["version"].Value; if (_version != "1.0.0" && _version != "1.1.0" && _version != "1.1.1" && _version != "1.3.0") throw new ApplicationException("WMS Version " + _version + " is not currently supported"); } else throw (new ApplicationException("No service version number was found in the capabilities XML file!")); } } #endregion } }