From 5e298304625d0af24d3fff518583f08b49c4bb9e Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Tue, 19 Feb 2013 16:32:56 +0100 Subject: [PATCH] Add WMTS GetCapabilities parser Implements WMTS GetCapabilities parser, which depends partly on an OWSCommon parser. Integration with the layer source will be done at a later stage. --- src/ol/coordinate.js | 16 ++ src/ol/parser/ogc/owscommon_v1.js | 214 ++++++++++++++++++ src/ol/parser/ogc/owscommon_v1_1_0.js | 45 ++++ src/ol/parser/ogc/wmtscapabilities.exports | 2 + src/ol/parser/ogc/wmtscapabilities.js | 19 ++ src/ol/parser/ogc/wmtscapabilities_v1_0_0.js | 161 +++++++++++++ src/ol/parser/xml.js | 6 + src/ol/projection.js | 22 +- .../ogc/wmtscapabilities_v1_0_0.test.js | 183 +++++++++++++++ .../xml/wmtscapabilities_v1_0_0/arcgis.xml | 70 ++++++ .../multi-getile-1.xml | 92 ++++++++ .../multi-getile-2.xml | 78 +++++++ .../xml/wmtscapabilities_v1_0_0/ogcsample.xml | 158 +++++++++++++ .../restsample-alternate-proj1.xml | 72 ++++++ .../restsample-alternate-proj2.xml | 72 ++++++ .../wmtscapabilities_v1_0_0/restsample.xml | 126 +++++++++++ 16 files changed, 1334 insertions(+), 2 deletions(-) create mode 100644 src/ol/parser/ogc/owscommon_v1.js create mode 100644 src/ol/parser/ogc/owscommon_v1_1_0.js create mode 100644 src/ol/parser/ogc/wmtscapabilities.exports create mode 100644 src/ol/parser/ogc/wmtscapabilities.js create mode 100644 src/ol/parser/ogc/wmtscapabilities_v1_0_0.js create mode 100644 test/spec/ol/parser/ogc/wmtscapabilities_v1_0_0.test.js create mode 100644 test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/arcgis.xml create mode 100644 test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/multi-getile-1.xml create mode 100644 test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/multi-getile-2.xml create mode 100644 test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/ogcsample.xml create mode 100644 test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/restsample-alternate-proj1.xml create mode 100644 test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/restsample-alternate-proj2.xml create mode 100644 test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/restsample.xml diff --git a/src/ol/coordinate.js b/src/ol/coordinate.js index b3bd66b10c..dcf4832038 100644 --- a/src/ol/coordinate.js +++ b/src/ol/coordinate.js @@ -88,3 +88,19 @@ ol.Coordinate.toStringXY = function(coordinate, opt_precision) { return ''; } }; + + +/** + * Create an ol.Coordinate from an Array and take into account axis order. + * @param {Array} array The array with coordinates. + * @param {string} axis the axis info. + * @return {ol.Coordinate} The coordinate created. + */ +ol.Coordinate.fromProjectedArray = function(array, axis) { + var firstAxis = axis.charAt(0); + if (firstAxis === 'n' || firstAxis === 's') { + return new ol.Coordinate(array[1], array[0]); + } else { + return new ol.Coordinate(array[0], array[1]); + } +}; diff --git a/src/ol/parser/ogc/owscommon_v1.js b/src/ol/parser/ogc/owscommon_v1.js new file mode 100644 index 0000000000..ae01b4ec93 --- /dev/null +++ b/src/ol/parser/ogc/owscommon_v1.js @@ -0,0 +1,214 @@ +goog.provide('ol.parser.ogc.OWSCommon_v1'); +goog.require('ol.Extent'); +goog.require('ol.parser.XML'); + + + +/** + * @constructor + * @extends {ol.parser.XML} + */ +ol.parser.ogc.OWSCommon_v1 = function() { + this.readers = { + 'http://www.opengis.net/ows': { + 'ServiceIdentification': function(node, obj) { + obj['serviceIdentification'] = {}; + this.readChildNodes(node, obj['serviceIdentification']); + }, + 'Title': function(node, obj) { + obj['title'] = this.getChildValue(node); + }, + 'Abstract': function(node, serviceIdentification) { + serviceIdentification['abstract'] = this.getChildValue(node); + }, + 'Keywords': function(node, serviceIdentification) { + serviceIdentification['keywords'] = {}; + this.readChildNodes(node, serviceIdentification['keywords']); + }, + 'Keyword': function(node, keywords) { + keywords[this.getChildValue(node)] = true; + }, + 'ServiceType': function(node, serviceIdentification) { + serviceIdentification['serviceType'] = { + 'codeSpace': node.getAttribute('codeSpace'), + 'value': this.getChildValue(node)}; + }, + 'ServiceTypeVersion': function(node, serviceIdentification) { + serviceIdentification['serviceTypeVersion'] = this.getChildValue(node); + }, + 'Fees': function(node, serviceIdentification) { + serviceIdentification['fees'] = this.getChildValue(node); + }, + 'AccessConstraints': function(node, serviceIdentification) { + serviceIdentification['accessConstraints'] = + this.getChildValue(node); + }, + 'ServiceProvider': function(node, obj) { + obj['serviceProvider'] = {}; + this.readChildNodes(node, obj['serviceProvider']); + }, + 'ProviderName': function(node, serviceProvider) { + serviceProvider['providerName'] = this.getChildValue(node); + }, + 'ProviderSite': function(node, serviceProvider) { + serviceProvider['providerSite'] = this.getAttributeNS(node, + 'http://www.w3.org/1999/xlink', 'href'); + }, + 'ServiceContact': function(node, serviceProvider) { + serviceProvider['serviceContact'] = {}; + this.readChildNodes(node, serviceProvider['serviceContact']); + }, + 'IndividualName': function(node, serviceContact) { + serviceContact['individualName'] = this.getChildValue(node); + }, + 'PositionName': function(node, serviceContact) { + serviceContact['positionName'] = this.getChildValue(node); + }, + 'ContactInfo': function(node, serviceContact) { + serviceContact['contactInfo'] = {}; + this.readChildNodes(node, serviceContact['contactInfo']); + }, + 'Phone': function(node, contactInfo) { + contactInfo['phone'] = {}; + this.readChildNodes(node, contactInfo['phone']); + }, + 'Voice': function(node, phone) { + phone['voice'] = this.getChildValue(node); + }, + 'Address': function(node, contactInfo) { + contactInfo['address'] = {}; + this.readChildNodes(node, contactInfo['address']); + }, + 'DeliveryPoint': function(node, address) { + address['deliveryPoint'] = this.getChildValue(node); + }, + 'City': function(node, address) { + address['city'] = this.getChildValue(node); + }, + 'AdministrativeArea': function(node, address) { + address['administrativeArea'] = this.getChildValue(node); + }, + 'PostalCode': function(node, address) { + address['postalCode'] = this.getChildValue(node); + }, + 'Country': function(node, address) { + address['country'] = this.getChildValue(node); + }, + 'ElectronicMailAddress': function(node, address) { + address['electronicMailAddress'] = this.getChildValue(node); + }, + 'Role': function(node, serviceContact) { + serviceContact['role'] = this.getChildValue(node); + }, + 'OperationsMetadata': function(node, obj) { + obj['operationsMetadata'] = {}; + this.readChildNodes(node, obj['operationsMetadata']); + }, + 'Operation': function(node, operationsMetadata) { + var name = node.getAttribute('name'); + operationsMetadata[name] = {}; + this.readChildNodes(node, operationsMetadata[name]); + }, + 'DCP': function(node, operation) { + operation['dcp'] = {}; + this.readChildNodes(node, operation['dcp']); + }, + 'HTTP': function(node, dcp) { + dcp['http'] = {}; + this.readChildNodes(node, dcp['http']); + }, + 'Get': function(node, http) { + if (!http['get']) { + http['get'] = []; + } + var obj = { + 'url': this.getAttributeNS(node, 'http://www.w3.org/1999/xlink', + 'href') + }; + this.readChildNodes(node, obj); + http['get'].push(obj); + }, + 'Post': function(node, http) { + if (!http['post']) { + http['post'] = []; + } + var obj = { + 'url': this.getAttributeNS(node, 'http://www.w3.org/1999/xlink', + 'href') + }; + this.readChildNodes(node, obj); + http['post'].push(obj); + }, + 'Parameter': function(node, operation) { + if (!operation['parameters']) { + operation['parameters'] = {}; + } + var name = node.getAttribute('name'); + operation['parameters'][name] = {}; + this.readChildNodes(node, operation['parameters'][name]); + }, + 'Constraint': function(node, obj) { + if (!obj['constraints']) { + obj['constraints'] = {}; + } + var name = node.getAttribute('name'); + obj['constraints'][name] = {}; + this.readChildNodes(node, obj['constraints'][name]); + }, + 'Value': function(node, allowedValues) { + allowedValues[this.getChildValue(node)] = true; + }, + 'OutputFormat': function(node, obj) { + obj['formats'].push({'value': this.getChildValue(node)}); + this.readChildNodes(node, obj); + }, + 'WGS84BoundingBox': function(node, obj) { + var boundingBox = {}; + boundingBox['crs'] = node.getAttribute('crs'); + if (obj['BoundingBox']) { + obj['BoundingBox'].push(boundingBox); + } else { + obj['projection'] = boundingBox['crs']; + boundingBox = obj; + } + this.readChildNodes(node, boundingBox); + }, + 'BoundingBox': function(node, obj) { + // FIXME: We consider that BoundingBox is the same as WGS84BoundingBox + // LowerCorner = "min_x min_y" + // UpperCorner = "max_x max_y" + // It should normally depend on the projection + var readers = this.readers['http://www.opengis.net/ows']; + readers['WGS84BoundingBox'].apply(this, [node, obj]); + }, + 'LowerCorner': function(node, obj) { + var str = this.getChildValue(node).replace( + this.regExes.trimSpace, ''); + str = str.replace(this.regExes.trimComma, ','); + var pointList = str.split(this.regExes.splitSpace); + obj['left'] = pointList[0]; + obj['bottom'] = pointList[1]; + }, + 'UpperCorner': function(node, obj) { + var str = this.getChildValue(node).replace( + this.regExes.trimSpace, ''); + str = str.replace(this.regExes.trimComma, ','); + var pointList = str.split(this.regExes.splitSpace); + obj['right'] = pointList[0]; + obj['top'] = pointList[1]; + obj['bounds'] = new ol.Extent(parseFloat(obj['left']), + parseFloat(obj['bottom']), parseFloat(obj['right']), + parseFloat(obj['top'])); + delete obj['left']; + delete obj['bottom']; + delete obj['right']; + delete obj['top']; + }, + 'Language': function(node, obj) { + obj['language'] = this.getChildValue(node); + } + } + }; + goog.base(this); +}; +goog.inherits(ol.parser.ogc.OWSCommon_v1, ol.parser.XML); diff --git a/src/ol/parser/ogc/owscommon_v1_1_0.js b/src/ol/parser/ogc/owscommon_v1_1_0.js new file mode 100644 index 0000000000..98c7bfc016 --- /dev/null +++ b/src/ol/parser/ogc/owscommon_v1_1_0.js @@ -0,0 +1,45 @@ +goog.provide('ol.parser.ogc.OWSCommon_v1_1_0'); +goog.require('goog.object'); +goog.require('ol.parser.ogc.OWSCommon_v1'); + + + +/** + * @constructor + * @extends {ol.parser.ogc.OWSCommon_v1} + */ +ol.parser.ogc.OWSCommon_v1_1_0 = function() { + goog.base(this); + this.readers['http://www.opengis.net/ows/1.1'] = + this.readers['http://www.opengis.net/ows']; + goog.object.extend(this.readers['http://www.opengis.net/ows/1.1'], { + 'AllowedValues': function(node, parameter) { + parameter['allowedValues'] = {}; + this.readChildNodes(node, parameter['allowedValues']); + }, + 'AnyValue': function(node, parameter) { + parameter['anyValue'] = true; + }, + 'DataType': function(node, parameter) { + parameter['dataType'] = this.getChildValue(node); + }, + 'Range': function(node, allowedValues) { + allowedValues['range'] = {}; + this.readChildNodes(node, allowedValues['range']); + }, + 'MinimumValue': function(node, range) { + range['minValue'] = this.getChildValue(node); + }, + 'MaximumValue': function(node, range) { + range['maxValue'] = this.getChildValue(node); + }, + 'Identifier': function(node, obj) { + obj['identifier'] = this.getChildValue(node); + }, + 'SupportedCRS': function(node, obj) { + obj['supportedCRS'] = this.getChildValue(node); + } + }); +}; +goog.inherits(ol.parser.ogc.OWSCommon_v1_1_0, + ol.parser.ogc.OWSCommon_v1); diff --git a/src/ol/parser/ogc/wmtscapabilities.exports b/src/ol/parser/ogc/wmtscapabilities.exports new file mode 100644 index 0000000000..dec7a65f4e --- /dev/null +++ b/src/ol/parser/ogc/wmtscapabilities.exports @@ -0,0 +1,2 @@ +@exportSymbol ol.parser.ogc.WMTSCapabilities +@exportProperty ol.parser.ogc.WMTSCapabilities.prototype.read diff --git a/src/ol/parser/ogc/wmtscapabilities.js b/src/ol/parser/ogc/wmtscapabilities.js new file mode 100644 index 0000000000..fee0293153 --- /dev/null +++ b/src/ol/parser/ogc/wmtscapabilities.js @@ -0,0 +1,19 @@ +goog.provide('ol.parser.ogc.WMTSCapabilities'); +goog.require('ol.parser.ogc.Versioned'); +goog.require('ol.parser.ogc.WMTSCapabilities_v1_0_0'); + + + +/** + * @constructor + * @param {Object=} opt_options Options which will be set on this object. + * @extends {ol.parser.ogc.Versioned} + */ +ol.parser.ogc.WMTSCapabilities = function(opt_options) { + opt_options = opt_options || {}; + opt_options['defaultVersion'] = '1.0.0'; + this.parsers = {}; + this.parsers['v1_0_0'] = ol.parser.ogc.WMTSCapabilities_v1_0_0; + goog.base(this, opt_options); +}; +goog.inherits(ol.parser.ogc.WMTSCapabilities, ol.parser.ogc.Versioned); diff --git a/src/ol/parser/ogc/wmtscapabilities_v1_0_0.js b/src/ol/parser/ogc/wmtscapabilities_v1_0_0.js new file mode 100644 index 0000000000..cade9332f8 --- /dev/null +++ b/src/ol/parser/ogc/wmtscapabilities_v1_0_0.js @@ -0,0 +1,161 @@ +goog.provide('ol.parser.ogc.WMTSCapabilities_v1_0_0'); +goog.require('goog.dom.xml'); +goog.require('ol.Coordinate'); +goog.require('ol.Projection'); +goog.require('ol.parser.XML'); +goog.require('ol.parser.ogc.OWSCommon_v1_1_0'); + + + +/** + * @constructor + * @extends {ol.parser.XML} + */ +ol.parser.ogc.WMTSCapabilities_v1_0_0 = function() { + this.readers = { + 'http://www.opengis.net/wmts/1.0': { + 'Capabilities': function(node, obj) { + this.readChildNodes(node, obj); + }, + 'Contents': function(node, obj) { + obj['contents'] = {}; + obj['contents']['layers'] = []; + obj['contents']['tileMatrixSets'] = {}; + this.readChildNodes(node, obj['contents']); + }, + 'Layer': function(node, obj) { + var layer = { + 'styles': [], + 'formats': [], + 'dimensions': [], + 'tileMatrixSetLinks': [] + }; + layer['layers'] = []; + this.readChildNodes(node, layer); + obj['layers'].push(layer); + }, + 'Style': function(node, obj) { + var style = {}; + style['isDefault'] = (node.getAttribute('isDefault') === 'true'); + this.readChildNodes(node, style); + obj['styles'].push(style); + }, + 'Format': function(node, obj) { + obj['formats'].push(this.getChildValue(node)); + }, + 'TileMatrixSetLink': function(node, obj) { + var tileMatrixSetLink = {}; + this.readChildNodes(node, tileMatrixSetLink); + obj['tileMatrixSetLinks'].push(tileMatrixSetLink); + }, + 'TileMatrixSet': function(node, obj) { + // node could be child of wmts:Contents or wmts:TileMatrixSetLink + // duck type wmts:Contents by looking for layers + if (obj['layers']) { + // TileMatrixSet as object type in schema + var tileMatrixSet = { + 'matrixIds': [] + }; + this.readChildNodes(node, tileMatrixSet); + obj['tileMatrixSets'][tileMatrixSet['identifier']] = tileMatrixSet; + } else { + // TileMatrixSet as string type in schema + obj['tileMatrixSet'] = this.getChildValue(node); + } + }, + 'TileMatrix': function(node, obj) { + var tileMatrix = { + 'supportedCRS': obj.supportedCRS + }; + this.readChildNodes(node, tileMatrix); + obj['matrixIds'].push(tileMatrix); + }, + 'ScaleDenominator': function(node, obj) { + obj['scaleDenominator'] = parseFloat(this.getChildValue(node)); + }, + 'TopLeftCorner': function(node, obj) { + var topLeftCorner = this.getChildValue(node); + var coords = topLeftCorner.split(' '); + var axis = ol.Projection.getFromCode(obj['supportedCRS']).getAxis(); + obj['topLeftCorner'] = ol.Coordinate.fromProjectedArray( + [parseFloat(coords[0]), parseFloat(coords[1])], axis); + }, + 'TileWidth': function(node, obj) { + obj['tileWidth'] = parseInt(this.getChildValue(node), 10); + }, + 'TileHeight': function(node, obj) { + obj['tileHeight'] = parseInt(this.getChildValue(node), 10); + }, + 'MatrixWidth': function(node, obj) { + obj['matrixWidth'] = parseInt(this.getChildValue(node), 10); + }, + 'MatrixHeight': function(node, obj) { + obj['matrixHeight'] = parseInt(this.getChildValue(node), 10); + }, + 'ResourceURL': function(node, obj) { + obj['resourceUrl'] = obj['resourceUrl'] || {}; + var resourceType = node.getAttribute('resourceType'); + if (!obj['resourceUrls']) { + obj['resourceUrls'] = []; + } + var resourceUrl = obj['resourceUrl'][resourceType] = { + 'format': node.getAttribute('format'), + 'template': node.getAttribute('template'), + 'resourceType': resourceType + }; + obj['resourceUrls'].push(resourceUrl); + }, + 'WSDL': function(node, obj) { + obj['wsdl'] = {}; + obj['wsdl']['href'] = this.getAttributeNS(node, + 'http://www.w3.org/1999/xlink', 'href'); + // TODO: other attributes of element + }, + 'ServiceMetadataURL': function(node, obj) { + obj['serviceMetadataUrl'] = {}; + obj['serviceMetadataUrl']['href'] = + this.getAttributeNS(node, 'http://www.w3.org/1999/xlink', 'href'); + // TODO: other attributes of element + }, + 'LegendURL': function(node, obj) { + obj['legend'] = {}; + obj['legend']['href'] = this.getAttributeNS(node, + 'http://www.w3.org/1999/xlink', 'href'); + obj['legend']['format'] = node.getAttribute('format'); + }, + 'Dimension': function(node, obj) { + var dimension = {'values': []}; + this.readChildNodes(node, dimension); + obj['dimensions'].push(dimension); + }, + 'Default': function(node, obj) { + obj['default'] = this.getChildValue(node); + }, + 'Value': function(node, obj) { + obj['values'].push(this.getChildValue(node)); + } + } + }; + var ows = new ol.parser.ogc.OWSCommon_v1_1_0(); + this.readers['http://www.opengis.net/ows/1.1'] = + ows.readers['http://www.opengis.net/ows/1.1']; + goog.base(this); +}; +goog.inherits(ol.parser.ogc.WMTSCapabilities_v1_0_0, ol.parser.XML); + + +/** + * @param {string|Document|Element} data Data to read. + * @return {Object} An object representing the document. + */ +ol.parser.ogc.WMTSCapabilities_v1_0_0.prototype.read = function(data) { + if (typeof data == 'string') { + data = goog.dom.xml.loadXml(data); + } + if (data && data.nodeType == 9) { + data = data.documentElement; + } + var obj = {}; + this.readNode(data, obj); + return obj; +}; diff --git a/src/ol/parser/xml.js b/src/ol/parser/xml.js index d0df3ab763..6e07cf645c 100644 --- a/src/ol/parser/xml.js +++ b/src/ol/parser/xml.js @@ -6,6 +6,12 @@ goog.provide('ol.parser.XML'); * @constructor */ ol.parser.XML = function() { + this.regExes = { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }; }; diff --git a/src/ol/projection.js b/src/ol/projection.js index df23c5fb68..d6c57812a0 100644 --- a/src/ol/projection.js +++ b/src/ol/projection.js @@ -36,8 +36,9 @@ ol.ProjectionUnits = { * @param {string} code Code. * @param {ol.ProjectionUnits} units Units. * @param {ol.Extent} extent Extent. + * @param {string=} opt_axis Axis order. */ -ol.Projection = function(code, units, extent) { +ol.Projection = function(code, units, extent, opt_axis) { /** * @private @@ -57,6 +58,12 @@ ol.Projection = function(code, units, extent) { */ this.extent_ = extent; + /** + * @private + * @type {string} + */ + this.axis_ = opt_axis || 'enu'; + }; @@ -84,6 +91,14 @@ ol.Projection.prototype.getUnits = function() { }; +/** + * @return {string} Axis. + */ +ol.Projection.prototype.getAxis = function() { + return this.axis_; +}; + + /** * @constructor @@ -526,6 +541,7 @@ ol.Projection.EPSG_4326_EXTENT_ = new ol.Extent(-180, -90, 180, 90); */ ol.Projection.EPSG_4326_LIKE_CODES_ = [ 'CRS:84', + 'urn:ogc:def:crs:OGC:1.3:CRS84', 'EPSG:4326', 'urn:ogc:def:crs:EPSG:6.6:4326' ]; @@ -543,7 +559,9 @@ ol.Projection.EPSG_4326_LIKE_PROJECTIONS = goog.array.map( return new ol.Projection( code, ol.ProjectionUnits.DEGREES, - ol.Projection.EPSG_4326_EXTENT_); + ol.Projection.EPSG_4326_EXTENT_, + code === 'CRS:84' || code === 'urn:ogc:def:crs:OGC:1.3:CRS84' ? + 'enu' : 'neu'); }); diff --git a/test/spec/ol/parser/ogc/wmtscapabilities_v1_0_0.test.js b/test/spec/ol/parser/ogc/wmtscapabilities_v1_0_0.test.js new file mode 100644 index 0000000000..af7b43cd8d --- /dev/null +++ b/test/spec/ol/parser/ogc/wmtscapabilities_v1_0_0.test.js @@ -0,0 +1,183 @@ +goog.provide('ol.test.parser.ogc.WMTSCapabilities_v1_0_0'); + +describe('ol.parser.ogc.wmtscapabilities_v1_0_0', function() { + + var parser = new ol.parser.ogc.WMTSCapabilities(); + + describe('test ows', function() { + it('Test ows', function() { + var obj, serviceIdentification, serviceProvider, operationsMetadata, + contactInfo; + runs(function() { + var url = 'spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/' + + 'ogcsample.xml'; + goog.net.XhrIo.send(url, function(e) { + var xhr = e.target; + obj = parser.read(xhr.getResponseXml()); + serviceIdentification = obj.serviceIdentification; + serviceProvider = obj.serviceProvider; + operationsMetadata = obj.operationsMetadata; + contactInfo = serviceProvider.serviceContact.contactInfo; + }); + }); + waitsFor(function() { + return (obj !== undefined); + }, 'XHR timeout', 1000); + runs(function() { + expect(serviceIdentification.title).toEqual('Web Map Tile Service'); + expect(serviceIdentification.serviceTypeVersion).toEqual('1.0.0'); + expect(serviceIdentification.serviceType.value).toEqual('OGC WMTS'); + expect(serviceProvider.providerName).toEqual('MiraMon'); + var url = 'http://www.creaf.uab.es/miramon'; + expect(serviceProvider.providerSite).toEqual(url); + var name = 'Joan Maso Pau'; + expect(serviceProvider.serviceContact.individualName).toEqual(name); + var position = 'Senior Software Engineer'; + expect(serviceProvider.serviceContact.positionName).toEqual(position); + expect(contactInfo.address.administrativeArea).toEqual('Barcelona'); + expect(contactInfo.address.city).toEqual('Bellaterra'); + expect(contactInfo.address.country).toEqual('Spain'); + expect(contactInfo.address.deliveryPoint).toEqual('Fac Ciencies UAB'); + var email = 'joan.maso@uab.es'; + expect(contactInfo.address.electronicMailAddress).toEqual(email); + expect(contactInfo.address.postalCode).toEqual('08193'); + expect(contactInfo.phone.voice).toEqual('+34 93 581 1312'); + var dcp = operationsMetadata.GetCapabilities.dcp; + url = 'http://www.miramon.uab.es/cgi-bin/MiraMon5_0.cgi?'; + expect(dcp.http.get[0].url).toEqual(url); + dcp = operationsMetadata.GetCapabilities.dcp; + expect(dcp.http.get[0].constraints.GetEncoding.allowedValues).toEqual( + {'KVP': true}); + url = 'http://www.miramon.uab.es/cgi-bin/MiraMon5_0.cgi?'; + dcp = operationsMetadata.GetFeatureInfo.dcp; + expect(dcp.http.get[0].url).toEqual(url); + dcp = operationsMetadata.GetFeatureInfo.dcp; + expect(dcp.http.get[0].constraints).toBeUndefined(); + url = 'http://www.miramon.uab.es/cgi-bin/MiraMon5_0.cgi?'; + expect(operationsMetadata.GetTile.dcp.http.get[0].url).toEqual(url); + dcp = operationsMetadata.GetTile.dcp; + expect(dcp.http.get[0].constraints).toBeUndefined(); + }); + }); + }); + describe('test layers', function() { + it('Test layers', function() { + var obj, contents, layer, wgs84Bbox, dimensions; + runs(function() { + var url = 'spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/' + + 'ogcsample.xml'; + goog.net.XhrIo.send(url, function(e) { + var xhr = e.target; + obj = parser.read(xhr.getResponseXml()); + contents = obj.contents; + layer = contents.layers[0]; + wgs84Bbox = layer.bounds; + dimensions = layer.dimensions; + }); + }); + waitsFor(function() { + return (obj !== undefined); + }, 'XHR timeout', 1000); + runs(function() { + expect(contents.layers.length).toEqual(1); + expect(layer['abstract']).toEqual('Coastline/shorelines (BA010)'); + expect(layer.identifier).toEqual('coastlines'); + expect(layer.title).toEqual('Coastlines'); + expect(layer.formats.length).toEqual(2); + expect(layer.formats[0]).toEqual('image/png'); + expect(layer.formats[1]).toEqual('image/gif'); + expect(layer.styles.length).toEqual(2); + expect(layer.styles[0].identifier).toEqual('DarkBlue'); + expect(layer.styles[0].isDefault).toBeTruthy(); + expect(layer.styles[0].title).toEqual('Dark Blue'); + var url = 'http://www.miramon.uab.es/wmts/Coastlines/' + + 'coastlines_darkBlue.png'; + expect(layer.styles[0].legend.href).toEqual(url); + expect(layer.styles[0].legend.format).toEqual('image/png'); + expect(layer.styles[1].identifier).toEqual('thickAndRed'); + expect(!layer.styles[1].isDefault).toBeTruthy(); + expect(layer.styles[1].title).toEqual('Thick And Red'); + expect(layer.styles[1].legend).toBeUndefined(); + expect(layer.tileMatrixSetLinks.length).toEqual(1); + expect(layer.tileMatrixSetLinks[0].tileMatrixSet).toEqual('BigWorld'); + expect(wgs84Bbox instanceof ol.Extent).toBeTruthy(); + expect(wgs84Bbox.minX).toEqual(-180.0); + expect(wgs84Bbox.maxX).toEqual(180.0); + expect(wgs84Bbox.minY).toEqual(-90.0); + expect(wgs84Bbox.maxY).toEqual(90.0); + expect(layer.resourceUrl.tile.format).toEqual('image/png'); + var tpl = 'http://www.example.com/wmts/coastlines/{TileMatrix}/' + + '{TileRow}/{TileCol}.png'; + expect(layer.resourceUrl.tile.template).toEqual(tpl); + var format = 'application/gml+xml; version=3.1'; + expect(layer.resourceUrl.FeatureInfo.format).toEqual(format); + tpl = 'http://www.example.com/wmts/coastlines/{TileMatrixSet}/' + + '{TileMatrix}/{TileRow}/{TileCol}/{J}/{I}.xml'; + expect(layer.resourceUrl.FeatureInfo.template).toEqual(tpl); + expect(layer.resourceUrls[0].format).toEqual('image/png'); + expect(layer.resourceUrls[0].resourceType).toEqual('tile'); + tpl = 'http://www.example.com/wmts/coastlines/{TileMatrix}/' + + '{TileRow}/{TileCol}.png'; + expect(layer.resourceUrls[0].template).toEqual(tpl); + format = 'application/gml+xml; version=3.1'; + expect(layer.resourceUrls[1].format).toEqual(format); + expect(layer.resourceUrls[1].resourceType).toEqual('FeatureInfo'); + tpl = 'http://www.example.com/wmts/coastlines/{TileMatrixSet}/' + + '{TileMatrix}/{TileRow}/{TileCol}/{J}/{I}.xml'; + expect(layer.resourceUrls[1].template).toEqual(tpl); + expect(dimensions.length).toEqual(1); + expect(dimensions[0].title).toEqual('Time'); + expect(dimensions[0]['abstract']).toEqual('Monthly datasets'); + expect(dimensions[0].identifier).toEqual('TIME'); + expect(dimensions[0]['default']).toEqual('default'); + expect(dimensions[0].values.length).toEqual(3); + expect(dimensions[0].values[0]).toEqual('2007-05'); + expect(dimensions[0].values[1]).toEqual('2007-06'); + expect(dimensions[0].values[1]).toEqual('2007-06'); + expect(dimensions[0].values[2]).toEqual('2007-07'); + }); + }); + }); + describe('test tileMatrixSets', function() { + it('Test tileMatrixSets', function() { + var obj, tileMatrixSets, bigWorld; + runs(function() { + var url = 'spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/' + + 'ogcsample.xml'; + goog.net.XhrIo.send(url, function(e) { + var xhr = e.target; + obj = parser.read(xhr.getResponseXml()); + tileMatrixSets = obj.contents.tileMatrixSets; + bigWorld = tileMatrixSets['BigWorld']; + }); + }); + waitsFor(function() { + return (obj !== undefined); + }, 'XHR timeout', 1000); + runs(function() { + expect(bigWorld).toBeDefined(); + expect(bigWorld.identifier).toEqual('BigWorld'); + expect(bigWorld.matrixIds.length).toEqual(2); + expect(bigWorld.matrixIds[0].identifier).toEqual('1e6'); + expect(bigWorld.matrixIds[0].matrixHeight).toEqual(50000); + expect(bigWorld.matrixIds[0].matrixWidth).toEqual(60000); + expect(bigWorld.matrixIds[0].scaleDenominator).toEqual(1000000); + expect(bigWorld.matrixIds[0].tileWidth).toEqual(256); + expect(bigWorld.matrixIds[0].tileHeight).toEqual(256); + expect(bigWorld.matrixIds[0].topLeftCorner.x).toEqual(-180); + expect(bigWorld.matrixIds[0].topLeftCorner.y).toEqual(84); + expect(bigWorld.matrixIds[1].identifier).toEqual('2.5e6'); + expect(bigWorld.matrixIds[1].matrixHeight).toEqual(7000); + expect(bigWorld.matrixIds[1].matrixWidth).toEqual(9000); + expect(bigWorld.matrixIds[1].scaleDenominator).toEqual(2500000); + expect(bigWorld.matrixIds[1].tileWidth).toEqual(256); + expect(bigWorld.matrixIds[1].tileHeight).toEqual(256); + expect(bigWorld.matrixIds[1].topLeftCorner.x).toEqual(-180); + expect(bigWorld.matrixIds[1].topLeftCorner.y).toEqual(84); + }); + }); + }); +}); + +goog.require('goog.net.XhrIo'); +goog.require('ol.parser.ogc.WMTSCapabilities'); diff --git a/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/arcgis.xml b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/arcgis.xml new file mode 100644 index 0000000000..50279f5303 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/arcgis.xml @@ -0,0 +1,70 @@ + + + + WorldTimeZones + OGC WMTS + 1.0.0 + + + + + + + + + RESTful + + + + + + + KVP + + + + + + + + + + WorldTimeZones + WorldTimeZones + + -2.0037507067161843E7 -3.024097195838617E7 + 2.0037507067161843E7 3.0240971458386205E7 + + + -179.99999550841463 -88.99999992161119 + 179.99999550841463 88.99999992161118 + + + image/png + + GoogleMapsCompatible + + + + + GoogleMapsCompatible + the wellknown 'GoogleMapsCompatible' tile matrix set defined by OGC WMTS specification + GoogleMapsCompatible + urn:ogc:def:crs:EPSG:6.18:3:3857 + urn:ogc:def:wkss:OGC:1.0:GoogleMapsCompatible + + 5 + 17471320.75089743 + -20037508.34278925 20037508.34278925 + 256 + 256 + 32 + 32 + + + + + diff --git a/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/multi-getile-1.xml b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/multi-getile-1.xml new file mode 100644 index 0000000000..f4c36b969a --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/multi-getile-1.xml @@ -0,0 +1,92 @@ + + + + + + + + + + REST + + + + + + + + + + + + + REST + + + + + + + REST + + + + + + + KVP + + + + + + + KVP + + + + + + + + + + Agglomérations et villes isolées + Les agglomérations et villes isolées (communes non rattachées à une agglomération et comptant au moins 10`000 habitants) font partie des régions d’analyse de la statistique suisse. Ce niveau géographique est défini depuis plus de 100 ans, afin de mesurer l’urbanisation, phénomène fondamental structurant l’organisation du territoire. Sa fonction principale est de permettre une comparaison spatiale entre des espaces urbains inégalement délimités sur le plan institutionnel. Une version ancienne est appliquée pour la première fois en 1930, puis révisée en 1984 et 1990, toujours sur la base des recensements de la population. La version actuelle classe les 2896 communes de Suisse (état 2000) selon leur appartenance ou pas à une agglomération ou ville isolée en fonction de critères statistiques (Etat et évolution de la population, lien de continuité de la zone bâtie, rapport entre population active occupée et population résidante, structure économique et flux de pendulaires). Les agglomérations et les villes isolées forment l`espace urbain, les territoires restant l`espace rural. La définition des agglomérations de l’OFS n’a pas valeur d’obligation légale. + + 5.140242 45.398181 + 11.47757 48.230651 + + ch.are.agglomerationen_isolierte_staedte-2000 + + + image/png + + Time + 20090101 + 20090101 + + + 21781 + + + + 21781 + urn:ogc:def:crs:EPSG:1.0:21781 + + 0 + 14285750.5715 + 420000.0 350000.0 + 256 + 256 + 1 + 1 + + + + + diff --git a/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/multi-getile-2.xml b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/multi-getile-2.xml new file mode 100644 index 0000000000..58f0f61155 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/multi-getile-2.xml @@ -0,0 +1,78 @@ + + + + + + + + + + REST + + + + + + + + + + + + + KVP + + + + + + + REST + + + + + + + + + + Agglomérations et villes isolées + Les agglomérations et villes isolées (communes non rattachées à une agglomération et comptant au moins 10`000 habitants) font partie des régions d’analyse de la statistique suisse. Ce niveau géographique est défini depuis plus de 100 ans, afin de mesurer l’urbanisation, phénomène fondamental structurant l’organisation du territoire. Sa fonction principale est de permettre une comparaison spatiale entre des espaces urbains inégalement délimités sur le plan institutionnel. Une version ancienne est appliquée pour la première fois en 1930, puis révisée en 1984 et 1990, toujours sur la base des recensements de la population. La version actuelle classe les 2896 communes de Suisse (état 2000) selon leur appartenance ou pas à une agglomération ou ville isolée en fonction de critères statistiques (Etat et évolution de la population, lien de continuité de la zone bâtie, rapport entre population active occupée et population résidante, structure économique et flux de pendulaires). Les agglomérations et les villes isolées forment l`espace urbain, les territoires restant l`espace rural. La définition des agglomérations de l’OFS n’a pas valeur d’obligation légale. + + 5.140242 45.398181 + 11.47757 48.230651 + + ch.are.agglomerationen_isolierte_staedte-2000 + + + image/png + + Time + 20090101 + 20090101 + + + 21781 + + + + 21781 + urn:ogc:def:crs:EPSG:1.0:21781 + + 0 + 14285750.5715 + 420000.0 350000.0 + 256 + 256 + 1 + 1 + + + + + diff --git a/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/ogcsample.xml b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/ogcsample.xml new file mode 100644 index 0000000000..9f0f1bc690 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/ogcsample.xml @@ -0,0 +1,158 @@ + + + + Web Map Tile Service + Service that contrains the map access interface to some TileMatrixSets + + tile + tile matrix set + map + + OGC WMTS + 1.0.0 + none + none + + + MiraMon + + + Joan Maso Pau + Senior Software Engineer + + + +34 93 581 1312 + +34 93 581 4151 + + + Fac Ciencies UAB + Bellaterra + Barcelona + 08193 + Spain + joan.maso@uab.es + + + + + + + + + + + + KVP + + + + + + + + + + + + + + + + + + + + + + + + Coastlines + Coastline/shorelines (BA010) + + -180 -90 + 180 90 + + coastlines + + + + + image/png + image/gif + + Time + Monthly datasets + TIME + 2007-05 + 2007-06 + 2007-07 + default + + + BigWorld + + + + BigWorld + urn:ogc:def:crs:OGC:1.3:CRS84 + + 1e6 + 1e6 + -180 84 + 256 + 256 + 60000 + 50000 + + + 2.5e6 + 2.5e6 + -180 84 + 256 + 256 + 9000 + 7000 + + + + + + Foundation + "Digital Chart Of The World" data + Foundation + + Boundaries + Boundaries + coastlines + politicalBoundaries + depthContours + + + Transportation + Transportation + roads + railroads + airports + + + + World Geology + World Geology + worldAgeRockType + worldFaultLines + felsicMagmatic + maficMagmatic + + + diff --git a/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/restsample-alternate-proj1.xml b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/restsample-alternate-proj1.xml new file mode 100644 index 0000000000..5b57b8b2f9 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/restsample-alternate-proj1.xml @@ -0,0 +1,72 @@ + + + + + + + + + + REST + + + + + + + + + + + + + REST + + + + + + + + + + Agglomérations et villes isolées + Les agglomérations et villes isolées (communes non rattachées à une agglomération et comptant au moins 10`000 habitants) font partie des régions d’analyse de la statistique suisse. Ce niveau géographique est défini depuis plus de 100 ans, afin de mesurer l’urbanisation, phénomène fondamental structurant l’organisation du territoire. Sa fonction principale est de permettre une comparaison spatiale entre des espaces urbains inégalement délimités sur le plan institutionnel. Une version ancienne est appliquée pour la première fois en 1930, puis révisée en 1984 et 1990, toujours sur la base des recensements de la population. La version actuelle classe les 2896 communes de Suisse (état 2000) selon leur appartenance ou pas à une agglomération ou ville isolée en fonction de critères statistiques (Etat et évolution de la population, lien de continuité de la zone bâtie, rapport entre population active occupée et population résidante, structure économique et flux de pendulaires). Les agglomérations et les villes isolées forment l`espace urbain, les territoires restant l`espace rural. La définition des agglomérations de l’OFS n’a pas valeur d’obligation légale. + + 5.140242 45.398181 + 11.47757 48.230651 + + ch.are.agglomerationen_isolierte_staedte-2000 + + + image/png + + Time + 20090101 + 20090101 + + + 21781 + + + + + 21781 + urn:ogc:def:crs:EPSG:21781 + + 0 + 14285750.5715 + 420000.0 350000.0 + 256 + 256 + 1 + 1 + + + + + diff --git a/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/restsample-alternate-proj2.xml b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/restsample-alternate-proj2.xml new file mode 100644 index 0000000000..6d73ae4dc5 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/restsample-alternate-proj2.xml @@ -0,0 +1,72 @@ + + + + + + + + + + REST + + + + + + + + + + + + + REST + + + + + + + + + + Agglomérations et villes isolées + Les agglomérations et villes isolées (communes non rattachées à une agglomération et comptant au moins 10`000 habitants) font partie des régions d’analyse de la statistique suisse. Ce niveau géographique est défini depuis plus de 100 ans, afin de mesurer l’urbanisation, phénomène fondamental structurant l’organisation du territoire. Sa fonction principale est de permettre une comparaison spatiale entre des espaces urbains inégalement délimités sur le plan institutionnel. Une version ancienne est appliquée pour la première fois en 1930, puis révisée en 1984 et 1990, toujours sur la base des recensements de la population. La version actuelle classe les 2896 communes de Suisse (état 2000) selon leur appartenance ou pas à une agglomération ou ville isolée en fonction de critères statistiques (Etat et évolution de la population, lien de continuité de la zone bâtie, rapport entre population active occupée et population résidante, structure économique et flux de pendulaires). Les agglomérations et les villes isolées forment l`espace urbain, les territoires restant l`espace rural. La définition des agglomérations de l’OFS n’a pas valeur d’obligation légale. + + 5.140242 45.398181 + 11.47757 48.230651 + + ch.are.agglomerationen_isolierte_staedte-2000 + + + image/png + + Time + 20090101 + 20090101 + + + 21781 + + + + + 21781 + urn:ogc:def:crs:EPSG:1.0:21781 + + 0 + 14285750.5715 + 420000.0 350000.0 + 256 + 256 + 1 + 1 + + + + + diff --git a/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/restsample.xml b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/restsample.xml new file mode 100644 index 0000000000..b7434e4724 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/wmtscapabilities_v1_0_0/restsample.xml @@ -0,0 +1,126 @@ + + + + Federal Geodata Infrastructure of Switzerland + Some Geodata are subject to license and fees + + FGDI + Pixelkarte + Switzerland + + OGC WMTS + 1.0.0 + yes + license + + + swisstopo + + + David Oesch + + + + +41 (0)31 / 963 21 11 + +41 (0)31 / 963 24 59 + + + swisstopo + Bern + BE + 3084 + Switzerland + + + + + + + + + + + + + REST + + + + + + + + + + + + + REST + + + + + + + + + + Agglomérations et villes isolées + Les agglomérations et villes isolées (communes non rattachées à une agglomération et comptant au moins 10`000 habitants) font partie des régions d’analyse de la statistique suisse. Ce niveau géographique est défini depuis plus de 100 ans, afin de mesurer l’urbanisation, phénomène fondamental structurant l’organisation du territoire. Sa fonction principale est de permettre une comparaison spatiale entre des espaces urbains inégalement délimités sur le plan institutionnel. Une version ancienne est appliquée pour la première fois en 1930, puis révisée en 1984 et 1990, toujours sur la base des recensements de la population. La version actuelle classe les 2896 communes de Suisse (état 2000) selon leur appartenance ou pas à une agglomération ou ville isolée en fonction de critères statistiques (Etat et évolution de la population, lien de continuité de la zone bâtie, rapport entre population active occupée et population résidante, structure économique et flux de pendulaires). Les agglomérations et les villes isolées forment l`espace urbain, les territoires restant l`espace rural. La définition des agglomérations de l’OFS n’a pas valeur d’obligation légale. + + 5.140242 45.398181 + 11.47757 48.230651 + + ch.are.agglomerationen_isolierte_staedte-2000 + + + image/png + + Time + 20090101 + 20090101 + + + 21781 + + + + + + 21781 + urn:ogc:def:crs:EPSG::21781 + + 0 + 14285750.5715 + 420000.0 350000.0 + 256 + 256 + 1 + 1 + + + 8 + 7142875.28575 + 420000.0 350000.0 + 256 + 256 + 1 + 1 + + + 12 + 3571437.64288 + 420000.0 350000.0 + 256 + 256 + 2 + 2 + + + + +