diff --git a/src/ol/expr/expression.js b/src/ol/expr/expression.js index 81a511bc26..277364d750 100644 --- a/src/ol/expr/expression.js +++ b/src/ol/expr/expression.js @@ -97,7 +97,14 @@ ol.expr.lib = {}; ol.expr.functions = { EXTENT: 'extent', FID: 'fid', - GEOMETRY_TYPE: 'geometryType' + GEOMETRY_TYPE: 'geometryType', + INTERSECTS: 'intersects', + CONTAINS: 'contains', + DWITHIN: 'dwithin', + WITHIN: 'within', + LIKE: 'like', + IEQ: 'ieq', + INEQ: 'ineq' }; @@ -107,12 +114,16 @@ ol.expr.functions = { * @param {number} maxX Maximum x-coordinate value. * @param {number} minY Minimum y-coordinate value. * @param {number} maxY Maximum y-coordinate value. + * @param {string=} opt_projection Projection of the extent. + * @param {string=} opt_attribute Name of the geometry attribute to use. * @return {boolean} The provided extent intersects the feature's extent. * @this {ol.Feature} */ -ol.expr.lib[ol.expr.functions.EXTENT] = function(minX, maxX, minY, maxY) { +ol.expr.lib[ol.expr.functions.EXTENT] = function(minX, maxX, minY, maxY, + opt_projection, opt_attribute) { var intersects = false; - var geometry = this.getGeometry(); + var geometry = goog.isDef(opt_attribute) ? + this.getAttributes()[opt_attribute] : this.getGeometry(); if (geometry) { intersects = ol.extent.intersects(geometry.getBounds(), [minX, maxX, minY, maxY]); @@ -142,6 +153,75 @@ ol.expr.lib[ol.expr.functions.FID] = function(var_args) { }; +/** + * Determine if a feature attribute is like the provided value. + * @param {string} attribute The name of the attribute to test for. + * @param {string} value The value to test for. + * @param {string} wildCard The wildcard character to use. + * @param {string} singleChar The single character to use. + * @param {string} escapeChar The escape character to use. + * @param {boolean} matchCase Should we match case or not? + * @this {ol.Feature} + */ +ol.expr.lib[ol.expr.functions.LIKE] = function(attribute, value, wildCard, + singleChar, escapeChar, matchCase) { + if (wildCard == '.') { + throw new Error('"." is an unsupported wildCard character for ' + + 'ol.filter.Comparison'); + } + // set UMN MapServer defaults for unspecified parameters + wildCard = goog.isDef(wildCard) ? wildCard : '*'; + singleChar = goog.isDef(singleChar) ? singleChar : '.'; + escapeChar = goog.isDef(escapeChar) ? escapeChar : '!'; + var val; + val = value.replace( + new RegExp('\\' + escapeChar + '(.|$)', 'g'), '\\$1'); + val = value.replace( + new RegExp('\\' + singleChar, 'g'), '.'); + val = value.replace( + new RegExp('\\' + wildCard, 'g'), '.*'); + val = value.replace( + new RegExp('\\\\.\\*', 'g'), '\\' + wildCard); + val = value.replace( + new RegExp('\\\\\\.', 'g'), '\\' + singleChar); + var attributes = this.getAttributes(); + var modifiers = (matchCase === false) ? 'gi' : 'g'; + return new RegExp(val, modifiers).test(attributes[attribute]); +}; + + +/** + * Case insensitive comparison for equality. + * @param {string} attribute Name of the attribute. + * @param {string} value Value to test for equality. + * @this {ol.Feature} + */ +ol.expr.lib[ol.expr.functions.IEQ] = function(attribute, value) { + var attributes = this.getAttributes(); + if (goog.isString(value) && goog.isString(attributes[attribute])) { + return value.toUpperCase() == attributes[attribute].toUpperCase(); + } else { + return value == attributes[attribute]; + } +}; + + +/** + * Case insensitive comparison for non-equality. + * @param {string} attribute Name of the attribute. + * @param {string} value Value to test for non-equality. + * @this {ol.Feature} + */ +ol.expr.lib[ol.expr.functions.INEQ] = function(attribute, value) { + var attributes = this.getAttributes(); + if (goog.isString(value) && goog.isString(attributes[attribute])) { + return value.toUpperCase() == attributes[attribute].toUpperCase(); + } else { + return value != attributes[attribute]; + } +}; + + /** * Determine if a feature's default geometry is of the given type. * @param {ol.geom.GeometryType} type Geometry type. @@ -156,3 +236,31 @@ ol.expr.lib[ol.expr.functions.GEOMETRY_TYPE] = function(type) { } return same; }; + + +ol.expr.lib[ol.expr.functions.INTERSECTS] = function(geom, opt_projection, + opt_attribute) { + throw new Error('Spatial function not implemented: ' + + ol.expr.functions.INTERSECTS); +}; + + +ol.expr.lib[ol.expr.functions.WITHIN] = function(geom, opt_projection, + opt_attribute) { + throw new Error('Spatial function not implemented: ' + + ol.expr.functions.WITHIN); +}; + + +ol.expr.lib[ol.expr.functions.CONTAINS] = function(geom, opt_projeciton, + opt_attribute) { + throw new Error('Spatial function not implemented: ' + + ol.expr.functions.CONTAINS); +}; + + +ol.expr.lib[ol.expr.functions.DWITHIN] = function(geom, distance, units, + opt_projection, opt_attribute) { + throw new Error('Spatial function not implemented: ' + + ol.expr.functions.DWITHIN); +}; diff --git a/src/ol/parser/ogc/filter.js b/src/ol/parser/ogc/filter.js new file mode 100644 index 0000000000..6f1aece8fa --- /dev/null +++ b/src/ol/parser/ogc/filter.js @@ -0,0 +1,37 @@ +goog.provide('ol.parser.ogc.Filter'); +goog.require('ol.parser.ogc.Filter_v1_0_0'); +goog.require('ol.parser.ogc.Filter_v1_1_0'); +goog.require('ol.parser.ogc.Versioned'); + + +/** + * @define {boolean} Whether to enable OGC Filter version 1.0.0. + */ +ol.ENABLE_OGCFILTER_1_0_0 = true; + + +/** + * @define {boolean} Whether to enable OGC Filter version 1.1.0. + */ +ol.ENABLE_OGCFILTER_1_1_0 = true; + + + +/** + * @constructor + * @param {Object=} opt_options Options which will be set on this object. + * @extends {ol.parser.ogc.Versioned} + */ +ol.parser.ogc.Filter = function(opt_options) { + opt_options = opt_options || {}; + opt_options['defaultVersion'] = '1.0.0'; + this.parsers = {}; + if (ol.ENABLE_OGCFILTER_1_0_0) { + this.parsers['v1_0_0'] = ol.parser.ogc.Filter_v1_0_0; + } + if (ol.ENABLE_OGCFILTER_1_1_0) { + this.parsers['v1_1_0'] = ol.parser.ogc.Filter_v1_1_0; + } + goog.base(this, opt_options); +}; +goog.inherits(ol.parser.ogc.Filter, ol.parser.ogc.Versioned); diff --git a/src/ol/parser/ogc/filter_v1.js b/src/ol/parser/ogc/filter_v1.js new file mode 100644 index 0000000000..4b7f1063ec --- /dev/null +++ b/src/ol/parser/ogc/filter_v1.js @@ -0,0 +1,582 @@ +goog.provide('ol.parser.ogc.Filter_v1'); +goog.require('goog.array'); +goog.require('goog.dom.xml'); +goog.require('goog.string'); +goog.require('ol.expr'); +goog.require('ol.expr.Call'); +goog.require('ol.expr.Comparison'); +goog.require('ol.expr.ComparisonOp'); +goog.require('ol.expr.Identifier'); +goog.require('ol.expr.Logical'); +goog.require('ol.expr.LogicalOp'); +goog.require('ol.expr.Not'); +goog.require('ol.expr.functions'); +goog.require('ol.parser.XML'); + + + +/** + * @constructor + * @extends {ol.parser.XML} + */ +ol.parser.ogc.Filter_v1 = function() { + this.defaultNamespaceURI = 'http://www.opengis.net/ogc'; + this.errorProperty = 'filter'; + this.readers = { + 'http://www.opengis.net/ogc': { + '_expression': function(node) { + // only the simplest of ogc:expression handled + // "some text and an attribute" + var obj, value = ''; + for (var child = node.firstChild; child; child = child.nextSibling) { + switch (child.nodeType) { + case 1: + obj = this.readNode(child); + if (obj['property']) { + value += obj['property']; + } else if (goog.isDef(obj['value'])) { + value += obj['value']; + } + break; + case 3: // text node + case 4: // cdata section + value += child.nodeValue; + break; + default: + break; + } + } + return value; + }, + 'Filter': function(node, obj) { + var container = { + 'filters': [] + }; + this.readChildNodes(node, container); + if (goog.isDef(container['fids'])) { + obj['filter'] = new ol.expr.Call( + new ol.expr.Identifier(ol.expr.functions.FID), + container['fids']); + } else if (container['filters'].length > 0) { + obj['filter'] = container['filters'][0]; + } + }, + 'FeatureId': function(node, obj) { + var fid = node.getAttribute('fid'); + if (fid) { + if (!goog.isDef(obj['fids'])) { + obj['fids'] = {}; + } + obj['fids'][fid] = true; + } + }, + 'And': function(node, obj) { + var container = {'filters': []}; + this.readChildNodes(node, container); + var filter = this.aggregateLogical_(container['filters'], + ol.expr.LogicalOp.AND); + obj['filters'].push(filter); + }, + 'Or': function(node, obj) { + var container = {'filters': []}; + this.readChildNodes(node, container); + var filter = this.aggregateLogical_(container['filters'], + ol.expr.LogicalOp.OR); + obj['filters'].push(filter); + }, + 'Not': function(node, obj) { + var container = {'filters': []}; + this.readChildNodes(node, container); + // Not is unary so can only contain 1 child filter + obj['filters'].push(new ol.expr.Not( + container.filters[0])); + }, + 'PropertyIsNull': function(node, obj) { + var container = {}; + this.readChildNodes(node, container); + obj['filters'].push(new ol.expr.Comparison( + ol.expr.ComparisonOp.EQ, + container['property'], + null)); + }, + 'PropertyIsLessThan': function(node, obj) { + var container = {}; + this.readChildNodes(node, container); + obj['filters'].push(new ol.expr.Comparison( + ol.expr.ComparisonOp.LT, + container['property'], + container['value'])); + }, + 'PropertyIsGreaterThan': function(node, obj) { + var container = {}; + this.readChildNodes(node, container); + obj['filters'].push(new ol.expr.Comparison( + ol.expr.ComparisonOp.GT, + container['property'], + container['value'])); + }, + 'PropertyIsLessThanOrEqualTo': function(node, obj) { + var container = {}; + this.readChildNodes(node, container); + obj['filters'].push(new ol.expr.Comparison( + ol.expr.ComparisonOp.LTE, + container['property'], + container['value'])); + }, + 'PropertyIsGreaterThanOrEqualTo': function(node, obj) { + var container = {}; + this.readChildNodes(node, container); + obj['filters'].push(new ol.expr.Comparison( + ol.expr.ComparisonOp.GTE, + container['property'], + container['value'])); + }, + 'PropertyIsBetween': function(node, obj) { + var container = {}; + this.readChildNodes(node, container); + obj['filters'].push(new ol.expr.Logical(ol.expr.LogicalOp.AND, + new ol.expr.Comparison(ol.expr.ComparisonOp.GTE, + container['property'], container['lowerBoundary']), + new ol.expr.Comparison(ol.expr.ComparisonOp.LTE, + container['property'], container['upperBoundary']))); + }, + 'Literal': function(node, obj) { + var nodeValue = this.getChildValue(node); + var value = goog.string.toNumber(nodeValue); + obj['value'] = isNaN(value) ? nodeValue : value; + }, + 'PropertyName': function(node, obj) { + obj['property'] = this.getChildValue(node); + }, + 'LowerBoundary': function(node, obj) { + var readers = this.readers[this.defaultNamespaceURI]; + obj['lowerBoundary'] = goog.string.toNumber( + readers['_expression'].call(this, node)); + }, + 'UpperBoundary': function(node, obj) { + var readers = this.readers[this.defaultNamespaceURI]; + obj['upperBoundary'] = goog.string.toNumber( + readers['_expression'].call(this, node)); + }, + '_spatial': function(node, obj, identifier) { + var args = [], container = {}; + this.readChildNodes(node, container); + if (goog.isDef(container.geometry)) { + args.push(this.gml_.createGeometry(container)); + } else { + args = container['bounds']; + } + if (goog.isDef(container['distance'])) { + args.push(container['distance']); + } + if (goog.isDef(container['distanceUnits'])) { + args.push(container['distanceUnits']); + } + args.push(container['projection']); + if (goog.isDef(container['property'])) { + args.push(container['property']); + } + obj['filters'].push(new ol.expr.Call(new ol.expr.Identifier( + identifier), args)); + }, + 'BBOX': function(node, obj) { + var readers = this.readers[this.defaultNamespaceURI]; + readers['_spatial'].call(this, node, obj, + ol.expr.functions.EXTENT); + }, + 'Intersects': function(node, obj) { + var readers = this.readers[this.defaultNamespaceURI]; + readers['_spatial'].call(this, node, obj, + ol.expr.functions.INTERSECTS); + }, + 'Within': function(node, obj) { + var readers = this.readers[this.defaultNamespaceURI]; + readers['_spatial'].call(this, node, obj, + ol.expr.functions.WITHIN); + }, + 'Contains': function(node, obj) { + var readers = this.readers[this.defaultNamespaceURI]; + readers['_spatial'].call(this, node, obj, + ol.expr.functions.CONTAINS); + }, + 'DWithin': function(node, obj) { + var readers = this.readers[this.defaultNamespaceURI]; + readers['_spatial'].call(this, node, obj, + ol.expr.functions.DWITHIN); + }, + 'Distance': function(node, obj) { + obj['distance'] = parseInt(this.getChildValue(node), 10); + obj['distanceUnits'] = node.getAttribute('units'); + } + } + }; + this.writers = { + 'http://www.opengis.net/ogc': { + 'Filter': function(filter) { + var node = this.createElementNS('ogc:Filter'); + this.writeNode(this.getFilterType_(filter), filter, null, node); + return node; + }, + '_featureIds': function(filter) { + var node = this.createDocumentFragment(); + var fids = filter.getArgs(); + for (var i = 0, ii = fids.length; i < ii; i++) { + this.writeNode('FeatureId', fids[i], null, node); + } + return node; + }, + 'FeatureId': function(fid) { + var node = this.createElementNS('ogc:FeatureId'); + node.setAttribute('fid', fid); + return node; + }, + 'And': function(filter) { + var node = this.createElementNS('ogc:And'); + var subFilters = []; + this.getSubfiltersForLogical_(filter, subFilters); + for (var i = 0, ii = subFilters.length; i < ii; ++i) { + var subFilter = subFilters[i]; + if (goog.isDefAndNotNull(subFilter)) { + this.writeNode(this.getFilterType_(subFilter), subFilter, + null, node); + } + } + return node; + }, + 'Or': function(filter) { + var node = this.createElementNS('ogc:Or'); + var subFilters = []; + this.getSubfiltersForLogical_(filter, subFilters); + for (var i = 0, ii = subFilters.length; i < ii; ++i) { + var subFilter = subFilters[i]; + if (goog.isDefAndNotNull(subFilter)) { + this.writeNode(this.getFilterType_(subFilter), subFilter, + null, node); + } + } + return node; + }, + 'Not': function(filter) { + var node = this.createElementNS('ogc:Not'); + var childFilter = filter.getArgument(); + this.writeNode(this.getFilterType_(childFilter), childFilter, null, + node); + return node; + }, + 'PropertyIsLessThan': function(filter) { + var node = this.createElementNS('ogc:PropertyIsLessThan'); + this.writeNode('PropertyName', filter.getLeft(), null, node); + this.writeOgcExpression(filter.getRight(), node); + return node; + }, + 'PropertyIsGreaterThan': function(filter) { + var node = this.createElementNS('ogc:PropertyIsGreaterThan'); + this.writeNode('PropertyName', filter.getLeft(), null, node); + this.writeOgcExpression(filter.getRight(), node); + return node; + }, + 'PropertyIsLessThanOrEqualTo': function(filter) { + var node = this.createElementNS('ogc:PropertyIsLessThanOrEqualTo'); + this.writeNode('PropertyName', filter.getLeft(), null, node); + this.writeOgcExpression(filter.getRight(), node); + return node; + }, + 'PropertyIsGreaterThanOrEqualTo': function(filter) { + var node = this.createElementNS('ogc:PropertyIsGreaterThanOrEqualTo'); + this.writeNode('PropertyName', filter.getLeft(), null, node); + this.writeOgcExpression(filter.getRight(), node); + return node; + }, + 'PropertyIsBetween': function(filter) { + var node = this.createElementNS('ogc:PropertyIsBetween'); + var property = filter.getLeft().getLeft(); + this.writeNode('PropertyName', property, null, node); + var lower, upper; + var filters = new Array(2); + filters[0] = filter.getLeft(); + filters[1] = filter.getRight(); + for (var i = 0; i < 2; ++i) { + var value = filters[i].getRight(); + if (filters[i].getOperator() === ol.expr.ComparisonOp.GTE) { + lower = value; + } else if (filters[i].getOperator() === ol.expr.ComparisonOp.LTE) { + upper = value; + } + } + this.writeNode('LowerBoundary', lower, null, node); + this.writeNode('UpperBoundary', upper, null, node); + return node; + }, + 'PropertyName': function(name) { + var node = this.createElementNS('ogc:PropertyName'); + node.appendChild(this.createTextNode(name)); + return node; + }, + 'Literal': function(value) { + if (value instanceof Date) { + value = value.toISOString(); + } + var node = this.createElementNS('ogc:Literal'); + node.appendChild(this.createTextNode(value)); + return node; + }, + 'LowerBoundary': function(value) { + var node = this.createElementNS('ogc:LowerBoundary'); + this.writeOgcExpression(value, node); + return node; + }, + 'UpperBoundary': function(value) { + var node = this.createElementNS('ogc:UpperBoundary'); + this.writeOgcExpression(value, node); + return node; + }, + 'INTERSECTS': function(filter) { + return this.writeSpatial_(filter, 'Intersects'); + }, + 'WITHIN': function(filter) { + return this.writeSpatial_(filter, 'Within'); + }, + 'CONTAINS': function(filter) { + return this.writeSpatial_(filter, 'Contains'); + }, + 'DWITHIN': function(filter) { + var node = this.writeSpatial_(filter, 'DWithin'); + this.writeNode('Distance', filter, null, node); + return node; + }, + 'Distance': function(filter) { + var node = this.createElementNS('ogc:Distance'); + var args = filter.getArgs(); + node.setAttribute('units', args[2]); + node.appendChild(this.createTextNode(args[1])); + return node; + }, + 'Function': function(filter) { + var node = this.createElementNS('ogc:Function'); + node.setAttribute('name', filter.getCallee().getName()); + var params = filter.getArgs(); + for (var i = 0, len = params.length; i < len; i++) { + this.writeOgcExpression(params[i], node); + } + return node; + }, + 'PropertyIsNull': function(filter) { + var node = this.createElementNS('ogc:PropertyIsNull'); + this.writeNode('PropertyName', filter.getLeft(), null, node); + return node; + } + } + }; + this.filterMap_ = { + '&&': 'And', + '||': 'Or', + '!': 'Not', + '==': 'PropertyIsEqualTo', + '!=': 'PropertyIsNotEqualTo', + '<': 'PropertyIsLessThan', + '>': 'PropertyIsGreaterThan', + '<=': 'PropertyIsLessThanOrEqualTo', + '>=': 'PropertyIsGreaterThanOrEqualTo', + '..': 'PropertyIsBetween', + '~': 'PropertyIsLike', + 'NULL': 'PropertyIsNull', + 'BBOX': 'BBOX', + 'DWITHIN': 'DWITHIN', + 'WITHIN': 'WITHIN', + 'CONTAINS': 'CONTAINS', + 'INTERSECTS': 'INTERSECTS', + 'FID': '_featureIds' + }; + goog.base(this); +}; +goog.inherits(ol.parser.ogc.Filter_v1, ol.parser.XML); + + +/** + * @param {ol.expr.Expression} filter The filter to determine the type of. + * @return {string} The type of filter. + * @private + */ +ol.parser.ogc.Filter_v1.prototype.getFilterType_ = function(filter) { + var type; + if (filter instanceof ol.expr.Logical || + filter instanceof ol.expr.Comparison) { + type = filter.getOperator(); + var isNull = (type === ol.expr.ComparisonOp.EQ && + filter.getRight() === null); + if (isNull) { + type = 'NULL'; + } + var isBetween = (type === ol.expr.LogicalOp.AND && + filter.getLeft() instanceof ol.expr.Comparison && + filter.getRight() instanceof ol.expr.Comparison && + filter.getLeft().getLeft() === filter.getRight().getLeft() && + (filter.getLeft().getOperator() === ol.expr.ComparisonOp.LTE || + filter.getLeft().getOperator() === ol.expr.ComparisonOp.GTE) && + (filter.getRight().getOperator() === ol.expr.ComparisonOp.LTE || + filter.getRight().getOperator() === ol.expr.ComparisonOp.GTE)); + if (isBetween) { + type = '..'; + } + } else if (filter instanceof ol.expr.Call) { + var callee = filter.getCallee().getName(); + if (callee === ol.expr.functions.FID) { + type = 'FID'; + } + else if (callee === ol.expr.functions.IEQ) { + type = '=='; + } else if (callee === ol.expr.functions.INEQ) { + type = '!='; + } + else if (callee === ol.expr.functions.LIKE) { + type = '~'; + } + else if (callee === ol.expr.functions.CONTAINS) { + type = 'CONTAINS'; + } else if (callee === ol.expr.functions.WITHIN) { + type = 'WITHIN'; + } else if (callee === ol.expr.functions.DWITHIN) { + type = 'DWITHIN'; + } else if (callee === ol.expr.functions.EXTENT) { + type = 'BBOX'; + } else if (callee === ol.expr.functions.INTERSECTS) { + type = 'INTERSECTS'; + } + } else if (filter instanceof ol.expr.Not) { + type = '!'; + } + var filterType = this.filterMap_[type]; + if (!filterType) { + throw new Error('Filter writing not supported for rule type: ' + type); + } + return filterType; +}; + + +/** + * @param {string|Document|Element} data Data to read. + * @return {Object} An object representing the document. + */ +ol.parser.ogc.Filter_v1.prototype.read = function(data) { + if (goog.isString(data)) { + data = goog.dom.xml.loadXml(data); + } + if (data && data.nodeType == 9) { + data = data.documentElement; + } + var obj = {}; + this.readNode(data, obj); + return obj['filter']; +}; + + +/** + * @param {ol.expr.Expression} filter The filter to write out. + * @return {string} The serialized filter. + */ +ol.parser.ogc.Filter_v1.prototype.write = function(filter) { + var root = this.writeNode('Filter', filter); + this.setAttributeNS( + root, 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation', this.schemaLocation); + return this.serialize(root); +}; + + +/** + * @param {ol.expr.Call|string|number} value The value write out. + * @param {Element} node The node to append to. + * @return {Element} The node to which was appended. + * @protected + */ +ol.parser.ogc.Filter_v1.prototype.writeOgcExpression = function(value, node) { + if (value instanceof ol.expr.Call) { + this.writeNode('Function', value, null, node); + } else { + this.writeNode('Literal', value, null, node); + } + return node; +}; + + +/** + * @param {ol.expr.Logical} filter The filter to retrieve the sub filters from. + * @param {Array.} subFilters The sub filters retrieved. + * @private + */ +ol.parser.ogc.Filter_v1.prototype.getSubfiltersForLogical_ = function(filter, + subFilters) { + var operator = filter.getOperator(); + var filters = new Array(2); + filters[0] = filter.getLeft(); + filters[1] = filter.getRight(); + for (var i = 0; i < 2; ++i) { + if (filters[i] instanceof ol.expr.Logical && filters[i].getOperator() === + operator) { + this.getSubfiltersForLogical_(filters[i], subFilters); + } else { + subFilters.push(filters[i]); + } + } +}; + + +/** + * Since ol.expr.Logical can only have a left and a right, we need to nest + * sub filters coming from OGC Filter. + * @param {Array.} filters The filters to aggregate. + * @param {ol.expr.LogicalOp} operator The logical operator to use. + * @return {ol.expr.Logical} The logical filter created. + * @private + */ +ol.parser.ogc.Filter_v1.prototype.aggregateLogical_ = function(filters, + operator) { + var subFilters = []; + var newFilters = []; + // we only need to do this if we have more than 2 items + if (filters.length > 2) { + while (filters.length) { + subFilters.push(filters.pop()); + if (subFilters.length === 2) { + newFilters.push(new ol.expr.Logical(operator, + subFilters[0], subFilters[1])); + goog.array.clear(subFilters); + } + } + // there could be a single item left now + if (subFilters.length === 1) { + newFilters.push(subFilters[0]); + } + return this.aggregateLogical_(newFilters, operator); + } else { + return new ol.expr.Logical(operator, filters[0], filters[1]); + } +}; + + +/** + * @param {ol.parser.ogc.GML_v2|ol.parser.ogc.GML_v3} gml The GML parser to + * use. + * @protected + */ +ol.parser.ogc.Filter_v1.prototype.setGmlParser = function(gml) { + this.gml_ = gml; + for (var uri in this.gml_.readers) { + for (var key in this.gml_.readers[uri]) { + if (!goog.isDef(this.readers[uri])) { + this.readers[uri] = {}; + } + this.readers[uri][key] = goog.bind(this.gml_.readers[uri][key], + this.gml_); + } + } + for (uri in this.gml_.writers) { + for (key in this.gml_.writers[uri]) { + if (!goog.isDef(this.writers[uri])) { + this.writers[uri] = {}; + } + this.writers[uri][key] = goog.bind(this.gml_.writers[uri][key], + this.gml_); + } + } +}; diff --git a/src/ol/parser/ogc/filter_v1_0_0.js b/src/ol/parser/ogc/filter_v1_0_0.js new file mode 100644 index 0000000000..7bbc07f568 --- /dev/null +++ b/src/ol/parser/ogc/filter_v1_0_0.js @@ -0,0 +1,167 @@ +goog.provide('ol.parser.ogc.Filter_v1_0_0'); + +goog.require('goog.object'); +goog.require('ol.expr'); +goog.require('ol.expr.Call'); +goog.require('ol.expr.Comparison'); +goog.require('ol.expr.ComparisonOp'); +goog.require('ol.expr.Identifier'); +goog.require('ol.expr.functions'); +goog.require('ol.geom.Geometry'); +goog.require('ol.parser.ogc.Filter_v1'); +goog.require('ol.parser.ogc.GML_v2'); + + + +/** + * @constructor + * @extends {ol.parser.ogc.Filter_v1} + */ +ol.parser.ogc.Filter_v1_0_0 = function() { + goog.base(this); + this.version = '1.0.0'; + this.schemaLocation = 'http://www.opengis.net/ogc ' + + 'http://schemas.opengis.net/filter/1.0.0/filter.xsd'; + goog.object.extend(this.readers['http://www.opengis.net/ogc'], { + 'PropertyIsEqualTo': function(node, obj) { + var container = {}; + this.readChildNodes(node, container); + obj['filters'].push(new ol.expr.Comparison( + ol.expr.ComparisonOp.EQ, + container['property'], + container['value'])); + }, + 'PropertyIsNotEqualTo': function(node, obj) { + var container = {}; + this.readChildNodes(node, container); + obj['filters'].push(new ol.expr.Comparison( + ol.expr.ComparisonOp.NEQ, + container['property'], + container['value'])); + }, + 'PropertyIsLike': function(node, obj) { + var container = {}; + this.readChildNodes(node, container); + var args = []; + args.push(container['property'], container['value'], + node.getAttribute('wildCard'), + node.getAttribute('singleChar'), + node.getAttribute('escape') + ); + obj['filters'].push(new ol.expr.Call( + new ol.expr.Identifier(ol.expr.functions.LIKE), args)); + } + }); + goog.object.extend(this.writers['http://www.opengis.net/ogc'], { + 'PropertyIsEqualTo': function(filter) { + var node = this.createElementNS('ogc:PropertyIsEqualTo'); + var property = filter.getLeft(); + if (goog.isDef(property)) { + this.writeNode('PropertyName', property, null, node); + } + this.writeOgcExpression(filter.getRight(), node); + return node; + }, + 'PropertyIsNotEqualTo': function(filter) { + var node = this.createElementNS('ogc:PropertyIsNotEqualTo'); + var property = filter.getLeft(); + if (goog.isDef(property)) { + this.writeNode('PropertyName', property, null, node); + } + this.writeOgcExpression(filter.getRight(), node); + return node; + }, + 'PropertyIsLike': function(filter) { + var node = this.createElementNS('ogc:PropertyIsLike'); + var args = filter.getArgs(); + node.setAttribute('wildCard', args[2]); + node.setAttribute('singleChar', args[3]); + node.setAttribute('escape', args[4]); + var property = args[0]; + if (goog.isDef(property)) { + this.writeNode('PropertyName', property, null, node); + } + this.writeNode('Literal', args[1], null, node); + return node; + }, + 'BBOX': function(filter) { + var node = this.createElementNS('ogc:BBOX'); + var args = filter.getArgs(); + var property = args[5], bbox = [args[0], args[1], args[2], args[3]], + projection = args[4]; + // PropertyName is mandatory in 1.0.0, but e.g. GeoServer also + // accepts filters without it. + if (goog.isDefAndNotNull(property)) { + this.writeNode('PropertyName', property, null, node); + } + var box = this.writeNode('Box', bbox, + 'http://www.opengis.net/gml'); + if (goog.isDefAndNotNull(projection)) { + box.setAttribute('srsName', projection); + } + node.appendChild(box); + return node; + } + }); + this.setGmlParser(new ol.parser.ogc.GML_v2({featureNS: 'http://foo'})); +}; +goog.inherits(ol.parser.ogc.Filter_v1_0_0, + ol.parser.ogc.Filter_v1); + + +/** + * @param {ol.expr.Call} filter The filter to write out. + * @param {string} name The name of the spatial operator. + * @return {Element} The node created. + * @private + */ +ol.parser.ogc.Filter_v1_0_0.prototype.writeSpatial_ = function(filter, name) { + var node = this.createElementNS('ogc:' + name); + var args = filter.getArgs(); + var property, geom = null, bbox, call, projection; + if (goog.isNumber(args[0])) { + bbox = [args[0], args[1], args[2], args[3]]; + projection = args[4]; + property = args[5]; + } else if (args[0] instanceof ol.geom.Geometry) { + geom = args[0]; + if (name === 'DWithin') { + projection = args[3]; + property = args[4]; + } else { + projection = args[1]; + property = args[2]; + } + } else if (args[0] instanceof ol.expr.Call) { + call = args[0]; + if (name === 'DWithin') { + projection = args[3]; + property = args[4]; + } else { + projection = args[1]; + property = args[2]; + } + } + if (goog.isDefAndNotNull(property)) { + this.writeNode('PropertyName', property, null, node); + } + if (goog.isDef(call)) { + this.writeNode('Function', call, null, node); + } else { + var child; + if (geom !== null) { + child = this.writeNode('_geometry', geom, + this.gml_.featureNS).firstChild; + } else if (bbox.length === 4) { + child = this.writeNode('Box', bbox, + 'http://www.opengis.net/gml'); + } + if (goog.isDef(child)) { + if (goog.isDef(projection)) { + child.setAttribute('srsName', projection); + } + node.appendChild(child); + } + } + return node; +}; diff --git a/src/ol/parser/ogc/filter_v1_1_0.js b/src/ol/parser/ogc/filter_v1_1_0.js new file mode 100644 index 0000000000..6cfa18ed44 --- /dev/null +++ b/src/ol/parser/ogc/filter_v1_1_0.js @@ -0,0 +1,217 @@ +goog.provide('ol.parser.ogc.Filter_v1_1_0'); + +goog.require('goog.object'); +goog.require('ol.expr'); +goog.require('ol.expr.Call'); +goog.require('ol.expr.Comparison'); +goog.require('ol.expr.ComparisonOp'); +goog.require('ol.expr.Identifier'); +goog.require('ol.expr.functions'); +goog.require('ol.geom.Geometry'); +goog.require('ol.parser.ogc.Filter_v1'); +goog.require('ol.parser.ogc.GML_v3'); + + + +/** + * @constructor + * @extends {ol.parser.ogc.Filter_v1} + */ +ol.parser.ogc.Filter_v1_1_0 = function() { + goog.base(this); + this.version = '1.1.0'; + this.schemaLocation = 'http://www.opengis.net/ogc ' + + 'http://schemas.opengis.net/filter/1.1.0/filter.xsd'; + goog.object.extend(this.readers['http://www.opengis.net/ogc'], { + 'PropertyIsEqualTo': function(node, obj) { + var matchCase = node.getAttribute('matchCase'); + var container = {}, filter; + this.readChildNodes(node, container); + if (matchCase === 'false' || matchCase === '0') { + filter = new ol.expr.Call(new ol.expr.Identifier(ol.expr.functions.IEQ), + [container['property'], container['value']]); + } else { + filter = new ol.expr.Comparison( + ol.expr.ComparisonOp.EQ, + container['property'], + container['value']); + } + obj['filters'].push(filter); + }, + 'PropertyIsNotEqualTo': function(node, obj) { + var matchCase = node.getAttribute('matchCase'); + var container = {}, filter; + this.readChildNodes(node, container); + if (matchCase === 'false' || matchCase === '0') { + filter = new ol.expr.Call(new ol.expr.Identifier( + ol.expr.functions.INEQ), + [container['property'], container['value']]); + } else { + filter = new ol.expr.Comparison( + ol.expr.ComparisonOp.NEQ, + container['property'], + container['value']); + } + obj['filters'].push(filter); + }, + 'PropertyIsLike': function(node, obj) { + var container = {}; + this.readChildNodes(node, container); + var args = []; + args.push(container['property'], container['value'], + node.getAttribute('wildCard'), + node.getAttribute('singleChar'), + node.getAttribute('escapeChar'), + node.getAttribute('matchCase')); + obj['filters'].push(new ol.expr.Call( + new ol.expr.Identifier(ol.expr.functions.LIKE), args)); + } + }); + goog.object.extend(this.writers['http://www.opengis.net/ogc'], { + 'PropertyIsEqualTo': function(filter) { + var node = this.createElementNS('ogc:PropertyIsEqualTo'); + var property, value; + if (filter instanceof ol.expr.Call) { + var args = filter.getArgs(); + property = args[0]; + value = args[1]; + node.setAttribute('matchCase', false); + } else { + property = filter.getLeft(); + value = filter.getRight(); + } + this.writeNode('PropertyName', property, null, node); + this.writeOgcExpression(value, node); + return node; + }, + 'PropertyIsNotEqualTo': function(filter) { + var node = this.createElementNS('ogc:PropertyIsNotEqualTo'); + var property, value; + if (filter instanceof ol.expr.Call) { + var args = filter.getArgs(); + property = args[0]; + value = args[1]; + node.setAttribute('matchCase', false); + } else { + property = filter.getLeft(); + value = filter.getRight(); + } + this.writeNode('PropertyName', property, null, node); + this.writeOgcExpression(value, node); + return node; + }, + 'PropertyIsLike': function(filter) { + var node = this.createElementNS('ogc:PropertyIsLike'); + var args = filter.getArgs(); + node.setAttribute('wildCard', args[2]); + node.setAttribute('singleChar', args[3]); + node.setAttribute('escapeChar', args[4]); + if (goog.isDefAndNotNull(args[5])) { + node.setAttribute('matchCase', args[5]); + } + var property = args[0]; + if (goog.isDef(property)) { + this.writeNode('PropertyName', property, null, node); + } + this.writeNode('Literal', args[1], null, node); + return node; + }, + 'BBOX': function(filter) { + var node = this.createElementNS('ogc:BBOX'); + var args = filter.getArgs(); + var property = args[5], bbox = [args[0], args[1], args[2], args[3]], + projection = args[4]; + // PropertyName is optional in 1.1.0 + if (goog.isDefAndNotNull(property)) { + this.writeNode('PropertyName', property, null, node); + } + var box = this.writeNode('Envelope', bbox, + 'http://www.opengis.net/gml'); + if (goog.isDefAndNotNull(projection)) { + box.setAttribute('srsName', projection); + } + node.appendChild(box); + return node; + }, + 'SortBy': function(sortProperties) { + var node = this.createElementNS('ogc:SortBy'); + for (var i = 0, l = sortProperties.length; i < l; i++) { + this.writeNode('SortProperty', sortProperties[i], null, node); + } + return node; + }, + 'SortProperty': function(sortProperty) { + var node = this.createElementNS('ogc:SortProperty'); + this.writeNode('PropertyName', sortProperty['property'], null, node); + this.writeNode('SortOrder', + (sortProperty['order'] == 'DESC') ? 'DESC' : 'ASC', null, node); + return node; + }, + 'SortOrder': function(value) { + var node = this.createElementNS('ogc:SortOrder'); + node.appendChild(this.createTextNode(value)); + return node; + } + }); + this.setGmlParser(new ol.parser.ogc.GML_v3()); +}; +goog.inherits(ol.parser.ogc.Filter_v1_1_0, + ol.parser.ogc.Filter_v1); + + +/** + * @param {ol.expr.Call} filter The filter to write out. + * @param {string} name The name of the spatial operator. + * @return {Element} The node created. + * @private + */ +ol.parser.ogc.Filter_v1_1_0.prototype.writeSpatial_ = function(filter, name) { + var node = this.createElementNS('ogc:' + name); + var args = filter.getArgs(); + var property, geom = null, bbox, call, projection; + if (goog.isNumber(args[0])) { + bbox = [args[0], args[1], args[2], args[3]]; + projection = args[4]; + property = args[5]; + } else if (args[0] instanceof ol.geom.Geometry) { + geom = args[0]; + if (name === 'DWithin') { + projection = args[3]; + property = args[4]; + } else { + projection = args[1]; + property = args[2]; + } + } else if (args[0] instanceof ol.expr.Call) { + call = args[0]; + if (name === 'DWithin') { + projection = args[3]; + property = args[4]; + } else { + projection = args[1]; + property = args[2]; + } + } + if (goog.isDefAndNotNull(property)) { + this.writeNode('PropertyName', property, null, node); + } + if (goog.isDef(call)) { + this.writeNode('Function', call, null, node); + } else { + var child; + if (geom !== null) { + child = this.writeNode('_geometry', geom, + this.gml_.featureNS).firstChild; + } else if (bbox.length === 4) { + child = this.writeNode('Envelope', bbox, + 'http://www.opengis.net/gml'); + } + if (goog.isDef(child)) { + if (goog.isDef(projection)) { + child.setAttribute('srsName', projection); + } + node.appendChild(child); + } + } + return node; +}; diff --git a/src/ol/parser/ogc/gml.js b/src/ol/parser/ogc/gml.js index f5c221655f..339ef64971 100644 --- a/src/ol/parser/ogc/gml.js +++ b/src/ol/parser/ogc/gml.js @@ -284,7 +284,7 @@ ol.parser.ogc.GML = function(opt_options) { sharedVertices = callback(feature, geom.type); } } - var geometry = this.createGeometry_({geometry: geom}, + var geometry = this.createGeometry({geometry: geom}, sharedVertices); if (goog.isDef(geometry)) { feature.setGeometry(geometry); @@ -434,7 +434,7 @@ ol.parser.ogc.GML = function(opt_options) { } else if (type === ol.geom.GeometryType.GEOMETRYCOLLECTION) { child = this.writeNode('GeometryCollection', geometry, null, node); } - if (goog.isDef(this.srsName)) { + if (goog.isDefAndNotNull(this.srsName)) { this.setAttributeNS(child, null, 'srsName', this.srsName); } return node; @@ -503,13 +503,12 @@ ol.parser.ogc.GML.prototype.readNode = function(node, obj, opt_first) { /** - * @private * @param {Object} container Geometry container. * @param {ol.geom.SharedVertices=} opt_vertices Shared vertices. * @return {ol.geom.Geometry} The geometry created. */ // TODO use a mixin since this is also used in the KML parser -ol.parser.ogc.GML.prototype.createGeometry_ = function(container, +ol.parser.ogc.GML.prototype.createGeometry = function(container, opt_vertices) { var geometry = null, coordinates, i, ii; switch (container.geometry.type) { @@ -553,7 +552,7 @@ ol.parser.ogc.GML.prototype.createGeometry_ = function(container, case ol.geom.GeometryType.GEOMETRYCOLLECTION: var geometries = []; for (i = 0, ii = container.geometry.parts.length; i < ii; i++) { - geometries.push(this.createGeometry_({ + geometries.push(this.createGeometry({ geometry: container.geometry.parts[i] }, opt_vertices)); } diff --git a/src/ol/parser/ogc/gml_v2.js b/src/ol/parser/ogc/gml_v2.js index feea6d3b22..9b4c364c2a 100644 --- a/src/ol/parser/ogc/gml_v2.js +++ b/src/ol/parser/ogc/gml_v2.js @@ -29,6 +29,7 @@ ol.parser.ogc.GML_v2 = function(opt_options) { 'Box': function(node, container) { var coordinates = []; this.readChildNodes(node, coordinates); + container.projection = node.getAttribute('srsName'); container.bounds = [coordinates[0][0][0], coordinates[0][1][0], coordinates[0][0][1], coordinates[0][1][1]]; } @@ -90,10 +91,10 @@ ol.parser.ogc.GML_v2 = function(opt_options) { }, 'Box': function(extent) { var node = this.createElementNS('gml:Box'); - this.writeNode('coordinates', [[extent.minX, extent.minY], - [extent.maxX, extent.maxY]], null, node); + this.writeNode('coordinates', [[extent[0], extent[1]], + [extent[2], extent[3]]], null, node); // srsName attribute is optional for gml:Box - if (goog.isDef(this.srsName)) { + if (goog.isDefAndNotNull(this.srsName)) { node.setAttribute('srsName', this.srsName); } return node; diff --git a/src/ol/parser/ogc/gml_v3.js b/src/ol/parser/ogc/gml_v3.js index 744d75afc8..7ed61aa31c 100644 --- a/src/ol/parser/ogc/gml_v3.js +++ b/src/ol/parser/ogc/gml_v3.js @@ -55,7 +55,7 @@ ol.parser.ogc.GML_v3 = function(opt_options) { } else if (type === ol.geom.GeometryType.GEOMETRYCOLLECTION) { child = this.writeNode('MultiGeometry', geometry, null, node); } - if (goog.isDef(this.srsName)) { + if (goog.isDefAndNotNull(this.srsName)) { this.setAttributeNS(child, null, 'srsName', this.srsName); } return node; @@ -206,6 +206,7 @@ ol.parser.ogc.GML_v3 = function(opt_options) { 'Envelope': function(node, container) { var coordinates = []; this.readChildNodes(node, coordinates); + container.projection = node.getAttribute('srsName'); container.bounds = [coordinates[0][0][0][0], coordinates[1][0][0][0], coordinates[0][0][0][1], coordinates[1][0][0][1]]; }, @@ -374,9 +375,9 @@ ol.parser.ogc.GML_v3 = function(opt_options) { // only 2d for simple features profile var pos; if (this.axisOrientation.substr(0, 2) === 'en') { - pos = (bounds.left + ' ' + bounds.bottom); + pos = (bounds[0] + ' ' + bounds[2]); } else { - pos = (bounds.bottom + ' ' + bounds.left); + pos = (bounds[2] + ' ' + bounds[0]); } var node = this.createElementNS('gml:lowerCorner'); node.appendChild(this.createTextNode(pos)); @@ -386,9 +387,9 @@ ol.parser.ogc.GML_v3 = function(opt_options) { // only 2d for simple features profile var pos; if (this.axisOrientation.substr(0, 2) === 'en') { - pos = (bounds.right + ' ' + bounds.top); + pos = (bounds[1] + ' ' + bounds[3]); } else { - pos = (bounds.top + ' ' + bounds.right); + pos = (bounds[3] + ' ' + bounds[1]); } var node = this.createElementNS('gml:upperCorner'); node.appendChild(this.createTextNode(pos)); diff --git a/src/ol/parser/xml.js b/src/ol/parser/xml.js index e5c35f3d5c..09a4389792 100644 --- a/src/ol/parser/xml.js +++ b/src/ol/parser/xml.js @@ -182,8 +182,9 @@ ol.parser.XML.prototype.createElementNS = function(name, opt_uri) { * results to a node. * * @param {string} name The name of a node to generate. Only use a local name. - * @param {Object} obj Structure containing data for the writer. - * @param {string=} opt_uri The name space uri to which the node belongs. + * @param {Object|string|number} obj Structure containing data for the writer. + * @param {?string=} opt_uri The name space uri to which the node + * belongs. * @param {Element=} opt_parent Result will be appended to this node. If no * parent is supplied, the node will not be appended to anything. * @return {?Element} The child node. @@ -273,3 +274,22 @@ ol.parser.XML.prototype.serialize = function(node) { return goog.dom.xml.serialize(node); } }; + + +/** + * Create a document fragment node that can be appended to another node + * created by createElementNS. This will call + * document.createDocumentFragment outside of IE. In IE, the ActiveX + * object's createDocumentFragment method is used. + * + * @return {Element} A document fragment. + */ +ol.parser.XML.prototype.createDocumentFragment = function() { + var element; + if (this.xmldom) { + element = this.xmldom.createDocumentFragment(); + } else { + element = document.createDocumentFragment(); + } + return element; +}; diff --git a/test/spec/ol/parser/ogc/filter_v1_0_0.test.js b/test/spec/ol/parser/ogc/filter_v1_0_0.test.js new file mode 100644 index 0000000000..3c413c75ca --- /dev/null +++ b/test/spec/ol/parser/ogc/filter_v1_0_0.test.js @@ -0,0 +1,238 @@ +goog.provide('ol.test.parser.ogc.Filter_v1_0_0'); + +describe('ol.parser.ogc.Filter_v1_0_0', function() { + + var parser = new ol.parser.ogc.Filter_v1_0_0(); + + describe('#readwrite', function() { + + it('intersects filter read / written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/intersects.xml'; + afterLoadXml(url, function(xml) { + var filter = parser.read(xml); + expect(filter instanceof ol.expr.Call).to.be(true); + expect(filter.getCallee().getName()).to.eql( + ol.expr.functions.INTERSECTS); + var args = filter.getArgs(); + var geom = args[0]; + expect(geom instanceof ol.geom.Polygon).to.be(true); + expect(args[2]).to.eql('Geometry'); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('within filter read / written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/within.xml'; + afterLoadXml(url, function(xml) { + var filter = parser.read(xml); + expect(filter instanceof ol.expr.Call).to.be(true); + expect(filter.getCallee().getName()).to.eql(ol.expr.functions.WITHIN); + var args = filter.getArgs(); + var geom = args[0]; + expect(geom instanceof ol.geom.Polygon).to.be(true); + expect(args[2]).to.eql('Geometry'); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('contains filter read / written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/contains.xml'; + afterLoadXml(url, function(xml) { + var filter = parser.read(xml); + expect(filter instanceof ol.expr.Call).to.be(true); + expect(filter.getCallee().getName()).to.eql( + ol.expr.functions.CONTAINS); + var args = filter.getArgs(); + var geom = args[0]; + expect(geom instanceof ol.geom.Polygon).to.be(true); + expect(args[2]).to.eql('Geometry'); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('between filter read / written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/between.xml'; + afterLoadXml(url, function(xml) { + var filter = parser.read(xml); + expect(filter instanceof ol.expr.Logical).to.be.ok(); + expect(filter.getOperator()).to.eql(ol.expr.LogicalOp.AND); + expect(filter.getLeft() instanceof ol.expr.Comparison).to.be.ok(); + expect(filter.getLeft().getOperator()).to.eql(ol.expr.ComparisonOp.GTE); + expect(filter.getLeft().getLeft()).to.eql('number'); + expect(filter.getLeft().getRight()).to.eql(0); + expect(filter.getRight() instanceof ol.expr.Comparison).to.be.ok(); + expect(filter.getRight().getOperator()).to.eql( + ol.expr.ComparisonOp.LTE); + expect(filter.getRight().getLeft()).to.eql('number'); + expect(filter.getRight().getRight()).to.eql(100); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('between filter read correctly without literals', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/between2.xml'; + afterLoadXml(url, function(xml) { + var filter = parser.read(xml); + expect(filter instanceof ol.expr.Logical).to.be.ok(); + expect(filter.getOperator()).to.eql(ol.expr.LogicalOp.AND); + expect(filter.getLeft() instanceof ol.expr.Comparison).to.be.ok(); + expect(filter.getLeft().getOperator()).to.eql(ol.expr.ComparisonOp.GTE); + expect(filter.getLeft().getLeft()).to.eql('number'); + expect(filter.getLeft().getRight()).to.eql(0); + expect(filter.getRight() instanceof ol.expr.Comparison).to.be.ok(); + expect(filter.getRight().getOperator()).to.eql( + ol.expr.ComparisonOp.LTE); + expect(filter.getRight().getLeft()).to.eql('number'); + expect(filter.getRight().getRight()).to.eql(100); + done(); + }); + }); + + it('null filter read / written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/null.xml'; + afterLoadXml(url, function(xml) { + var filter = parser.read(xml); + expect(filter instanceof ol.expr.Comparison).to.be.ok(); + expect(filter.getLeft()).to.eql('prop'); + expect(filter.getRight()).to.eql(null); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('BBOX written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/bbox.xml'; + afterLoadXml(url, function(xml) { + var filter = new ol.expr.Call( + new ol.expr.Identifier(ol.expr.functions.EXTENT), + [-180, -90, 180, 90, 'EPSG:4326', 'the_geom']); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('BBOX without geometry name written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/bbox_nogeom.xml'; + afterLoadXml(url, function(xml) { + var filter = new ol.expr.Call( + new ol.expr.Identifier(ol.expr.functions.EXTENT), + [-180, -90, 180, 90, 'EPSG:4326']); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('DWithin written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/dwithin.xml'; + afterLoadXml(url, function(xml) { + var filter = new ol.expr.Call(new ol.expr.Identifier( + ol.expr.functions.DWITHIN), + [new ol.geom.Point([2488789, 289552]), 1000, 'm', undefined, + 'Geometry']); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + filter = parser.read(xml); + output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + }); + + // the Filter Encoding spec doesn't allow for FID filters inside logical + // filters however, to be liberal, we will write them without complaining + describe('#logicalfid', function() { + + it('logical filter [OR] with fid filter written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureid.xml'; + afterLoadXml(url, function(xml) { + var filter = new ol.expr.Logical(ol.expr.LogicalOp.OR, + new ol.expr.Call(new ol.expr.Identifier(ol.expr.functions.LIKE), + ['person', 'me', '*', '.', '!']), + new ol.expr.Call(new ol.expr.Identifier(ol.expr.functions.FID), + ['foo.1', 'foo.2'])); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('logical filter [AND] with fid filter written correctly', + function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/' + + 'logicalfeatureidand.xml'; + afterLoadXml(url, function(xml) { + var filter = new ol.expr.Logical(ol.expr.LogicalOp.AND, + new ol.expr.Call(new ol.expr.Identifier(ol.expr.functions.LIKE), + ['person', 'me', '*', '.', '!']), + new ol.expr.Call(new ol.expr.Identifier(ol.expr.functions.FID), + ['foo.1', 'foo.2'])); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('logical filter [NOT] with fid filter written correctly', + function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/' + + 'logicalfeatureidnot.xml'; + afterLoadXml(url, function(xml) { + var filter = new ol.expr.Not( + new ol.expr.Call(new ol.expr.Identifier(ol.expr.functions.FID), + ['foo.2'])); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + }); + + describe('#date', function() { + + it('date writing works as expected', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/betweendates.xml'; + afterLoadXml(url, function(xml) { + // ISO 8601: 2010-11-27T18:19:15.123Z + var start = new Date(Date.UTC(2010, 10, 27, 18, 19, 15, 123)); + // ISO 8601: 2011-12-27T18:19:15.123Z + var end = new Date(Date.UTC(2011, 11, 27, 18, 19, 15, 123)); + var filter = new ol.expr.Logical(ol.expr.LogicalOp.AND, + new ol.expr.Comparison(ol.expr.ComparisonOp.GTE, 'when', start), + new ol.expr.Comparison(ol.expr.ComparisonOp.LTE, 'when', end)); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + }); + +}); + +goog.require('goog.dom.xml'); +goog.require('ol.expr'); +goog.require('ol.expr.Call'); +goog.require('ol.expr.Comparison'); +goog.require('ol.expr.ComparisonOp'); +goog.require('ol.expr.Identifier'); +goog.require('ol.expr.Logical'); +goog.require('ol.expr.LogicalOp'); +goog.require('ol.expr.Not'); +goog.require('ol.expr.functions'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); +goog.require('ol.parser.ogc.Filter_v1_0_0'); diff --git a/test/spec/ol/parser/ogc/filter_v1_1_0.test.js b/test/spec/ol/parser/ogc/filter_v1_1_0.test.js new file mode 100644 index 0000000000..695a848d65 --- /dev/null +++ b/test/spec/ol/parser/ogc/filter_v1_1_0.test.js @@ -0,0 +1,230 @@ +goog.provide('ol.test.parser.ogc.Filter_v1_1_0'); + +describe('ol.parser.ogc.Filter_v1_1_0', function() { + + var parser = new ol.parser.ogc.Filter_v1_1_0(); + + describe('#readwrite', function() { + + it('filter read correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_1_0/test.xml'; + afterLoadXml(url, function(xml) { + var filter = parser.read(xml); + expect(filter instanceof ol.expr.Logical).to.be(true); + expect(filter.getOperator()).to.eql(ol.expr.LogicalOp.OR); + var filters = []; + parser.getSubfiltersForLogical_(filter, filters); + expect(filters.length).to.eql(5); + expect(filters[0]).to.eql(new ol.expr.Logical(ol.expr.LogicalOp.AND, + new ol.expr.Comparison( + ol.expr.ComparisonOp.GTE, 'number', 1064866676), + new ol.expr.Comparison( + ol.expr.ComparisonOp.LTE, 'number', 1065512599))); + expect(filters[1]).to.eql(new ol.expr.Not(new ol.expr.Comparison( + ol.expr.ComparisonOp.LTE, 'FOO', 5000))); + expect(filters[2] instanceof ol.expr.Call).to.be(true); + expect(filters[2].getCallee().getName()).to.eql( + ol.expr.functions.LIKE); + expect(filters[2].getArgs()).to.eql(['cat', '*dog.food!*good', '*', + '.', '!', null]); + expect(filters[3] instanceof ol.expr.Call).to.be(true); + expect(filters[3].getCallee().getName()).to.eql( + ol.expr.functions.IEQ); + expect(filters[3].getArgs()).to.eql(['cat', 'dog']); + expect(filters[4] instanceof ol.expr.Comparison).to.be(true); + expect(filters[4].getOperator()).to.eql(ol.expr.ComparisonOp.EQ); + expect(filters[4].getLeft()).to.eql('cat'); + expect(filters[4].getRight()).to.eql('dog'); + done(); + }); + }); + + it('matchCase read correctly', function() { + var cases = [{ + str: + '' + + '' + + 'cat' + + 'dog' + + '' + + '', + exp: true + }, { + str: + '' + + '' + + 'cat' + + 'dog' + + '' + + '', + exp: true + }, { + str: + '' + + '' + + 'cat' + + 'dog' + + '' + + '', + exp: true + }, { + str: + '' + + '' + + 'cat' + + 'dog' + + '' + + '', + exp: false + }, { + str: + '' + + '' + + 'cat' + + 'dog' + + '' + + '', + exp: false + }, { + str: + '' + + '' + + 'cat' + + 'dog' + + '' + + '', + exp: true + }, { + str: + '' + + '' + + 'cat' + + 'dog' + + '' + + '', + exp: false + }]; + var filter, c; + for (var i = 0; i < cases.length; ++i) { + c = cases[i]; + filter = parser.read(c.str); + var matchCase = (filter instanceof ol.expr.Call) ? false : true; + expect(matchCase).to.eql(c.exp); + } + }); + + it('BBOX filter written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_1_0/bbox.xml'; + afterLoadXml(url, function(xml) { + var filter = parser.read(xml); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('BBOX filter without property name written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_1_0/bbox_nogeomname.xml'; + afterLoadXml(url, function(xml) { + var filter = parser.read(xml); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('Intersects filter read / written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_1_0/intersects.xml'; + afterLoadXml(url, function(xml) { + var filter = parser.read(xml); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('Filter functions written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_1_0/function.xml'; + afterLoadXml(url, function(xml) { + var filter = new ol.expr.Call(new ol.expr.Identifier( + ol.expr.functions.INTERSECTS), + [new ol.expr.Call(new ol.expr.Identifier('querySingle'), + ['sf:restricted', 'the_geom', + 'cat=3']), undefined, 'the_geom']); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('Custom filter functions written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_1_0/customfunction.xml'; + afterLoadXml(url, function(xml) { + var filter = new ol.expr.Logical(ol.expr.LogicalOp.AND, + new ol.expr.Call(new ol.expr.Identifier(ol.expr.functions.INEQ), + ['FOO', new ol.expr.Call(new ol.expr.Identifier('customFunction'), + ['param1', 'param2'])])); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('Nested filter functions written correctly', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_1_0/nestedfunction.xml'; + afterLoadXml(url, function(xml) { + var filter = new ol.expr.Call(new ol.expr.Identifier( + ol.expr.functions.DWITHIN), + [new ol.expr.Call(new ol.expr.Identifier('collectGeometries'), + [new ol.expr.Call(new ol.expr.Identifier('queryCollection'), + ['sf:roads', 'the_geom', 'INCLUDE'])]), 200, 'meters', + undefined, 'the_geom']); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('matchCase written correctly on Like filter', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_1_0/likematchcase.xml'; + afterLoadXml(url, function(xml) { + var filter = new ol.expr.Call( + new ol.expr.Identifier(ol.expr.functions.LIKE), + ['person', '*me*', '*', '.', '!', false]); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('sortBy written correctly on Like filter', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_1_0/sortby.xml'; + afterLoadXml(url, function(xml) { + var writer = parser.writers['http://www.opengis.net/ogc']['SortBy']; + var output = writer.call(parser, [{ + 'property': 'Title', + 'order': 'ASC' + },{ + 'property': 'Relevance', + 'order': 'DESC' + }]); + expect(output).to.xmleql(xml); + done(); + }); + }); + + }); + +}); + +goog.require('goog.dom.xml'); +goog.require('ol.expr'); +goog.require('ol.expr.Call'); +goog.require('ol.expr.Comparison'); +goog.require('ol.expr.ComparisonOp'); +goog.require('ol.expr.Identifier'); +goog.require('ol.expr.Logical'); +goog.require('ol.expr.LogicalOp'); +goog.require('ol.expr.Not'); +goog.require('ol.expr.functions'); +goog.require('ol.parser.ogc.Filter_v1_1_0'); diff --git a/test/spec/ol/parser/ogc/gml_v2.test.js b/test/spec/ol/parser/ogc/gml_v2.test.js index cfa4d82859..f57f1cbbd9 100644 --- a/test/spec/ol/parser/ogc/gml_v2.test.js +++ b/test/spec/ol/parser/ogc/gml_v2.test.js @@ -19,7 +19,7 @@ describe('ol.parser.gml_v2', function() { afterLoadXml(url, function(xml) { var obj = parser.read(xml); parser.srsName = 'foo'; - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; expect(goog.dom.xml.loadXml(parser.serialize(node))).to.xmleql(xml); @@ -47,7 +47,7 @@ describe('ol.parser.gml_v2', function() { afterLoadXml(url, function(xml) { var obj = parser.read(xml); parser.srsName = 'foo'; - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; expect(goog.dom.xml.loadXml(parser.serialize(node))).to.xmleql(xml); @@ -76,7 +76,7 @@ describe('ol.parser.gml_v2', function() { afterLoadXml(url, function(xml) { var obj = parser.read(xml); parser.srsName = 'foo'; - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; expect(goog.dom.xml.loadXml(parser.serialize(node))).to.xmleql(xml); @@ -104,7 +104,7 @@ describe('ol.parser.gml_v2', function() { afterLoadXml(url, function(xml) { var obj = parser.read(xml); parser.srsName = 'foo'; - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; expect(goog.dom.xml.loadXml(parser.serialize(node))).to.xmleql(xml); @@ -138,7 +138,7 @@ describe('ol.parser.gml_v2', function() { afterLoadXml(url, function(xml) { var obj = parser.read(xml); parser.srsName = 'foo'; - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; expect(goog.dom.xml.loadXml(parser.serialize(node))).to.xmleql(xml); @@ -170,7 +170,7 @@ describe('ol.parser.gml_v2', function() { afterLoadXml(url, function(xml) { var obj = parser.read(xml); parser.srsName = 'foo'; - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; expect(goog.dom.xml.loadXml(parser.serialize(node))).to.xmleql(xml); @@ -188,7 +188,7 @@ describe('ol.parser.gml_v2', function() { var p = new ol.parser.ogc.GML_v2({srsName: 'foo', featureNS: 'http://foo'}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; expect(goog.dom.xml.loadXml(p.serialize(node))).to.xmleql(xml); @@ -231,7 +231,7 @@ describe('ol.parser.gml_v2', function() { afterLoadXml(url, function(xml) { var obj = parser.read(xml); parser.srsName = 'foo'; - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; expect(goog.dom.xml.loadXml(parser.serialize(node))).to.xmleql(xml); diff --git a/test/spec/ol/parser/ogc/gml_v3.test.js b/test/spec/ol/parser/ogc/gml_v3.test.js index b58878b0c4..5586181d0d 100644 --- a/test/spec/ol/parser/ogc/gml_v3.test.js +++ b/test/spec/ol/parser/ogc/gml_v3.test.js @@ -17,7 +17,7 @@ describe('ol.parser.gml_v3', function() { var url = 'spec/ol/parser/ogc/xml/gml_v3/linearring.xml'; afterLoadXml(url, function(xml) { var obj = parser.read(xml); - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); parser.srsName = 'foo'; var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -33,7 +33,7 @@ describe('ol.parser.gml_v3', function() { var url = 'spec/ol/parser/ogc/xml/gml_v3/linestring.xml'; afterLoadXml(url, function(xml) { var obj = parser.read(xml); - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); parser.srsName = 'foo'; var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -59,7 +59,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v3({curve: true, srsName: 'foo'}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; expect(goog.dom.xml.loadXml(p.serialize(node))).to.xmleql(xml); @@ -84,7 +84,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v3({multiCurve: false, srsName: 'foo'}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; expect(goog.dom.xml.loadXml(p.serialize(node))).to.xmleql(xml); @@ -99,7 +99,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var obj = parser.read(xml); parser.srsName = 'foo'; - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; expect(goog.dom.xml.loadXml(parser.serialize(node))).to.xmleql(xml); @@ -116,7 +116,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v3({curve: true, srsName: 'foo'}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; expect(goog.dom.xml.loadXml(p.serialize(node))).to.xmleql(xml); @@ -143,7 +143,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var obj = parser.read(xml); parser.srsName = 'foo'; - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; expect(goog.dom.xml.loadXml(parser.serialize(node))).to.xmleql(xml); @@ -170,7 +170,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v3({multiSurface: false, srsName: 'foo'}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; expect(goog.dom.xml.loadXml(p.serialize(node))).to.xmleql(xml); @@ -195,7 +195,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var obj = parser.read(xml); parser.srsName = 'foo'; - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; expect(goog.dom.xml.loadXml(parser.serialize(node))).to.xmleql(xml); @@ -211,7 +211,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v3({surface: true, srsName: 'foo'}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; expect(goog.dom.xml.loadXml(p.serialize(node))).to.xmleql(xml); @@ -225,7 +225,7 @@ describe('ol.parser.gml_v3', function() { var url = 'spec/ol/parser/ogc/xml/gml_v3/point.xml'; afterLoadXml(url, function(xml) { var obj = parser.read(xml); - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); parser.srsName = 'foo'; var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -240,7 +240,7 @@ describe('ol.parser.gml_v3', function() { var url = 'spec/ol/parser/ogc/xml/gml_v3/polygon.xml'; afterLoadXml(url, function(xml) { var obj = parser.read(xml); - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); parser.srsName = 'foo'; var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -263,7 +263,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v3({surface: true, srsName: 'foo'}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; expect(goog.dom.xml.loadXml(p.serialize(node))).to.xmleql(xml); diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0.xml new file mode 100644 index 0000000000..5aea430597 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0.xml @@ -0,0 +1,23 @@ + + + + number + + 1064866676 + + + 1065512599 + + + + cat + *dog.food!*good + + + + FOO + 5000 + + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/bbox.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/bbox.xml new file mode 100644 index 0000000000..48d6f7f118 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/bbox.xml @@ -0,0 +1,8 @@ + + + the_geom + + -180,-90 180,90 + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/bbox_nogeom.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/bbox_nogeom.xml new file mode 100644 index 0000000000..d763209eda --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/bbox_nogeom.xml @@ -0,0 +1,7 @@ + + + + -180,-90 180,90 + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/between.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/between.xml new file mode 100644 index 0000000000..1108065c53 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/between.xml @@ -0,0 +1,11 @@ + + + number + + 0 + + + 100 + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/between2.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/between2.xml new file mode 100644 index 0000000000..3655c7a877 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/between2.xml @@ -0,0 +1,7 @@ + + + number + 0 + 100 + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/betweendates.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/betweendates.xml new file mode 100644 index 0000000000..3ad5b0131e --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/betweendates.xml @@ -0,0 +1,11 @@ + + + when + + 2010-11-27T18:19:15.123Z + + + 2011-12-27T18:19:15.123Z + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/contains.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/contains.xml new file mode 100644 index 0000000000..98b99ce04d --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/contains.xml @@ -0,0 +1,12 @@ + + + Geometry + + + + 2488789,289552 2588789,289552 2588789,389552 2488789,389552 2488789,289552 + + + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/custombetweendates.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/custombetweendates.xml new file mode 100644 index 0000000000..f12024a9dd --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/custombetweendates.xml @@ -0,0 +1,11 @@ + + + when + + 2010-11-27 + + + 2011-12-27 + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/dwithin.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/dwithin.xml new file mode 100644 index 0000000000..9b71143a30 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/dwithin.xml @@ -0,0 +1,9 @@ + + + Geometry + + 2488789,289552 + + 1000 + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/intersects.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/intersects.xml new file mode 100644 index 0000000000..6f34074a11 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/intersects.xml @@ -0,0 +1,12 @@ + + + Geometry + + + + 2488789,289552 2588789,289552 2588789,389552 2488789,389552 2488789,289552 + + + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureid.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureid.xml new file mode 100644 index 0000000000..85e7b8f3c0 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureid.xml @@ -0,0 +1,10 @@ + + + + person + me + + + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureidand.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureidand.xml new file mode 100644 index 0000000000..446197772a --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureidand.xml @@ -0,0 +1,10 @@ + + + + person + me + + + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureidnot.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureidnot.xml new file mode 100644 index 0000000000..94ad30468f --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureidnot.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/null.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/null.xml new file mode 100644 index 0000000000..bc0d304e64 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/null.xml @@ -0,0 +1,5 @@ + + + prop + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/within.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/within.xml new file mode 100644 index 0000000000..820ea450fc --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/within.xml @@ -0,0 +1,12 @@ + + + Geometry + + + + 2488789,289552 2588789,289552 2588789,389552 2488789,389552 2488789,289552 + + + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_1_0/bbox.xml b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/bbox.xml new file mode 100644 index 0000000000..9974500d3d --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/bbox.xml @@ -0,0 +1,9 @@ + + + the_geom + + -180 -90 + 180 90 + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_1_0/bbox_nogeomname.xml b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/bbox_nogeomname.xml new file mode 100644 index 0000000000..29a08f44c9 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/bbox_nogeomname.xml @@ -0,0 +1,8 @@ + + + + -180 -90 + 180 90 + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_1_0/customfunction.xml b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/customfunction.xml new file mode 100644 index 0000000000..cebdc718cc --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/customfunction.xml @@ -0,0 +1,11 @@ + + + + FOO + + param1 + param2 + + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_1_0/function.xml b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/function.xml new file mode 100644 index 0000000000..749508778f --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/function.xml @@ -0,0 +1,10 @@ + + + the_geom + + sf:restricted + the_geom + cat=3 + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_1_0/intersects.xml b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/intersects.xml new file mode 100644 index 0000000000..b2b537638b --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/intersects.xml @@ -0,0 +1,9 @@ + + + Geometry + + -180 -90 + 180 90 + + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_1_0/likematchcase.xml b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/likematchcase.xml new file mode 100644 index 0000000000..97225dfcdc --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/likematchcase.xml @@ -0,0 +1,6 @@ + + + person + *me* + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_1_0/nestedfunction.xml b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/nestedfunction.xml new file mode 100644 index 0000000000..9771d40de7 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/nestedfunction.xml @@ -0,0 +1,13 @@ + + + the_geom + + + sf:roads + the_geom + INCLUDE + + + 200 + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_1_0/sortby.xml b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/sortby.xml new file mode 100644 index 0000000000..c229843628 --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/sortby.xml @@ -0,0 +1,10 @@ + + + Title + ASC + + + Relevance + DESC + + diff --git a/test/spec/ol/parser/ogc/xml/filter_v1_1_0/test.xml b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/test.xml new file mode 100644 index 0000000000..f025e4d3be --- /dev/null +++ b/test/spec/ol/parser/ogc/xml/filter_v1_1_0/test.xml @@ -0,0 +1,31 @@ + + + + number + + 1064866676 + + + 1065512599 + + + + cat + *dog.food!*good + + + + FOO + 5000 + + + + cat + dog + + + cat + dog + + +