diff --git a/src/ol/expr/expression.js b/src/ol/expr/expression.js index 81a511bc26..18508f29cf 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.get(opt_attribute) : this.getGeometry(); if (geometry) { intersects = ol.extent.intersects(geometry.getBounds(), [minX, maxX, minY, maxY]); @@ -142,6 +153,72 @@ ol.expr.lib[ol.expr.functions.FID] = function(var_args) { }; +/** + * Determine if two strings are like one another, based on simple pattern + * matching. + * @param {string} value The string to test. + * @param {string} pattern The comparison pattern. + * @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(value, pattern, wildCard, + singleChar, escapeChar, matchCase) { + if (wildCard == '.') { + throw new Error('"." is an unsupported wildCard character for ' + + 'the "like" function'); + } + // set UMN MapServer defaults for unspecified parameters + wildCard = goog.isDef(wildCard) ? wildCard : '*'; + singleChar = goog.isDef(singleChar) ? singleChar : '.'; + escapeChar = goog.isDef(escapeChar) ? escapeChar : '!'; + pattern = pattern.replace( + new RegExp('\\' + escapeChar + '(.|$)', 'g'), '\\$1'); + pattern = pattern.replace( + new RegExp('\\' + singleChar, 'g'), '.'); + pattern = pattern.replace( + new RegExp('\\' + wildCard, 'g'), '.*'); + pattern = pattern.replace( + new RegExp('\\\\.\\*', 'g'), '\\' + wildCard); + pattern = pattern.replace( + new RegExp('\\\\\\.', 'g'), '\\' + singleChar); + var modifiers = (matchCase === false) ? 'gi' : 'g'; + return new RegExp(pattern, modifiers).test(value); +}; + + +/** + * Case insensitive comparison for equality. + * @param {*} first First value. + * @param {*} second Second value. + * @this {ol.Feature} + */ +ol.expr.lib[ol.expr.functions.IEQ] = function(first, second) { + if (goog.isString(first) && goog.isString(second)) { + return first.toUpperCase() == second.toUpperCase(); + } else { + return first == second; + } +}; + + +/** + * Case insensitive comparison for non-equality. + * @param {*} first First value. + * @param {*} second Second value. + * @this {ol.Feature} + */ +ol.expr.lib[ol.expr.functions.INEQ] = function(first, second) { + if (goog.isString(first) && goog.isString(second)) { + return first.toUpperCase() != second.toUpperCase(); + } else { + return first != second; + } +}; + + /** * Determine if a feature's default geometry is of the given type. * @param {ol.geom.GeometryType} type Geometry type. @@ -156,3 +233,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/expr/expressions.js b/src/ol/expr/expressions.js index bd827885ea..1f16e7ff9c 100644 --- a/src/ol/expr/expressions.js +++ b/src/ol/expr/expressions.js @@ -277,12 +277,12 @@ ol.expr.Identifier.prototype.getName = function() { * * @constructor * @extends {ol.expr.Expression} - * @param {string|number|boolean|null} value A literal value. + * @param {string|number|boolean|Date|null} value A literal value. */ ol.expr.Literal = function(value) { /** - * @type {string|number|boolean|null} + * @type {string|number|boolean|Date|null} * @private */ this.value_ = value; @@ -301,7 +301,7 @@ ol.expr.Literal.prototype.evaluate = function() { /** * Get the literal value. - * @return {string|number|boolean|null} The literal value. + * @return {string|number|boolean|Date|null} The literal value. */ ol.expr.Literal.prototype.getValue = function() { return this.value_; 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..1deca301fa --- /dev/null +++ b/src/ol/parser/ogc/filter_v1.js @@ -0,0 +1,607 @@ +goog.provide('ol.parser.ogc.Filter_v1'); +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom.xml'); +goog.require('goog.object'); +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.Literal'); +goog.require('ol.expr.Logical'); +goog.require('ol.expr.LogicalOp'); +goog.require('ol.expr.Math'); +goog.require('ol.expr.MathOp'); +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) { + var expressions = []; + var obj, value, numValue, expr; + for (var child = node.firstChild; child; child = child.nextSibling) { + switch (child.nodeType) { + case 1: + obj = this.readNode(child); + if (obj.property) { + expressions.push(obj.property); + } else if (goog.isDef(obj.value)) { + return obj.value; + } + break; + case 3: // text node + case 4: // cdata section + value = goog.string.trim(child.nodeValue); + // no need to concatenate empty strings + if (value) { + // check for numeric values + numValue = goog.string.toNumber(value); + if (!isNaN(numValue)) { + value = numValue; + } + expressions.push(new ol.expr.Literal(value)); + } + break; + default: + break; + } + } + // if we have more than one property or literal, we concatenate them + var num = expressions.length; + if (num === 1) { + expr = expressions[0]; + } else { + expr = new ol.expr.Literal(''); + if (num > 1) { + var add = ol.expr.MathOp.ADD; + for (var i = 0; i < num; ++i) { + expr = new ol.expr.Math(add, expr, expressions[i]); + } + } + } + return expr; + }, + '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), + goog.object.getValues(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 = {}; + } + if (!obj.fids.hasOwnProperty(fid)) { + obj.fids[fid] = new ol.expr.Literal(fid); + } + } + }, + '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, + new ol.expr.Literal(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 = new ol.expr.Literal(isNaN(value) ? nodeValue : value); + }, + 'PropertyName': function(node, obj) { + obj.property = new ol.expr.Identifier(this.getChildValue(node)); + }, + 'LowerBoundary': function(node, obj) { + var readers = this.readers[this.defaultNamespaceURI]; + obj.lowerBoundary = readers._expression.call(this, node); + }, + 'UpperBoundary': function(node, obj) { + var readers = this.readers[this.defaultNamespaceURI]; + obj.upperBoundary = readers._expression.call(this, node); + }, + _spatial: function(node, obj, identifier) { + var args = [], container = {}; + this.readChildNodes(node, container); + if (goog.isDef(container.geometry)) { + args.push(new ol.expr.Literal(this.gml_.createGeometry(container))); + } else { + args = [new ol.expr.Literal(container.bounds[0]), + new ol.expr.Literal(container.bounds[1]), + new ol.expr.Literal(container.bounds[2]), + new ol.expr.Literal(container.bounds[3])]; + } + if (goog.isDef(container.distance)) { + args.push(container.distance); + } + if (goog.isDef(container.distanceUnits)) { + args.push(container.distanceUnits); + } + args.push(new ol.expr.Literal(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) { + var value = goog.string.toNumber(this.getChildValue(node)); + obj.distance = new ol.expr.Literal(value); + obj.distanceUnits = new ol.expr.Literal(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 args = filter.getArgs(); + for (var i = 0, ii = args.length; i < ii; i++) { + goog.asserts.assert(args[i] instanceof ol.expr.Literal); + this.writeNode('FeatureId', args[i].getValue(), 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 expr = filters[i].getRight(); + if (filters[i].getOperator() === ol.expr.ComparisonOp.GTE) { + lower = expr; + } else if (filters[i].getOperator() === ol.expr.ComparisonOp.LTE) { + upper = expr; + } + } + this.writeNode('LowerBoundary', lower, null, node); + this.writeNode('UpperBoundary', upper, null, node); + return node; + }, + 'PropertyName': function(expr) { + goog.asserts.assert(expr instanceof ol.expr.Identifier); + var node = this.createElementNS('ogc:PropertyName'); + node.appendChild(this.createTextNode(expr.getName())); + return node; + }, + 'Literal': function(expr) { + goog.asserts.assert(expr instanceof ol.expr.Literal); + var node = this.createElementNS('ogc:Literal'); + node.appendChild(this.createTextNode(expr.getValue())); + return node; + }, + 'LowerBoundary': function(expr) { + var node = this.createElementNS('ogc:LowerBoundary'); + this.writeOgcExpression(expr, node); + return node; + }, + 'UpperBoundary': function(expr) { + var node = this.createElementNS('ogc:UpperBoundary'); + this.writeOgcExpression(expr, 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(); + goog.asserts.assert(args[2] instanceof ol.expr.Literal); + node.setAttribute('units', args[2].getValue()); + goog.asserts.assert(args[1] instanceof ol.expr.Literal); + node.appendChild(this.createTextNode(args[1].getValue())); + 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; + } + } + }; + goog.base(this); +}; +goog.inherits(ol.parser.ogc.Filter_v1, ol.parser.XML); + + +/** + * @private + */ +ol.parser.ogc.Filter_v1.filterMap_ = { + '&&': 'And', + '||': 'Or', + '!': 'Not', + '==': 'PropertyIsEqualTo', + '!=': 'PropertyIsNotEqualTo', + '<': 'PropertyIsLessThan', + '>': 'PropertyIsGreaterThan', + '<=': 'PropertyIsLessThanOrEqualTo', + '>=': 'PropertyIsGreaterThanOrEqualTo', + '..': 'PropertyIsBetween', + 'like': 'PropertyIsLike', + 'null': 'PropertyIsNull', + 'extent': 'BBOX', + 'dwithin': 'DWITHIN', + 'within': 'WITHIN', + 'contains': 'CONTAINS', + 'intersects': 'INTERSECTS', + 'fid': '_featureIds', + 'ieq': 'PropertyIsEqualTo', + 'ineq': 'PropertyIsNotEqualTo' +}; + + +/** + * @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 left = filter.getLeft(); + var right = filter.getRight(); + var isNull = (type === ol.expr.ComparisonOp.EQ && + right instanceof ol.expr.Literal && right.getValue() === null); + if (isNull) { + type = 'null'; + } + var isBetween = (type === ol.expr.LogicalOp.AND && + left instanceof ol.expr.Comparison && + right instanceof ol.expr.Comparison && + left.getLeft() instanceof ol.expr.Identifier && + right.getLeft() instanceof ol.expr.Identifier && + left.getLeft().getName() === right.getLeft().getName() && + (left.getOperator() === ol.expr.ComparisonOp.LTE || + left.getOperator() === ol.expr.ComparisonOp.GTE) && + (right.getOperator() === ol.expr.ComparisonOp.LTE || + right.getOperator() === ol.expr.ComparisonOp.GTE)); + if (isBetween) { + type = '..'; + } + } else if (filter instanceof ol.expr.Call) { + var callee = filter.getCallee(); + goog.asserts.assert(callee instanceof ol.expr.Identifier); + type = callee.getName(); + } else if (filter instanceof ol.expr.Not) { + type = '!'; + } + var filterType = ol.parser.ogc.Filter_v1.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.Expression} expr 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(expr, node) { + if (expr instanceof ol.expr.Call) { + this.writeNode('Function', expr, null, node); + } else if (expr instanceof ol.expr.Literal) { + this.writeNode('Literal', expr, null, node); + } else if (expr instanceof ol.expr.Identifier) { + this.writeNode('PropertyName', expr, 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])); + subFilters.length = 0; + } + } + // 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..ddaa2cd18a --- /dev/null +++ b/src/ol/parser/ogc/filter_v1_0_0.js @@ -0,0 +1,179 @@ +goog.provide('ol.parser.ogc.Filter_v1_0_0'); + +goog.require('goog.asserts'); +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.Literal'); +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, + new ol.expr.Literal(node.getAttribute('wildCard')), + new ol.expr.Literal(node.getAttribute('singleChar')), + new ol.expr.Literal(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(); + 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(); + 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(); + goog.asserts.assert(args[2] instanceof ol.expr.Literal); + node.setAttribute('wildCard', args[2].getValue()); + goog.asserts.assert(args[3] instanceof ol.expr.Literal); + node.setAttribute('singleChar', args[3].getValue()); + goog.asserts.assert(args[4] instanceof ol.expr.Literal); + node.setAttribute('escape', args[4].getValue()); + 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(); + goog.asserts.assert(args[0] instanceof ol.expr.Literal); + goog.asserts.assert(args[1] instanceof ol.expr.Literal); + goog.asserts.assert(args[2] instanceof ol.expr.Literal); + goog.asserts.assert(args[3] instanceof ol.expr.Literal); + goog.asserts.assert(args[4] instanceof ol.expr.Literal); + var property = args[5], bbox = [args[0].getValue(), args[1].getValue(), + args[2].getValue(), args[3].getValue()], + projection = args[4].getValue(); + // 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 (args[0] instanceof ol.expr.Literal && goog.isNumber(args[0].getValue())) { + goog.asserts.assert(args[1] instanceof ol.expr.Literal); + goog.asserts.assert(args[2] instanceof ol.expr.Literal); + goog.asserts.assert(args[3] instanceof ol.expr.Literal); + bbox = [args[0].getValue(), args[1].getValue(), args[2].getValue(), + args[3].getValue()]; + projection = args[4]; + property = args[5]; + } else if (args[0] instanceof ol.expr.Literal && + args[0].getValue() instanceof ol.geom.Geometry) { + geom = args[0].getValue(); + 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)) { + goog.asserts.assert(projection instanceof ol.expr.Literal); + if (goog.isDefAndNotNull(projection.getValue())) { + child.setAttribute('srsName', projection.getValue()); + } + 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..a1c7e47f43 --- /dev/null +++ b/src/ol/parser/ogc/filter_v1_1_0.js @@ -0,0 +1,237 @@ +goog.provide('ol.parser.ogc.Filter_v1_1_0'); + +goog.require('goog.asserts'); +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.Literal'); +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, + new ol.expr.Literal(node.getAttribute('wildCard')), + new ol.expr.Literal(node.getAttribute('singleChar')), + new ol.expr.Literal(node.getAttribute('escapeChar')), + new ol.expr.Literal(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(); + goog.asserts.assert(args[2] instanceof ol.expr.Literal); + goog.asserts.assert(args[3] instanceof ol.expr.Literal); + goog.asserts.assert(args[4] instanceof ol.expr.Literal); + node.setAttribute('wildCard', args[2].getValue()); + node.setAttribute('singleChar', args[3].getValue()); + node.setAttribute('escapeChar', args[4].getValue()); + if (goog.isDefAndNotNull(args[5])) { + goog.asserts.assert(args[5] instanceof ol.expr.Literal); + node.setAttribute('matchCase', args[5].getValue()); + } + 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(); + goog.asserts.assert(args[0] instanceof ol.expr.Literal); + goog.asserts.assert(args[1] instanceof ol.expr.Literal); + goog.asserts.assert(args[2] instanceof ol.expr.Literal); + goog.asserts.assert(args[3] instanceof ol.expr.Literal); + goog.asserts.assert(args[4] instanceof ol.expr.Literal); + var property = args[5], bbox = [args[0].getValue(), args[1].getValue(), + args[2].getValue(), args[3].getValue()], + projection = args[4].getValue(); + // 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); + goog.asserts.assert(sortProperty['order'] instanceof ol.expr.Literal); + this.writeNode('SortOrder', + (sortProperty['order'].getValue() == '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 (args[0] instanceof ol.expr.Literal && goog.isNumber(args[0].getValue())) { + goog.asserts.assert(args[1] instanceof ol.expr.Literal); + goog.asserts.assert(args[2] instanceof ol.expr.Literal); + goog.asserts.assert(args[3] instanceof ol.expr.Literal); + bbox = [args[0].getValue(), args[1].getValue(), args[2].getValue(), + args[3].getValue()]; + projection = args[4]; + property = args[5]; + } else if (args[0] instanceof ol.expr.Literal && + args[0].getValue() instanceof ol.geom.Geometry) { + geom = args[0].getValue(); + 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)) { + goog.asserts.assert(projection instanceof ol.expr.Literal); + if (goog.isDefAndNotNull(projection.getValue())) { + child.setAttribute('srsName', projection.getValue()); + } + node.appendChild(child); + } + } + return node; +}; diff --git a/src/ol/parser/ogc/gml.js b/src/ol/parser/ogc/gml.js index d48f2ab0e7..e2d510fb0f 100644 --- a/src/ol/parser/ogc/gml.js +++ b/src/ol/parser/ogc/gml.js @@ -310,7 +310,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); @@ -460,7 +460,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; @@ -550,13 +550,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) { @@ -600,7 +599,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 708ec8451f..b32aa1af11 100644 --- a/src/ol/parser/ogc/gml_v2.js +++ b/src/ol/parser/ogc/gml_v2.js @@ -31,6 +31,7 @@ ol.parser.ogc.GML_v2 = function(opt_options) { this.readers[this.defaultNamespaceURI]['_inherit'].apply(this, [node, coordinates, container]); 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]]; } @@ -100,10 +101,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 93839513eb..a9e5706a2d 100644 --- a/src/ol/parser/ogc/gml_v3.js +++ b/src/ol/parser/ogc/gml_v3.js @@ -56,7 +56,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; @@ -211,6 +211,7 @@ ol.parser.ogc.GML_v3 = function(opt_options) { this.readers[this.defaultNamespaceURI]['_inherit'].apply(this, [node, coordinates, container]); 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]]; }, @@ -387,9 +388,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)); @@ -399,9 +400,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/expr/expression.test.js b/test/spec/ol/expr/expression.test.js index 30b52945d5..3e6724283f 100644 --- a/test/spec/ol/expr/expression.test.js +++ b/test/spec/ol/expr/expression.test.js @@ -758,6 +758,74 @@ describe('ol.expr.lib', function() { }); + describe('like()', function() { + + var one = new ol.Feature({foo: 'bar'}); + var two = new ol.Feature({foo: 'baz'}); + var three = new ol.Feature({foo: 'foo'}); + + var like = parse('like(foo, "ba")'); + + it('First and second feature match, third does not', function() { + expect(evaluate(like, one), true); + expect(evaluate(like, two), true); + expect(evaluate(like, three), false); + }); + + var uclike = parse('like(foo, "BA")'); + it('Matchcase is true by default', function() { + expect(evaluate(uclike, one), false); + expect(evaluate(uclike, two), false); + expect(evaluate(uclike, three), false); + }); + + var ilike = parse('like(foo, "BA", "*", ".", "!", false)'); + it('Using matchcase false, first two features match again', function() { + expect(evaluate(ilike, one), true); + expect(evaluate(ilike, two), true); + expect(evaluate(uclike, three), false); + }); + + }); + + describe('ieq()', function() { + + var one = new ol.Feature({foo: 'Bar'}); + var two = new ol.Feature({bar: 'Foo'}); + + var ieq1 = parse('ieq(foo, "bar")'); + var ieq2 = parse('ieq("foo", bar)'); + + it('case-insensitive equality for an attribute', function() { + expect(evaluate(ieq1, one), true); + }); + + it('case-insensitive equality for an attribute as second argument', + function() { + expect(evaluate(ieq2, two), true); + }); + + }); + + describe('ineq()', function() { + + var one = new ol.Feature({foo: 'Bar'}); + var two = new ol.Feature({bar: 'Foo'}); + + var ieq1 = parse('ineq(foo, "bar")'); + var ieq2 = parse('ineq("foo", bar)'); + + it('case-insensitive non-equality for an attribute', function() { + expect(evaluate(ieq1, one), false); + }); + + it('case-insensitive non-equality for an attribute as second argument', + function() { + expect(evaluate(ieq2, two), false); + }); + + }); + }); describe('ol.expr.register()', function() { 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..be7de99cee --- /dev/null +++ b/test/spec/ol/parser/ogc/filter_v1_0_0.test.js @@ -0,0 +1,270 @@ +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('reading and writing', function() { + + it('handles intersects', 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.equal( + ol.expr.functions.INTERSECTS); + var args = filter.getArgs(); + var geom = args[0]; + expect(geom.getValue() instanceof ol.geom.Polygon).to.be(true); + expect(args[2].getName()).to.equal('Geometry'); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('handles within', 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.equal(ol.expr.functions.WITHIN); + var args = filter.getArgs(); + var geom = args[0]; + expect(geom.getValue() instanceof ol.geom.Polygon).to.be(true); + expect(args[2].getName()).to.equal('Geometry'); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('handles contains', 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.equal( + ol.expr.functions.CONTAINS); + var args = filter.getArgs(); + var geom = args[0]; + expect(geom.getValue() instanceof ol.geom.Polygon).to.be(true); + expect(args[2].getName()).to.equal('Geometry'); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('handles between', 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).to.be.a(ol.expr.Logical); + expect(filter.getOperator()).to.equal(ol.expr.LogicalOp.AND); + expect(filter.getLeft()).to.be.a(ol.expr.Comparison); + expect(filter.getLeft().getOperator()).to.equal( + ol.expr.ComparisonOp.GTE); + expect(filter.getLeft().getLeft().getName()).to.equal('number'); + expect(filter.getLeft().getRight().getValue()).to.equal(0); + expect(filter.getRight()).to.be.a(ol.expr.Comparison); + expect(filter.getRight().getOperator()).to.equal( + ol.expr.ComparisonOp.LTE); + expect(filter.getRight().getLeft().getName()).to.equal('number'); + expect(filter.getRight().getRight().getValue()).to.equal(100); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('handles between 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).to.be.a(ol.expr.Logical); + expect(filter.getOperator()).to.equal(ol.expr.LogicalOp.AND); + expect(filter.getLeft()).to.be.a(ol.expr.Comparison); + expect(filter.getLeft().getOperator()).to.equal( + ol.expr.ComparisonOp.GTE); + expect(filter.getLeft().getLeft().getName()).to.equal('number'); + expect(filter.getLeft().getRight().getValue()).to.equal(0); + expect(filter.getRight()).to.be.a(ol.expr.Comparison); + expect(filter.getRight().getOperator()).to.equal( + ol.expr.ComparisonOp.LTE); + expect(filter.getRight().getLeft().getName()).to.equal('number'); + expect(filter.getRight().getRight().getValue()).to.equal(100); + done(); + }); + }); + + it('handles null', 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).to.be.a(ol.expr.Comparison); + expect(filter.getLeft().getName()).to.equal('prop'); + expect(filter.getRight().getValue()).to.equal(null); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('writes BBOX', 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), + [new ol.expr.Literal(-180), new ol.expr.Literal(-90), + new ol.expr.Literal(180), new ol.expr.Literal(90), + new ol.expr.Literal('EPSG:4326'), + new ol.expr.Identifier('the_geom')]); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('writes BBOX without geometry name', 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), + [new ol.expr.Literal(-180), new ol.expr.Literal(-90), + new ol.expr.Literal(180), new ol.expr.Literal(90), + new ol.expr.Literal('EPSG:4326')]); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('reads DWithin', function(done) { + var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/dwithin.xml'; + afterLoadXml(url, function(xml) { + var filter = parser.read(xml); + expect(filter).to.be.a(ol.expr.Call); + var callee = filter.getCallee(); + expect(callee).to.be.a(ol.expr.Identifier); + var name = callee.getName(); + expect(name).to.equal(ol.expr.functions.DWITHIN); + var args = filter.getArgs(); + expect(args.length).to.equal(5); + var distance = args[1]; + expect(distance).to.be.a(ol.expr.Literal); + expect(distance.getValue()).to.equal(1000); + var units = args[2]; + expect(units).to.be.a(ol.expr.Literal); + expect(units.getValue()).to.equal('m'); + done(); + }); + }); + + it('writes DWithin', 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.expr.Literal(new ol.geom.Point([2488789, 289552])), + new ol.expr.Literal(1000), new ol.expr.Literal('m'), + new ol.expr.Literal(null), new ol.expr.Identifier('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('logical fid', function() { + + it('writes logical [OR] with fid', 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), + [new ol.expr.Identifier('person'), new ol.expr.Literal('me'), + new ol.expr.Literal('*'), new ol.expr.Literal('.'), + new ol.expr.Literal('!')]), + new ol.expr.Call(new ol.expr.Identifier(ol.expr.functions.FID), + [new ol.expr.Literal('foo.1'), new ol.expr.Literal('foo.2')])); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('writes logical [AND] with fid', + 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), + [new ol.expr.Identifier('person'), new ol.expr.Literal('me'), + new ol.expr.Literal('*'), new ol.expr.Literal('.'), + new ol.expr.Literal('!')]), + new ol.expr.Call(new ol.expr.Identifier(ol.expr.functions.FID), + [new ol.expr.Literal('foo.1'), new ol.expr.Literal('foo.2')])); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('writes logical [NOT] with fid', + 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), + [new ol.expr.Literal('foo.2')])); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + }); + + describe('_expression reader', function() { + it('handles combined propertyname and literal', + function() { + var xml = '10'; + var reader = parser.readers['http://www.opengis.net/ogc'][ + '_expression']; + var expr = reader.call(parser, goog.dom.xml.loadXml( + xml).documentElement); + expect(expr).to.be.a(ol.expr.Literal); + expect(expr.getValue()).to.equal(10); + xml = '' + + 'fooxbar'; + expr = reader.call(parser, goog.dom.xml.loadXml(xml).documentElement); + expect(expr.evaluate({x: 4})).to.eql('foo4bar'); + }); + }); + +}); + +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.Literal'); +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..b39fc59a0f --- /dev/null +++ b/test/spec/ol/parser/ogc/filter_v1_1_0.test.js @@ -0,0 +1,245 @@ +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('reading and writing', function() { + + it('reads filter', 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.equal(ol.expr.LogicalOp.OR); + var filters = []; + parser.getSubfiltersForLogical_(filter, filters); + expect(filters.length).to.equal(5); + expect(filters[0]).to.eql(new ol.expr.Logical(ol.expr.LogicalOp.AND, + new ol.expr.Comparison( + ol.expr.ComparisonOp.GTE, new ol.expr.Identifier('number'), + new ol.expr.Literal(1064866676)), + new ol.expr.Comparison( + ol.expr.ComparisonOp.LTE, new ol.expr.Identifier('number'), + new ol.expr.Literal(1065512599)))); + expect(filters[1]).to.eql(new ol.expr.Not(new ol.expr.Comparison( + ol.expr.ComparisonOp.LTE, new ol.expr.Identifier('FOO'), + new ol.expr.Literal(5000)))); + expect(filters[2] instanceof ol.expr.Call).to.be(true); + expect(filters[2].getCallee().getName()).to.equal( + ol.expr.functions.LIKE); + expect(filters[2].getArgs()).to.eql([new ol.expr.Identifier('cat'), + new ol.expr.Literal('*dog.food!*good'), new ol.expr.Literal('*'), + new ol.expr.Literal('.'), new ol.expr.Literal('!'), + new ol.expr.Literal(null)]); + expect(filters[3] instanceof ol.expr.Call).to.be(true); + expect(filters[3].getCallee().getName()).to.equal( + ol.expr.functions.IEQ); + expect(filters[3].getArgs()).to.eql([new ol.expr.Identifier('cat'), + new ol.expr.Literal('dog')]); + expect(filters[4] instanceof ol.expr.Comparison).to.be(true); + expect(filters[4].getOperator()).to.equal(ol.expr.ComparisonOp.EQ); + expect(filters[4].getLeft().getName()).to.equal('cat'); + expect(filters[4].getRight().getValue()).to.equal('dog'); + done(); + }); + }); + + it('reads matchCase', 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.equal(c.exp); + } + }); + + it('writes BBOX', 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('writes BBOX without property name', 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('handles intersects', 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('handles functions', 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'), + [new ol.expr.Literal('sf:restricted'), + new ol.expr.Literal('the_geom'), + new ol.expr.Literal('cat=3')]), new ol.expr.Literal(null), + new ol.expr.Identifier('the_geom')]); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('writes custom functions', 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), + [new ol.expr.Identifier('FOO'), new ol.expr.Call( + new ol.expr.Identifier('customFunction'), + [new ol.expr.Literal('param1'), new ol.expr.Literal('param2')])])); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('writes nested functions', 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'), + [new ol.expr.Literal('sf:roads'), + new ol.expr.Literal('the_geom'), + new ol.expr.Literal('INCLUDE')])]), new ol.expr.Literal(200), + new ol.expr.Literal('meters'), + new ol.expr.Literal(null), new ol.expr.Identifier('the_geom')]); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('writes matchCase on like', 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), + [new ol.expr.Identifier('person'), new ol.expr.Literal('*me*'), + new ol.expr.Literal('*'), new ol.expr.Literal('.'), + new ol.expr.Literal('!'), new ol.expr.Literal(false)]); + var output = parser.write(filter); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('writes sortBy on like', 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': new ol.expr.Identifier('Title'), + 'order': new ol.expr.Literal('ASC') + },{ + 'property': new ol.expr.Identifier('Relevance'), + 'order': new ol.expr.Literal('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.Literal'); +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 9c7fc69be9..9f564d5284 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.applyWriteOptions(obj); - var geom = parser.createGeometry_({geometry: obj.geometry}); + var geom = parser.createGeometry({geometry: obj.geometry}); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; delete parser.srsName; @@ -47,7 +47,7 @@ describe('ol.parser.gml_v2', function() { var url = 'spec/ol/parser/ogc/xml/gml_v2/multipoint-coordinates.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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -77,7 +77,7 @@ describe('ol.parser.gml_v2', function() { var url = 'spec/ol/parser/ogc/xml/gml_v2/linestring-coordinates.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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -106,7 +106,7 @@ describe('ol.parser.gml_v2', function() { var url = 'spec/ol/parser/ogc/xml/gml_v2/multilinestring-coordinates.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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -141,7 +141,7 @@ describe('ol.parser.gml_v2', function() { var url = 'spec/ol/parser/ogc/xml/gml_v2/polygon-coordinates.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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -166,7 +166,7 @@ describe('ol.parser.gml_v2', function() { var url = 'spec/ol/parser/ogc/xml/gml_v2/multipolygon-coordinates.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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -185,7 +185,7 @@ describe('ol.parser.gml_v2', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v2({featureNS: 'http://foo'}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); p.applyWriteOptions(obj); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; @@ -230,7 +230,7 @@ describe('ol.parser.gml_v2', function() { var url = 'spec/ol/parser/ogc/xml/gml_v2/linearring-coordinates.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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; diff --git a/test/spec/ol/parser/ogc/gml_v3.test.js b/test/spec/ol/parser/ogc/gml_v3.test.js index 8e72fccfdb..9bd2fc869d 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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -34,7 +34,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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -61,7 +61,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v3({curve: true}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); p.applyWriteOptions(obj); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; @@ -89,7 +89,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v3({multiCurve: false}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); p.applyWriteOptions(obj); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; @@ -106,7 +106,7 @@ describe('ol.parser.gml_v3', function() { var url = 'spec/ol/parser/ogc/xml/gml_v3/multicurve-singular.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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -125,7 +125,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v3({curve: true}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); p.applyWriteOptions(obj); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; @@ -154,7 +154,7 @@ describe('ol.parser.gml_v3', function() { var url = 'spec/ol/parser/ogc/xml/gml_v3/multipoint-singular.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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -183,7 +183,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v3({multiSurface: false}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); p.applyWriteOptions(obj); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; @@ -210,7 +210,7 @@ describe('ol.parser.gml_v3', function() { var url = 'spec/ol/parser/ogc/xml/gml_v3/multisurface-singular.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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -228,7 +228,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v3({surface: true}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); p.applyWriteOptions(obj); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; @@ -245,7 +245,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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -261,7 +261,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.applyWriteOptions(obj); var node = parser.featureNSWiters_['_geometry'].apply(parser, [geom]).firstChild; @@ -277,7 +277,7 @@ describe('ol.parser.gml_v3', function() { afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.GML_v3({surface: true}); var obj = p.read(xml); - var geom = p.createGeometry_({geometry: obj.geometry}); + var geom = p.createGeometry({geometry: obj.geometry}); p.applyWriteOptions(obj, {srsName: 'foo'}); var node = p.featureNSWiters_['_geometry'].apply(p, [geom]).firstChild; 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/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/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 + + +