From ab40ab620858097b85b5dce5639df7e4b24d63b2 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Mon, 1 Jul 2013 13:46:41 +0200 Subject: [PATCH 01/14] Add parser for OGC Filter 1.0 and 1.1 (read/write) This work is based on the ol.expr package by @tschaub. It adds a few named expression functions to that package: * INTERSECTS, CONTAINS, DWITHIN, WITHIN (no client-side implementation as yet) * LIKE (like comparison with wildcard, singleChar and escapeChar) * IEQ (case-insensitive equality) * INEQ (case-insensitive non-equality) It also adds a few extra parameters to the existing EXTENT function to be able to deserialize and serialize all info (i.e. projection and property name). Some changes were needed for the GML parser as well: * createGeometry function needed to be public * when parsing Box (GML2) and Envelope (GML3) also parse the srsName * fix up writing for Box and Envelope now that bounds is an array Also added createDocumentFragment function to the XML parser. Implementation is similar to OpenLayers 2. Some addtional notes on the implementation: * PropertyIsBetween was implemented as an ol.expr.Logical with operator ol.expr.LogicalOp.AND and two ol.expr.Comparison instances with operator ol.expr.ComparisonOp.GTE and ol.expr.ComparisonOp.LTE * In OGC Filter And and Or can contain more than 2 sub filters, so this is translated into a hierarchy of ol.expr.Logical --- src/ol/expr/expression.js | 114 +++- src/ol/parser/ogc/filter.js | 37 ++ src/ol/parser/ogc/filter_v1.js | 582 ++++++++++++++++++ src/ol/parser/ogc/filter_v1_0_0.js | 167 +++++ src/ol/parser/ogc/filter_v1_1_0.js | 217 +++++++ src/ol/parser/ogc/gml.js | 9 +- src/ol/parser/ogc/gml_v2.js | 7 +- src/ol/parser/ogc/gml_v3.js | 11 +- src/ol/parser/xml.js | 24 +- test/spec/ol/parser/ogc/filter_v1_0_0.test.js | 238 +++++++ test/spec/ol/parser/ogc/filter_v1_1_0.test.js | 230 +++++++ test/spec/ol/parser/ogc/gml_v2.test.js | 16 +- test/spec/ol/parser/ogc/gml_v3.test.js | 26 +- test/spec/ol/parser/ogc/xml/filter_v1_0_0.xml | 23 + .../ol/parser/ogc/xml/filter_v1_0_0/bbox.xml | 8 + .../ogc/xml/filter_v1_0_0/bbox_nogeom.xml | 7 + .../parser/ogc/xml/filter_v1_0_0/between.xml | 11 + .../parser/ogc/xml/filter_v1_0_0/between2.xml | 7 + .../ogc/xml/filter_v1_0_0/betweendates.xml | 11 + .../parser/ogc/xml/filter_v1_0_0/contains.xml | 12 + .../xml/filter_v1_0_0/custombetweendates.xml | 11 + .../parser/ogc/xml/filter_v1_0_0/dwithin.xml | 9 + .../ogc/xml/filter_v1_0_0/intersects.xml | 12 + .../xml/filter_v1_0_0/logicalfeatureid.xml | 10 + .../xml/filter_v1_0_0/logicalfeatureidand.xml | 10 + .../xml/filter_v1_0_0/logicalfeatureidnot.xml | 5 + .../ol/parser/ogc/xml/filter_v1_0_0/null.xml | 5 + .../parser/ogc/xml/filter_v1_0_0/within.xml | 12 + .../ol/parser/ogc/xml/filter_v1_1_0/bbox.xml | 9 + .../ogc/xml/filter_v1_1_0/bbox_nogeomname.xml | 8 + .../ogc/xml/filter_v1_1_0/customfunction.xml | 11 + .../parser/ogc/xml/filter_v1_1_0/function.xml | 10 + .../ogc/xml/filter_v1_1_0/intersects.xml | 9 + .../ogc/xml/filter_v1_1_0/likematchcase.xml | 6 + .../ogc/xml/filter_v1_1_0/nestedfunction.xml | 13 + .../parser/ogc/xml/filter_v1_1_0/sortby.xml | 10 + .../ol/parser/ogc/xml/filter_v1_1_0/test.xml | 31 + 37 files changed, 1899 insertions(+), 39 deletions(-) create mode 100644 src/ol/parser/ogc/filter.js create mode 100644 src/ol/parser/ogc/filter_v1.js create mode 100644 src/ol/parser/ogc/filter_v1_0_0.js create mode 100644 src/ol/parser/ogc/filter_v1_1_0.js create mode 100644 test/spec/ol/parser/ogc/filter_v1_0_0.test.js create mode 100644 test/spec/ol/parser/ogc/filter_v1_1_0.test.js create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/bbox.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/bbox_nogeom.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/between.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/between2.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/betweendates.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/contains.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/custombetweendates.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/dwithin.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/intersects.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureid.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureidand.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/logicalfeatureidnot.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/null.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/within.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_1_0/bbox.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_1_0/bbox_nogeomname.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_1_0/customfunction.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_1_0/function.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_1_0/intersects.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_1_0/likematchcase.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_1_0/nestedfunction.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_1_0/sortby.xml create mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_1_0/test.xml 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 + + + From 499319fb99928e7a44648e9e160a5e3363c43b8a Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Mon, 8 Jul 2013 17:04:27 +0200 Subject: [PATCH 02/14] address most of @tschaub's review comments, use dot notation where possible still needs to be done, and I have some questions on the _expression reader still --- src/ol/expr/expression.js | 23 ++- src/ol/expr/expressions.js | 6 +- src/ol/parser/ogc/filter_v1.js | 182 +++++++++--------- src/ol/parser/ogc/filter_v1_0_0.js | 54 ++++-- src/ol/parser/ogc/filter_v1_1_0.js | 54 ++++-- test/spec/ol/parser/ogc/filter_v1_0_0.test.js | 87 +++++---- test/spec/ol/parser/ogc/filter_v1_1_0.test.js | 65 ++++--- 7 files changed, 266 insertions(+), 205 deletions(-) diff --git a/src/ol/expr/expression.js b/src/ol/expr/expression.js index 277364d750..bc732e825f 100644 --- a/src/ol/expr/expression.js +++ b/src/ol/expr/expression.js @@ -123,7 +123,7 @@ ol.expr.lib[ol.expr.functions.EXTENT] = function(minX, maxX, minY, maxY, opt_projection, opt_attribute) { var intersects = false; var geometry = goog.isDef(opt_attribute) ? - this.getAttributes()[opt_attribute] : this.getGeometry(); + this.get(opt_attribute) : this.getGeometry(); if (geometry) { intersects = ol.extent.intersects(geometry.getBounds(), [minX, maxX, minY, maxY]); @@ -167,7 +167,7 @@ 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'); + 'the "like" function'); } // set UMN MapServer defaults for unspecified parameters wildCard = goog.isDef(wildCard) ? wildCard : '*'; @@ -184,9 +184,8 @@ ol.expr.lib[ol.expr.functions.LIKE] = function(attribute, value, wildCard, 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]); + return new RegExp(val, modifiers).test(this.get(attribute)); }; @@ -197,11 +196,11 @@ ol.expr.lib[ol.expr.functions.LIKE] = function(attribute, value, wildCard, * @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(); + var attributeValue = this.get(attribute); + if (goog.isString(value) && goog.isString(attributeValue)) { + return value.toUpperCase() == attributeValue.toUpperCase(); } else { - return value == attributes[attribute]; + return value == attributeValue; } }; @@ -213,11 +212,11 @@ ol.expr.lib[ol.expr.functions.IEQ] = function(attribute, value) { * @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(); + var attributeValue = this.get(attribute); + if (goog.isString(value) && goog.isString(attributeValue)) { + return value.toUpperCase() == attributeValue.toUpperCase(); } else { - return value != attributes[attribute]; + return value != attributeValue; } }; 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_v1.js b/src/ol/parser/ogc/filter_v1.js index 4b7f1063ec..3085e1397d 100644 --- a/src/ol/parser/ogc/filter_v1.js +++ b/src/ol/parser/ogc/filter_v1.js @@ -1,12 +1,15 @@ 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.Not'); @@ -24,18 +27,18 @@ ol.parser.ogc.Filter_v1 = function() { 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" + _expression: function(node) { 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']; + value += obj['property'].getName(); } else if (goog.isDef(obj['value'])) { - value += obj['value']; + // TODO adding this to value and then parsing causes + // ol.expr.UnexpectedToken on e.g. 10 + return obj['value']; } break; case 3: // text node @@ -46,17 +49,17 @@ ol.parser.ogc.Filter_v1 = function() { break; } } - return value; + return ol.expr.parse(value); }, 'Filter': function(node, obj) { var container = { 'filters': [] }; this.readChildNodes(node, container); - if (goog.isDef(container['fids'])) { + if (goog.isDef(container.fids)) { obj['filter'] = new ol.expr.Call( new ol.expr.Identifier(ol.expr.functions.FID), - container['fids']); + goog.object.getValues(container.fids)); } else if (container['filters'].length > 0) { obj['filter'] = container['filters'][0]; } @@ -64,10 +67,12 @@ ol.parser.ogc.Filter_v1 = function() { 'FeatureId': function(node, obj) { var fid = node.getAttribute('fid'); if (fid) { - if (!goog.isDef(obj['fids'])) { - obj['fids'] = {}; + if (!goog.isDef(obj.fids)) { + obj.fids = {}; + } + if (!obj.fids.hasOwnProperty(fid)) { + obj.fids[fid] = new ol.expr.Literal(fid); } - obj['fids'][fid] = true; } }, 'And': function(node, obj) { @@ -97,7 +102,7 @@ ol.parser.ogc.Filter_v1 = function() { obj['filters'].push(new ol.expr.Comparison( ol.expr.ComparisonOp.EQ, container['property'], - null)); + new ol.expr.Literal(null))); }, 'PropertyIsLessThan': function(node, obj) { var container = {}; @@ -143,28 +148,29 @@ ol.parser.ogc.Filter_v1 = function() { 'Literal': function(node, obj) { var nodeValue = this.getChildValue(node); var value = goog.string.toNumber(nodeValue); - obj['value'] = isNaN(value) ? nodeValue : value; + obj['value'] = new ol.expr.Literal(isNaN(value) ? nodeValue : value); }, 'PropertyName': function(node, obj) { - obj['property'] = this.getChildValue(node); + obj['property'] = new ol.expr.Identifier(this.getChildValue(node)); }, 'LowerBoundary': function(node, obj) { var readers = this.readers[this.defaultNamespaceURI]; - obj['lowerBoundary'] = goog.string.toNumber( - readers['_expression'].call(this, node)); + obj['lowerBoundary'] = 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)); + obj['upperBoundary'] = readers._expression.call(this, node); }, - '_spatial': function(node, obj, identifier) { + _spatial: function(node, obj, identifier) { var args = [], container = {}; this.readChildNodes(node, container); if (goog.isDef(container.geometry)) { - args.push(this.gml_.createGeometry(container)); + args.push(new ol.expr.Literal(this.gml_.createGeometry(container))); } else { - args = container['bounds']; + 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']); @@ -172,7 +178,7 @@ ol.parser.ogc.Filter_v1 = function() { if (goog.isDef(container['distanceUnits'])) { args.push(container['distanceUnits']); } - args.push(container['projection']); + args.push(new ol.expr.Literal(container.projection)); if (goog.isDef(container['property'])) { args.push(container['property']); } @@ -181,32 +187,32 @@ ol.parser.ogc.Filter_v1 = function() { }, 'BBOX': function(node, obj) { var readers = this.readers[this.defaultNamespaceURI]; - readers['_spatial'].call(this, node, obj, + 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, + 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, + 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, + 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, + 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'); + obj['distance'] = new ol.expr.Literal(this.getChildValue(node)); + obj['distanceUnits'] = new ol.expr.Literal(node.getAttribute('units')); } } }; @@ -219,9 +225,10 @@ ol.parser.ogc.Filter_v1 = function() { }, '_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); + 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; }, @@ -296,23 +303,26 @@ ol.parser.ogc.Filter_v1 = function() { filters[0] = filter.getLeft(); filters[1] = filter.getRight(); for (var i = 0; i < 2; ++i) { - var value = filters[i].getRight(); + var expr = filters[i].getRight(); if (filters[i].getOperator() === ol.expr.ComparisonOp.GTE) { - lower = value; + lower = expr; } else if (filters[i].getOperator() === ol.expr.ComparisonOp.LTE) { - upper = value; + upper = expr; } } this.writeNode('LowerBoundary', lower, null, node); this.writeNode('UpperBoundary', upper, null, node); return node; }, - 'PropertyName': function(name) { + 'PropertyName': function(expr) { + goog.asserts.assert(expr instanceof ol.expr.Identifier); var node = this.createElementNS('ogc:PropertyName'); - node.appendChild(this.createTextNode(name)); + node.appendChild(this.createTextNode(expr.getName())); return node; }, - 'Literal': function(value) { + 'Literal': function(expr) { + goog.asserts.assert(expr instanceof ol.expr.Literal); + var value = expr.getValue(); if (value instanceof Date) { value = value.toISOString(); } @@ -320,14 +330,14 @@ ol.parser.ogc.Filter_v1 = function() { node.appendChild(this.createTextNode(value)); return node; }, - 'LowerBoundary': function(value) { + 'LowerBoundary': function(expr) { var node = this.createElementNS('ogc:LowerBoundary'); - this.writeOgcExpression(value, node); + this.writeOgcExpression(expr, node); return node; }, - 'UpperBoundary': function(value) { + 'UpperBoundary': function(expr) { var node = this.createElementNS('ogc:UpperBoundary'); - this.writeOgcExpression(value, node); + this.writeOgcExpression(expr, node); return node; }, 'INTERSECTS': function(filter) { @@ -347,8 +357,10 @@ ol.parser.ogc.Filter_v1 = function() { 'Distance': function(filter) { var node = this.createElementNS('ogc:Distance'); var args = filter.getArgs(); - node.setAttribute('units', args[2]); - node.appendChild(this.createTextNode(args[1])); + 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) { @@ -378,14 +390,16 @@ ol.parser.ogc.Filter_v1 = function() { '<=': 'PropertyIsLessThanOrEqualTo', '>=': 'PropertyIsGreaterThanOrEqualTo', '..': 'PropertyIsBetween', - '~': 'PropertyIsLike', - 'NULL': 'PropertyIsNull', - 'BBOX': 'BBOX', - 'DWITHIN': 'DWITHIN', - 'WITHIN': 'WITHIN', - 'CONTAINS': 'CONTAINS', - 'INTERSECTS': 'INTERSECTS', - 'FID': '_featureIds' + 'like': 'PropertyIsLike', + 'null': 'PropertyIsNull', + 'extent': 'BBOX', + 'dwithin': 'DWITHIN', + 'within': 'WITHIN', + 'contains': 'CONTAINS', + 'intersects': 'INTERSECTS', + 'fid': '_featureIds', + 'ieq': 'PropertyIsEqualTo', + 'ineq': 'PropertyIsNotEqualTo' }; goog.base(this); }; @@ -402,46 +416,30 @@ ol.parser.ogc.Filter_v1.prototype.getFilterType_ = function(filter) { 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 && - filter.getRight() === null); + right instanceof ol.expr.Literal && right.getValue() === null); if (isNull) { - type = 'NULL'; + 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)); + 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().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'; - } + var callee = filter.getCallee(); + goog.asserts.assert(callee instanceof ol.expr.Identifier); + type = callee.getName(); } else if (filter instanceof ol.expr.Not) { type = '!'; } @@ -484,16 +482,18 @@ ol.parser.ogc.Filter_v1.prototype.write = function(filter) { /** - * @param {ol.expr.Call|string|number} value The value write out. + * @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(value, node) { - if (value instanceof ol.expr.Call) { - this.writeNode('Function', value, null, node); - } else { - this.writeNode('Literal', value, null, node); +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; }; @@ -540,7 +540,7 @@ ol.parser.ogc.Filter_v1.prototype.aggregateLogical_ = function(filters, if (subFilters.length === 2) { newFilters.push(new ol.expr.Logical(operator, subFilters[0], subFilters[1])); - goog.array.clear(subFilters); + subFilters.length = 0; } } // there could be a single item left now diff --git a/src/ol/parser/ogc/filter_v1_0_0.js b/src/ol/parser/ogc/filter_v1_0_0.js index 7bbc07f568..bcf2874935 100644 --- a/src/ol/parser/ogc/filter_v1_0_0.js +++ b/src/ol/parser/ogc/filter_v1_0_0.js @@ -1,11 +1,13 @@ 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'); @@ -44,10 +46,9 @@ ol.parser.ogc.Filter_v1_0_0 = function() { this.readChildNodes(node, container); var args = []; args.push(container['property'], container['value'], - node.getAttribute('wildCard'), - node.getAttribute('singleChar'), - node.getAttribute('escape') - ); + 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)); } @@ -56,27 +57,26 @@ ol.parser.ogc.Filter_v1_0_0 = function() { 'PropertyIsEqualTo': function(filter) { var node = this.createElementNS('ogc:PropertyIsEqualTo'); var property = filter.getLeft(); - if (goog.isDef(property)) { - this.writeNode('PropertyName', property, null, node); - } + 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.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]); + 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); @@ -87,8 +87,14 @@ ol.parser.ogc.Filter_v1_0_0 = function() { '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]; + 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)) { @@ -119,12 +125,17 @@ 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]]; + 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.geom.Geometry) { - geom = args[0]; + } 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]; @@ -157,8 +168,9 @@ ol.parser.ogc.Filter_v1_0_0.prototype.writeSpatial_ = function(filter, name) { 'http://www.opengis.net/gml'); } if (goog.isDef(child)) { - if (goog.isDef(projection)) { - child.setAttribute('srsName', projection); + goog.asserts.assert(projection instanceof ol.expr.Literal); + if (goog.isDefAndNotNull(projection.getValue())) { + child.setAttribute('srsName', projection.getValue()); } node.appendChild(child); } diff --git a/src/ol/parser/ogc/filter_v1_1_0.js b/src/ol/parser/ogc/filter_v1_1_0.js index 6cfa18ed44..a54813efb7 100644 --- a/src/ol/parser/ogc/filter_v1_1_0.js +++ b/src/ol/parser/ogc/filter_v1_1_0.js @@ -1,11 +1,13 @@ 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'); @@ -59,10 +61,10 @@ ol.parser.ogc.Filter_v1_1_0 = function() { this.readChildNodes(node, container); var args = []; args.push(container['property'], container['value'], - node.getAttribute('wildCard'), - node.getAttribute('singleChar'), - node.getAttribute('escapeChar'), - node.getAttribute('matchCase')); + 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)); } @@ -103,11 +105,15 @@ ol.parser.ogc.Filter_v1_1_0 = function() { '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]); + 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])) { - node.setAttribute('matchCase', 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)) { @@ -119,8 +125,14 @@ ol.parser.ogc.Filter_v1_1_0 = function() { '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]; + 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); @@ -143,8 +155,10 @@ ol.parser.ogc.Filter_v1_1_0 = function() { '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'] == 'DESC') ? 'DESC' : 'ASC', null, node); + (sortProperty['order'].getValue() == 'DESC') ? 'DESC' : 'ASC', null, + node); return node; }, 'SortOrder': function(value) { @@ -169,12 +183,17 @@ 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]]; + 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.geom.Geometry) { - geom = args[0]; + } 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]; @@ -207,8 +226,9 @@ ol.parser.ogc.Filter_v1_1_0.prototype.writeSpatial_ = function(filter, name) { 'http://www.opengis.net/gml'); } if (goog.isDef(child)) { - if (goog.isDef(projection)) { - child.setAttribute('srsName', projection); + goog.asserts.assert(projection instanceof ol.expr.Literal); + if (goog.isDefAndNotNull(projection.getValue())) { + child.setAttribute('srsName', projection.getValue()); } node.appendChild(child); } 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 index 3c413c75ca..43aaa54201 100644 --- a/test/spec/ol/parser/ogc/filter_v1_0_0.test.js +++ b/test/spec/ol/parser/ogc/filter_v1_0_0.test.js @@ -11,12 +11,12 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { afterLoadXml(url, function(xml) { var filter = parser.read(xml); expect(filter instanceof ol.expr.Call).to.be(true); - expect(filter.getCallee().getName()).to.eql( + expect(filter.getCallee().getName()).to.equal( 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'); + 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(); @@ -28,11 +28,11 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { 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); + expect(filter.getCallee().getName()).to.equal(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'); + 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(); @@ -44,12 +44,12 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { afterLoadXml(url, function(xml) { var filter = parser.read(xml); expect(filter instanceof ol.expr.Call).to.be(true); - expect(filter.getCallee().getName()).to.eql( + expect(filter.getCallee().getName()).to.equal( 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'); + 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(); @@ -61,16 +61,17 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { 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.getOperator()).to.equal(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.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() instanceof ol.expr.Comparison).to.be.ok(); - expect(filter.getRight().getOperator()).to.eql( + expect(filter.getRight().getOperator()).to.equal( ol.expr.ComparisonOp.LTE); - expect(filter.getRight().getLeft()).to.eql('number'); - expect(filter.getRight().getRight()).to.eql(100); + 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(); @@ -82,16 +83,17 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { 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.getOperator()).to.equal(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.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() instanceof ol.expr.Comparison).to.be.ok(); - expect(filter.getRight().getOperator()).to.eql( + expect(filter.getRight().getOperator()).to.equal( ol.expr.ComparisonOp.LTE); - expect(filter.getRight().getLeft()).to.eql('number'); - expect(filter.getRight().getRight()).to.eql(100); + expect(filter.getRight().getLeft().getName()).to.equal('number'); + expect(filter.getRight().getRight().getValue()).to.equal(100); done(); }); }); @@ -101,8 +103,8 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { 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); + 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(); @@ -114,7 +116,10 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { 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']); + [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(); @@ -126,7 +131,9 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { afterLoadXml(url, function(xml) { var filter = new ol.expr.Call( new ol.expr.Identifier(ol.expr.functions.EXTENT), - [-180, -90, 180, 90, 'EPSG:4326']); + [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(); @@ -138,8 +145,9 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { 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']); + [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); @@ -160,9 +168,11 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { 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.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), - ['foo.1', 'foo.2'])); + [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(); @@ -176,9 +186,11 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { 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.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), - ['foo.1', 'foo.2'])); + [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(); @@ -192,7 +204,7 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { afterLoadXml(url, function(xml) { var filter = new ol.expr.Not( new ol.expr.Call(new ol.expr.Identifier(ol.expr.functions.FID), - ['foo.2'])); + [new ol.expr.Literal('foo.2')])); var output = parser.write(filter); expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); done(); @@ -211,8 +223,10 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { // 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)); + new ol.expr.Comparison(ol.expr.ComparisonOp.GTE, + new ol.expr.Identifier('when'), new ol.expr.Literal(start)), + new ol.expr.Comparison(ol.expr.ComparisonOp.LTE, + new ol.expr.Identifier('when'), new ol.expr.Literal(end))); var output = parser.write(filter); expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); done(); @@ -229,6 +243,7 @@ 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'); 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 index 695a848d65..9d7d06bd3d 100644 --- a/test/spec/ol/parser/ogc/filter_v1_1_0.test.js +++ b/test/spec/ol/parser/ogc/filter_v1_1_0.test.js @@ -11,30 +11,36 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { 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); + expect(filter.getOperator()).to.equal(ol.expr.LogicalOp.OR); var filters = []; parser.getSubfiltersForLogical_(filter, filters); - expect(filters.length).to.eql(5); + 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, 'number', 1064866676), + ol.expr.ComparisonOp.GTE, new ol.expr.Identifier('number'), + new ol.expr.Literal(1064866676)), new ol.expr.Comparison( - ol.expr.ComparisonOp.LTE, 'number', 1065512599))); + 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, 'FOO', 5000))); + 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.eql( + expect(filters[2].getCallee().getName()).to.equal( ol.expr.functions.LIKE); - expect(filters[2].getArgs()).to.eql(['cat', '*dog.food!*good', '*', - '.', '!', null]); + 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.eql( + expect(filters[3].getCallee().getName()).to.equal( ol.expr.functions.IEQ); - expect(filters[3].getArgs()).to.eql(['cat', 'dog']); + 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.eql(ol.expr.ComparisonOp.EQ); - expect(filters[4].getLeft()).to.eql('cat'); - expect(filters[4].getRight()).to.eql('dog'); + 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(); }); }); @@ -109,7 +115,7 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { c = cases[i]; filter = parser.read(c.str); var matchCase = (filter instanceof ol.expr.Call) ? false : true; - expect(matchCase).to.eql(c.exp); + expect(matchCase).to.equal(c.exp); } }); @@ -149,8 +155,10 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { 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']); + [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(); @@ -162,8 +170,9 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { 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'])])); + [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(); @@ -177,8 +186,11 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { 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']); + [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(); @@ -190,7 +202,9 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { afterLoadXml(url, function(xml) { var filter = new ol.expr.Call( new ol.expr.Identifier(ol.expr.functions.LIKE), - ['person', '*me*', '*', '.', '!', false]); + [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(); @@ -202,11 +216,11 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { afterLoadXml(url, function(xml) { var writer = parser.writers['http://www.opengis.net/ogc']['SortBy']; var output = writer.call(parser, [{ - 'property': 'Title', - 'order': 'ASC' + 'property': new ol.expr.Identifier('Title'), + 'order': new ol.expr.Literal('ASC') },{ - 'property': 'Relevance', - 'order': 'DESC' + 'property': new ol.expr.Identifier('Relevance'), + 'order': new ol.expr.Literal('DESC') }]); expect(output).to.xmleql(xml); done(); @@ -223,6 +237,7 @@ 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'); From c299bfa1cbcef793f563f1901cbce952bd7d7772 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Mon, 8 Jul 2013 17:29:32 +0200 Subject: [PATCH 03/14] more dot notation --- src/ol/parser/ogc/filter_v1.js | 94 +++++++++++++++--------------- src/ol/parser/ogc/filter_v1_0_0.js | 16 ++--- src/ol/parser/ogc/filter_v1_1_0.js | 20 +++---- 3 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/ol/parser/ogc/filter_v1.js b/src/ol/parser/ogc/filter_v1.js index 3085e1397d..4aa77beb3d 100644 --- a/src/ol/parser/ogc/filter_v1.js +++ b/src/ol/parser/ogc/filter_v1.js @@ -33,12 +33,12 @@ ol.parser.ogc.Filter_v1 = function() { switch (child.nodeType) { case 1: obj = this.readNode(child); - if (obj['property']) { - value += obj['property'].getName(); - } else if (goog.isDef(obj['value'])) { + if (obj.property) { + value += obj.property.getName(); + } else if (goog.isDef(obj.value)) { // TODO adding this to value and then parsing causes // ol.expr.UnexpectedToken on e.g. 10 - return obj['value']; + return obj.value; } break; case 3: // text node @@ -53,15 +53,15 @@ ol.parser.ogc.Filter_v1 = function() { }, 'Filter': function(node, obj) { var container = { - 'filters': [] + filters: [] }; this.readChildNodes(node, container); if (goog.isDef(container.fids)) { - obj['filter'] = new ol.expr.Call( + 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]; + } else if (container.filters.length > 0) { + obj.filter = container.filters[0]; } }, 'FeatureId': function(node, obj) { @@ -76,90 +76,90 @@ ol.parser.ogc.Filter_v1 = function() { } }, 'And': function(node, obj) { - var container = {'filters': []}; + var container = {filters: []}; this.readChildNodes(node, container); - var filter = this.aggregateLogical_(container['filters'], + var filter = this.aggregateLogical_(container.filters, ol.expr.LogicalOp.AND); - obj['filters'].push(filter); + obj.filters.push(filter); }, 'Or': function(node, obj) { - var container = {'filters': []}; + var container = {filters: []}; this.readChildNodes(node, container); - var filter = this.aggregateLogical_(container['filters'], + var filter = this.aggregateLogical_(container.filters, ol.expr.LogicalOp.OR); - obj['filters'].push(filter); + obj.filters.push(filter); }, 'Not': function(node, obj) { - var container = {'filters': []}; + var container = {filters: []}; this.readChildNodes(node, container); // Not is unary so can only contain 1 child filter - obj['filters'].push(new ol.expr.Not( + 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( + obj.filters.push(new ol.expr.Comparison( ol.expr.ComparisonOp.EQ, - container['property'], + container.property, new ol.expr.Literal(null))); }, 'PropertyIsLessThan': function(node, obj) { var container = {}; this.readChildNodes(node, container); - obj['filters'].push(new ol.expr.Comparison( + obj.filters.push(new ol.expr.Comparison( ol.expr.ComparisonOp.LT, - container['property'], - container['value'])); + container.property, + container.value)); }, 'PropertyIsGreaterThan': function(node, obj) { var container = {}; this.readChildNodes(node, container); - obj['filters'].push(new ol.expr.Comparison( + obj.filters.push(new ol.expr.Comparison( ol.expr.ComparisonOp.GT, - container['property'], - container['value'])); + container.property, + container.value)); }, 'PropertyIsLessThanOrEqualTo': function(node, obj) { var container = {}; this.readChildNodes(node, container); - obj['filters'].push(new ol.expr.Comparison( + obj.filters.push(new ol.expr.Comparison( ol.expr.ComparisonOp.LTE, - container['property'], - container['value'])); + container.property, + container.value)); }, 'PropertyIsGreaterThanOrEqualTo': function(node, obj) { var container = {}; this.readChildNodes(node, container); - obj['filters'].push(new ol.expr.Comparison( + obj.filters.push(new ol.expr.Comparison( ol.expr.ComparisonOp.GTE, - container['property'], - container['value'])); + 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, + obj.filters.push(new ol.expr.Logical(ol.expr.LogicalOp.AND, new ol.expr.Comparison(ol.expr.ComparisonOp.GTE, - container['property'], container['lowerBoundary']), + container.property, container.lowerBoundary), new ol.expr.Comparison(ol.expr.ComparisonOp.LTE, - container['property'], container['upperBoundary']))); + 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); + obj.value = new ol.expr.Literal(isNaN(value) ? nodeValue : value); }, 'PropertyName': function(node, obj) { - obj['property'] = new ol.expr.Identifier(this.getChildValue(node)); + 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); + obj.lowerBoundary = readers._expression.call(this, node); }, 'UpperBoundary': function(node, obj) { var readers = this.readers[this.defaultNamespaceURI]; - obj['upperBoundary'] = readers._expression.call(this, node); + obj.upperBoundary = readers._expression.call(this, node); }, _spatial: function(node, obj, identifier) { var args = [], container = {}; @@ -172,17 +172,17 @@ ol.parser.ogc.Filter_v1 = function() { 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.distance)) { + args.push(container.distance); } - if (goog.isDef(container['distanceUnits'])) { - args.push(container['distanceUnits']); + 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']); + if (goog.isDef(container.property)) { + args.push(container.property); } - obj['filters'].push(new ol.expr.Call(new ol.expr.Identifier( + obj.filters.push(new ol.expr.Call(new ol.expr.Identifier( identifier), args)); }, 'BBOX': function(node, obj) { @@ -211,8 +211,8 @@ ol.parser.ogc.Filter_v1 = function() { ol.expr.functions.DWITHIN); }, 'Distance': function(node, obj) { - obj['distance'] = new ol.expr.Literal(this.getChildValue(node)); - obj['distanceUnits'] = new ol.expr.Literal(node.getAttribute('units')); + obj.distance = new ol.expr.Literal(this.getChildValue(node)); + obj.distanceUnits = new ol.expr.Literal(node.getAttribute('units')); } } }; @@ -464,7 +464,7 @@ ol.parser.ogc.Filter_v1.prototype.read = function(data) { } var obj = {}; this.readNode(data, obj); - return obj['filter']; + return obj.filter; }; diff --git a/src/ol/parser/ogc/filter_v1_0_0.js b/src/ol/parser/ogc/filter_v1_0_0.js index bcf2874935..ddaa2cd18a 100644 --- a/src/ol/parser/ogc/filter_v1_0_0.js +++ b/src/ol/parser/ogc/filter_v1_0_0.js @@ -28,28 +28,28 @@ ol.parser.ogc.Filter_v1_0_0 = function() { 'PropertyIsEqualTo': function(node, obj) { var container = {}; this.readChildNodes(node, container); - obj['filters'].push(new ol.expr.Comparison( + obj.filters.push(new ol.expr.Comparison( ol.expr.ComparisonOp.EQ, - container['property'], - container['value'])); + container.property, + container.value)); }, 'PropertyIsNotEqualTo': function(node, obj) { var container = {}; this.readChildNodes(node, container); - obj['filters'].push(new ol.expr.Comparison( + obj.filters.push(new ol.expr.Comparison( ol.expr.ComparisonOp.NEQ, - container['property'], - container['value'])); + container.property, + container.value)); }, 'PropertyIsLike': function(node, obj) { var container = {}; this.readChildNodes(node, container); var args = []; - args.push(container['property'], container['value'], + 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( + obj.filters.push(new ol.expr.Call( new ol.expr.Identifier(ol.expr.functions.LIKE), args)); } }); diff --git a/src/ol/parser/ogc/filter_v1_1_0.js b/src/ol/parser/ogc/filter_v1_1_0.js index a54813efb7..a1c7e47f43 100644 --- a/src/ol/parser/ogc/filter_v1_1_0.js +++ b/src/ol/parser/ogc/filter_v1_1_0.js @@ -31,14 +31,14 @@ ol.parser.ogc.Filter_v1_1_0 = function() { 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']]); + [container.property, container.value]); } else { filter = new ol.expr.Comparison( ol.expr.ComparisonOp.EQ, - container['property'], - container['value']); + container.property, + container.value); } - obj['filters'].push(filter); + obj.filters.push(filter); }, 'PropertyIsNotEqualTo': function(node, obj) { var matchCase = node.getAttribute('matchCase'); @@ -47,25 +47,25 @@ ol.parser.ogc.Filter_v1_1_0 = function() { if (matchCase === 'false' || matchCase === '0') { filter = new ol.expr.Call(new ol.expr.Identifier( ol.expr.functions.INEQ), - [container['property'], container['value']]); + [container.property, container.value]); } else { filter = new ol.expr.Comparison( ol.expr.ComparisonOp.NEQ, - container['property'], - container['value']); + container.property, + container.value); } - obj['filters'].push(filter); + obj.filters.push(filter); }, 'PropertyIsLike': function(node, obj) { var container = {}; this.readChildNodes(node, container); var args = []; - args.push(container['property'], container['value'], + 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( + obj.filters.push(new ol.expr.Call( new ol.expr.Identifier(ol.expr.functions.LIKE), args)); } }); From 31fd41ab1488c5e87018d1a9f4f4554dff0232bd Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Tue, 9 Jul 2013 13:34:23 +0200 Subject: [PATCH 04/14] make filterMap_ static as proposed by @tschaub --- src/ol/parser/ogc/filter_v1.js | 51 +++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/ol/parser/ogc/filter_v1.js b/src/ol/parser/ogc/filter_v1.js index 4aa77beb3d..45b22ac0ae 100644 --- a/src/ol/parser/ogc/filter_v1.js +++ b/src/ol/parser/ogc/filter_v1.js @@ -379,33 +379,38 @@ ol.parser.ogc.Filter_v1 = function() { } } }; - this.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' - }; 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. @@ -443,7 +448,7 @@ ol.parser.ogc.Filter_v1.prototype.getFilterType_ = function(filter) { } else if (filter instanceof ol.expr.Not) { type = '!'; } - var filterType = this.filterMap_[type]; + var filterType = ol.parser.ogc.Filter_v1.filterMap_[type]; if (!filterType) { throw new Error('Filter writing not supported for rule type: ' + type); } From 875edc540e349e49feee326cf544f62af63c06db Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Mon, 22 Jul 2013 13:23:08 +0200 Subject: [PATCH 05/14] implement @tschaub's suggestions for the LIKE function --- src/ol/expr/expression.js | 22 ++++++++++---------- test/spec/ol/expr/expression.test.js | 30 ++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/ol/expr/expression.js b/src/ol/expr/expression.js index bc732e825f..d90eca6b0d 100644 --- a/src/ol/expr/expression.js +++ b/src/ol/expr/expression.js @@ -154,16 +154,17 @@ 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. + * 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(attribute, value, wildCard, +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 ' + @@ -173,19 +174,18 @@ ol.expr.lib[ol.expr.functions.LIKE] = function(attribute, value, wildCard, wildCard = goog.isDef(wildCard) ? wildCard : '*'; singleChar = goog.isDef(singleChar) ? singleChar : '.'; escapeChar = goog.isDef(escapeChar) ? escapeChar : '!'; - var val; - val = value.replace( + pattern = pattern.replace( new RegExp('\\' + escapeChar + '(.|$)', 'g'), '\\$1'); - val = value.replace( + pattern = pattern.replace( new RegExp('\\' + singleChar, 'g'), '.'); - val = value.replace( + pattern = pattern.replace( new RegExp('\\' + wildCard, 'g'), '.*'); - val = value.replace( + pattern = pattern.replace( new RegExp('\\\\.\\*', 'g'), '\\' + wildCard); - val = value.replace( + pattern = pattern.replace( new RegExp('\\\\\\.', 'g'), '\\' + singleChar); var modifiers = (matchCase === false) ? 'gi' : 'g'; - return new RegExp(val, modifiers).test(this.get(attribute)); + return new RegExp(pattern, modifiers).test(value); }; diff --git a/test/spec/ol/expr/expression.test.js b/test/spec/ol/expr/expression.test.js index 30b52945d5..009f467a2e 100644 --- a/test/spec/ol/expr/expression.test.js +++ b/test/spec/ol/expr/expression.test.js @@ -758,6 +758,36 @@ 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('ol.expr.register()', function() { From 369d692a9067f57af281ce860797af01ba32fcb7 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Mon, 22 Jul 2013 14:11:29 +0200 Subject: [PATCH 06/14] implement @tschaub's suggestions for ieq and ineq --- src/ol/expr/expression.js | 26 +++++++++---------- test/spec/ol/expr/expression.test.js | 38 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/ol/expr/expression.js b/src/ol/expr/expression.js index d90eca6b0d..18508f29cf 100644 --- a/src/ol/expr/expression.js +++ b/src/ol/expr/expression.js @@ -191,32 +191,30 @@ ol.expr.lib[ol.expr.functions.LIKE] = function(value, pattern, wildCard, /** * Case insensitive comparison for equality. - * @param {string} attribute Name of the attribute. - * @param {string} value Value to test for equality. + * @param {*} first First value. + * @param {*} second Second value. * @this {ol.Feature} */ -ol.expr.lib[ol.expr.functions.IEQ] = function(attribute, value) { - var attributeValue = this.get(attribute); - if (goog.isString(value) && goog.isString(attributeValue)) { - return value.toUpperCase() == attributeValue.toUpperCase(); +ol.expr.lib[ol.expr.functions.IEQ] = function(first, second) { + if (goog.isString(first) && goog.isString(second)) { + return first.toUpperCase() == second.toUpperCase(); } else { - return value == attributeValue; + return first == second; } }; /** * Case insensitive comparison for non-equality. - * @param {string} attribute Name of the attribute. - * @param {string} value Value to test for non-equality. + * @param {*} first First value. + * @param {*} second Second value. * @this {ol.Feature} */ -ol.expr.lib[ol.expr.functions.INEQ] = function(attribute, value) { - var attributeValue = this.get(attribute); - if (goog.isString(value) && goog.isString(attributeValue)) { - return value.toUpperCase() == attributeValue.toUpperCase(); +ol.expr.lib[ol.expr.functions.INEQ] = function(first, second) { + if (goog.isString(first) && goog.isString(second)) { + return first.toUpperCase() != second.toUpperCase(); } else { - return value != attributeValue; + return first != second; } }; diff --git a/test/spec/ol/expr/expression.test.js b/test/spec/ol/expr/expression.test.js index 009f467a2e..3e6724283f 100644 --- a/test/spec/ol/expr/expression.test.js +++ b/test/spec/ol/expr/expression.test.js @@ -788,6 +788,44 @@ describe('ol.expr.lib', function() { }); + 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() { From deb88a5a6d2d768031974d9fe0efd4e685273a21 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Fri, 9 Aug 2013 10:42:16 +0200 Subject: [PATCH 07/14] change _expression reader --- src/ol/parser/ogc/filter_v1.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ol/parser/ogc/filter_v1.js b/src/ol/parser/ogc/filter_v1.js index 45b22ac0ae..c4127a8987 100644 --- a/src/ol/parser/ogc/filter_v1.js +++ b/src/ol/parser/ogc/filter_v1.js @@ -36,9 +36,9 @@ ol.parser.ogc.Filter_v1 = function() { if (obj.property) { value += obj.property.getName(); } else if (goog.isDef(obj.value)) { - // TODO adding this to value and then parsing causes - // ol.expr.UnexpectedToken on e.g. 10 - return obj.value; + if (obj.value instanceof ol.expr.Literal) { + value += obj.value.getValue(); + } } break; case 3: // text node From 29954d2ff99f12550f240a270be5a354fe297a39 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Fri, 9 Aug 2013 11:08:19 +0200 Subject: [PATCH 08/14] trim the string before passing it off to ol.expr.parse --- src/ol/expr/.parser.js.swp | Bin 0 -> 16384 bytes src/ol/parser/ogc/filter_v1.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 src/ol/expr/.parser.js.swp diff --git a/src/ol/expr/.parser.js.swp b/src/ol/expr/.parser.js.swp new file mode 100644 index 0000000000000000000000000000000000000000..aa92573b499004a5b37f21e954469934d17cefc7 GIT binary patch literal 16384 zcmeI3TWlOx8OJ9{leA55v^-Q4q?5GNYu7vLwVhBBJF>mrq;A%i+Utg(O3v);@%m(E zXErlu?JSOqN)bhB3#fhI0dYxFfr7Xwl~P0>KmtJ;(I=`>ctYv}B@~LdJd}zQ{^y*T zo%MPzPAY^d%}77*&Ya79=bP_*=X~FebA1m_Op;IN0~(IoH0{i`S04KP#hI-i*}p~0 z87^PWQ&H0P5cT5Ah8@pSJ5JdN8=qdhWSBX}DaOmLqg#$?SlXk0hY6=l?E-ZY1;!JO zHLws|_goX_33{sRCd!8EQCC0VwY_yz7-=BVz@{~Dvo_G5>=V`R-m{zBar^wHTSgTl z4MZAh=R5NRONK%{|41Ca(I4MZAd(rQpNC4pX{~-SV_pO@tJ&*$nU^jU47EL<`TyP)w$IY7dBd`qa2ZLY$+yQO} z|GWuxz-!<fj4$(+E2k5@E9<_IQTf&3VwH^ru`PY4t@iE4W0riFaikJ z0$#mA(=LE70S=CV6xa?fU$1E|gR|iCzyyat7uW*c+o@@9gFk^+z$Nf9xCnj@o&jG5 zi{PW+25@DEru_@N1fB;D_!P*3Ij|qx1-65Cwqp$7XW#;O7L>tZ@G-Cxyn7w$fEU5D z0BITR(_j+xfm^^k+cfPha0#3PPl08?z$4&JunX)2JHX%YOy3570e=R61ed@s!M8vW zi03{4uI3;;WCX8g7$vgmSh{#yLr>!m^*rX-Ys6)RB~E7LUs0&8>sp6q7G2~dBmT5# z@>Ty|Ve^TC}0k$MSVGI*Cq7MV>o z(L}9_pInAi>vy~{8TDC zKboDM6&(_?Y`Asv6|<%9fEG-W8TFzVUNhs4=u%g+f2KCQ7f^pu%wl*aC9CYTC!su& z%a-9a#CLIob5c1he+;X3rIe%Y8p$rvx;kVLZiwSjfh|*;C`AzR0DK>HNr7^YlpI%f z-smyqVAoU=GU_+=9oabL)Gfh<$i737n%+*UxwiEhsULOyfKA7SC#{(9p#JURWK20s z-$rVV)g!TFQcotkg?8d3eX?R$j8_}VKPig|Dh&0KgS}*ExR)4qo*cxJwXLdZJ4-D? zJOIOLXnnum`Di}RIJDSMyw5M5gcD_Div^30G|Bbcyrw{zPJBWksiE$%r!>g4q7k*B!TzkeB=S^(Xe~$;90rHRG@` zIo~E=n+BF-D15Qz7t{L15 zE6k;_u3&1++YptSXesAkSNDMy6>GkzLzULWFu~S^lT^5qHsx~VZ(rWJwC3wOR%uf~ znNOPv^i;bMga*~Ri_o50*QsAfH&d%k9n4En+VI4sp%@-sHs)SfjOAn*voEw9WrVT< zQA}#rqzNAh^3MGSCy6Kb-iYc?9bw65{ zjXW8HBXB&?7-xD;o{b10E!wGrV->Gbq-3u0nM#q7p$eRiVN;z`qw~#=U=K!)I4kfN zLq&Yoi{kr;$xaz=JE0$R9FND3vJwQRMe1?!0yr5uAuq46(nv16tlL(rv5T!PGdwa@ zwej*e87issk&|qN={ee}+51uW02Xs2pQn^$s~9wP?&3t}RjZS>2Cm{ki)Wqo%EE)z zTq9NI!WVWEW}8+e505AI5sQvxIV%Wrh*`5PEFKIVQM!Gx{jkJNPOh-FflWd|_`ee6 zOHSS+*ml500%m(swo1ulZmffBI547dwiMo!>|;1qZe90F-@E4T^l z0ylyk;4*Rp-v{3XkAtJ&2sjM3ftUQI+tszG513SA5qoY76GwuWFz7k#W36tB+%(~p z5kjpI**!M;I0=$hQapI|y1lgW(Cf2S6bUsEnyYk`ID^=s8btm~gbpHd2*nDOfrf-y z*hY(}n#g+v?M<0IlMzyV%P_SiZU%iewv%ey&`c>%)t29NugJN!2?m7cGWnonGc354 zd{u66O~*xIjuW9$IcOrkN@X@)TlJn@O4VpzG2f?(TS;@-;GzPp%W3O2u8)4|r|ym)NXL{69g_^jI{rE& zHNMe8=Hzcs>oVT32r=QLF<*^CA~=*gkhal05#G$bY@%7i#3uLNE5+MH%OmMyN2h1U zRg2J~+K3ohyK1!2(vWlGVljjaYITGchYyH#>B951x4$XJ78#%lGIlCwwl15mb{U)8 zriC;8eQeXNabfHa?ay}XIFdkeNWN3=ywMAOooqgZg()>#c9h2I=57p{N8Z|BL#ojJ Fe*po0-(CO! literal 0 HcmV?d00001 diff --git a/src/ol/parser/ogc/filter_v1.js b/src/ol/parser/ogc/filter_v1.js index c4127a8987..f898b9f6b0 100644 --- a/src/ol/parser/ogc/filter_v1.js +++ b/src/ol/parser/ogc/filter_v1.js @@ -49,7 +49,7 @@ ol.parser.ogc.Filter_v1 = function() { break; } } - return ol.expr.parse(value); + return ol.expr.parse(goog.string.trim(value)); }, 'Filter': function(node, obj) { var container = { From 8792973c08a40c7a83b4534aa48ab175a36fe5a2 Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Fri, 9 Aug 2013 15:57:29 +0200 Subject: [PATCH 09/14] make sure the _expression reader can deal with combined propertyname and literals --- src/ol/parser/ogc/filter_v1.js | 20 ++++++++++++------- test/spec/ol/parser/ogc/filter_v1_0_0.test.js | 18 +++++++++++++++++ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/ol/parser/ogc/filter_v1.js b/src/ol/parser/ogc/filter_v1.js index f898b9f6b0..b390e61db6 100644 --- a/src/ol/parser/ogc/filter_v1.js +++ b/src/ol/parser/ogc/filter_v1.js @@ -28,28 +28,34 @@ ol.parser.ogc.Filter_v1 = function() { this.readers = { 'http://www.opengis.net/ogc': { _expression: function(node) { - var obj, value = ''; + var obj, source = ''; for (var child = node.firstChild; child; child = child.nextSibling) { switch (child.nodeType) { case 1: obj = this.readNode(child); if (obj.property) { - value += obj.property.getName(); + var name = obj.property.getName(); + source += (source !== '') ? '+' + name : name; } else if (goog.isDef(obj.value)) { - if (obj.value instanceof ol.expr.Literal) { - value += obj.value.getValue(); - } + return obj.value; } break; case 3: // text node case 4: // cdata section - value += child.nodeValue; + if (source !== '') { + source += '+'; + } + if (isNaN(goog.string.toNumber(child.nodeValue))) { + source += goog.string.quote(goog.string.trim(child.nodeValue)); + } else { + source += goog.string.trim(child.nodeValue); + } break; default: break; } } - return ol.expr.parse(goog.string.trim(value)); + return ol.expr.parse(source); }, 'Filter': function(node, obj) { var container = { 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 index 43aaa54201..87ec4afffa 100644 --- a/test/spec/ol/parser/ogc/filter_v1_0_0.test.js +++ b/test/spec/ol/parser/ogc/filter_v1_0_0.test.js @@ -235,6 +235,24 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); + describe('_expression reader works as expected', function() { + it('_expression reader 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 instanceof ol.expr.Literal).to.be.ok(); + 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'); From 09c27f430d4ababb47be3f44afb7533863ca208a Mon Sep 17 00:00:00 2001 From: Bart van den Eijnden Date: Fri, 9 Aug 2013 15:58:31 +0200 Subject: [PATCH 10/14] remove accidentally committed swap file --- src/ol/expr/.parser.js.swp | Bin 16384 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/ol/expr/.parser.js.swp diff --git a/src/ol/expr/.parser.js.swp b/src/ol/expr/.parser.js.swp deleted file mode 100644 index aa92573b499004a5b37f21e954469934d17cefc7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeI3TWlOx8OJ9{leA55v^-Q4q?5GNYu7vLwVhBBJF>mrq;A%i+Utg(O3v);@%m(E zXErlu?JSOqN)bhB3#fhI0dYxFfr7Xwl~P0>KmtJ;(I=`>ctYv}B@~LdJd}zQ{^y*T zo%MPzPAY^d%}77*&Ya79=bP_*=X~FebA1m_Op;IN0~(IoH0{i`S04KP#hI-i*}p~0 z87^PWQ&H0P5cT5Ah8@pSJ5JdN8=qdhWSBX}DaOmLqg#$?SlXk0hY6=l?E-ZY1;!JO zHLws|_goX_33{sRCd!8EQCC0VwY_yz7-=BVz@{~Dvo_G5>=V`R-m{zBar^wHTSgTl z4MZAh=R5NRONK%{|41Ca(I4MZAd(rQpNC4pX{~-SV_pO@tJ&*$nU^jU47EL<`TyP)w$IY7dBd`qa2ZLY$+yQO} z|GWuxz-!<fj4$(+E2k5@E9<_IQTf&3VwH^ru`PY4t@iE4W0riFaikJ z0$#mA(=LE70S=CV6xa?fU$1E|gR|iCzyyat7uW*c+o@@9gFk^+z$Nf9xCnj@o&jG5 zi{PW+25@DEru_@N1fB;D_!P*3Ij|qx1-65Cwqp$7XW#;O7L>tZ@G-Cxyn7w$fEU5D z0BITR(_j+xfm^^k+cfPha0#3PPl08?z$4&JunX)2JHX%YOy3570e=R61ed@s!M8vW zi03{4uI3;;WCX8g7$vgmSh{#yLr>!m^*rX-Ys6)RB~E7LUs0&8>sp6q7G2~dBmT5# z@>Ty|Ve^TC}0k$MSVGI*Cq7MV>o z(L}9_pInAi>vy~{8TDC zKboDM6&(_?Y`Asv6|<%9fEG-W8TFzVUNhs4=u%g+f2KCQ7f^pu%wl*aC9CYTC!su& z%a-9a#CLIob5c1he+;X3rIe%Y8p$rvx;kVLZiwSjfh|*;C`AzR0DK>HNr7^YlpI%f z-smyqVAoU=GU_+=9oabL)Gfh<$i737n%+*UxwiEhsULOyfKA7SC#{(9p#JURWK20s z-$rVV)g!TFQcotkg?8d3eX?R$j8_}VKPig|Dh&0KgS}*ExR)4qo*cxJwXLdZJ4-D? zJOIOLXnnum`Di}RIJDSMyw5M5gcD_Div^30G|Bbcyrw{zPJBWksiE$%r!>g4q7k*B!TzkeB=S^(Xe~$;90rHRG@` zIo~E=n+BF-D15Qz7t{L15 zE6k;_u3&1++YptSXesAkSNDMy6>GkzLzULWFu~S^lT^5qHsx~VZ(rWJwC3wOR%uf~ znNOPv^i;bMga*~Ri_o50*QsAfH&d%k9n4En+VI4sp%@-sHs)SfjOAn*voEw9WrVT< zQA}#rqzNAh^3MGSCy6Kb-iYc?9bw65{ zjXW8HBXB&?7-xD;o{b10E!wGrV->Gbq-3u0nM#q7p$eRiVN;z`qw~#=U=K!)I4kfN zLq&Yoi{kr;$xaz=JE0$R9FND3vJwQRMe1?!0yr5uAuq46(nv16tlL(rv5T!PGdwa@ zwej*e87issk&|qN={ee}+51uW02Xs2pQn^$s~9wP?&3t}RjZS>2Cm{ki)Wqo%EE)z zTq9NI!WVWEW}8+e505AI5sQvxIV%Wrh*`5PEFKIVQM!Gx{jkJNPOh-FflWd|_`ee6 zOHSS+*ml500%m(swo1ulZmffBI547dwiMo!>|;1qZe90F-@E4T^l z0ylyk;4*Rp-v{3XkAtJ&2sjM3ftUQI+tszG513SA5qoY76GwuWFz7k#W36tB+%(~p z5kjpI**!M;I0=$hQapI|y1lgW(Cf2S6bUsEnyYk`ID^=s8btm~gbpHd2*nDOfrf-y z*hY(}n#g+v?M<0IlMzyV%P_SiZU%iewv%ey&`c>%)t29NugJN!2?m7cGWnonGc354 zd{u66O~*xIjuW9$IcOrkN@X@)TlJn@O4VpzG2f?(TS;@-;GzPp%W3O2u8)4|r|ym)NXL{69g_^jI{rE& zHNMe8=Hzcs>oVT32r=QLF<*^CA~=*gkhal05#G$bY@%7i#3uLNE5+MH%OmMyN2h1U zRg2J~+K3ohyK1!2(vWlGVljjaYITGchYyH#>B951x4$XJ78#%lGIlCwwl15mb{U)8 zriC;8eQeXNabfHa?ay}XIFdkeNWN3=ywMAOooqgZg()>#c9h2I=57p{N8Z|BL#ojJ Fe*po0-(CO! From a3ec0d776ccc3f1f038e6b300fcac0e6f53b249a Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Fri, 9 Aug 2013 17:15:42 -0600 Subject: [PATCH 11/14] Building an expression with constructors instead of ol.expr.parse --- src/ol/parser/ogc/filter_v1.js | 39 ++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/ol/parser/ogc/filter_v1.js b/src/ol/parser/ogc/filter_v1.js index b390e61db6..ef7ca8da0b 100644 --- a/src/ol/parser/ogc/filter_v1.js +++ b/src/ol/parser/ogc/filter_v1.js @@ -12,6 +12,8 @@ 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'); @@ -28,34 +30,49 @@ ol.parser.ogc.Filter_v1 = function() { this.readers = { 'http://www.opengis.net/ogc': { _expression: function(node) { - var obj, source = ''; + 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) { - var name = obj.property.getName(); - source += (source !== '') ? '+' + name : name; + expressions.push(obj.property); } else if (goog.isDef(obj.value)) { return obj.value; } break; case 3: // text node case 4: // cdata section - if (source !== '') { - source += '+'; - } - if (isNaN(goog.string.toNumber(child.nodeValue))) { - source += goog.string.quote(goog.string.trim(child.nodeValue)); - } else { - source += goog.string.trim(child.nodeValue); + 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; } } - return ol.expr.parse(source); + // 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 = { From 824c9508247a50f0590b1c54683adee6a3918ed0 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 14 Aug 2013 09:33:47 -0400 Subject: [PATCH 12/14] Parse distance as a number --- src/ol/parser/ogc/filter_v1.js | 3 ++- test/spec/ol/parser/ogc/filter_v1_0_0.test.js | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/ol/parser/ogc/filter_v1.js b/src/ol/parser/ogc/filter_v1.js index ef7ca8da0b..72ba5453fd 100644 --- a/src/ol/parser/ogc/filter_v1.js +++ b/src/ol/parser/ogc/filter_v1.js @@ -234,7 +234,8 @@ ol.parser.ogc.Filter_v1 = function() { ol.expr.functions.DWITHIN); }, 'Distance': function(node, obj) { - obj.distance = new ol.expr.Literal(this.getChildValue(node)); + var value = goog.string.toNumber(this.getChildValue(node)); + obj.distance = new ol.expr.Literal(value); obj.distanceUnits = new ol.expr.Literal(node.getAttribute('units')); } } 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 index 87ec4afffa..e3cb981bc6 100644 --- a/test/spec/ol/parser/ogc/filter_v1_0_0.test.js +++ b/test/spec/ol/parser/ogc/filter_v1_0_0.test.js @@ -140,6 +140,27 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); }); + 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('DWithin written correctly', function(done) { var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/dwithin.xml'; afterLoadXml(url, function(xml) { From 2d95488906057cad48da88e85d086364bacd3792 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 14 Aug 2013 11:26:01 -0400 Subject: [PATCH 13/14] Remove special write-only handling for dates --- src/ol/parser/ogc/filter_v1.js | 6 +---- test/spec/ol/parser/ogc/filter_v1_0_0.test.js | 22 ------------------- .../ogc/xml/filter_v1_0_0/betweendates.xml | 11 ---------- .../xml/filter_v1_0_0/custombetweendates.xml | 11 ---------- 4 files changed, 1 insertion(+), 49 deletions(-) delete mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/betweendates.xml delete mode 100644 test/spec/ol/parser/ogc/xml/filter_v1_0_0/custombetweendates.xml diff --git a/src/ol/parser/ogc/filter_v1.js b/src/ol/parser/ogc/filter_v1.js index 72ba5453fd..1deca301fa 100644 --- a/src/ol/parser/ogc/filter_v1.js +++ b/src/ol/parser/ogc/filter_v1.js @@ -346,12 +346,8 @@ ol.parser.ogc.Filter_v1 = function() { }, 'Literal': function(expr) { goog.asserts.assert(expr instanceof ol.expr.Literal); - var value = expr.getValue(); - if (value instanceof Date) { - value = value.toISOString(); - } var node = this.createElementNS('ogc:Literal'); - node.appendChild(this.createTextNode(value)); + node.appendChild(this.createTextNode(expr.getValue())); return node; }, 'LowerBoundary': function(expr) { 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 index e3cb981bc6..3fb30a9486 100644 --- a/test/spec/ol/parser/ogc/filter_v1_0_0.test.js +++ b/test/spec/ol/parser/ogc/filter_v1_0_0.test.js @@ -234,28 +234,6 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); - 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, - new ol.expr.Identifier('when'), new ol.expr.Literal(start)), - new ol.expr.Comparison(ol.expr.ComparisonOp.LTE, - new ol.expr.Identifier('when'), new ol.expr.Literal(end))); - var output = parser.write(filter); - expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); - done(); - }); - }); - - }); - describe('_expression reader works as expected', function() { it('_expression reader handles combined propertyname and literal', function() { 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 deleted file mode 100644 index 3ad5b0131e..0000000000 --- a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/betweendates.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - 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/custombetweendates.xml b/test/spec/ol/parser/ogc/xml/filter_v1_0_0/custombetweendates.xml deleted file mode 100644 index f12024a9dd..0000000000 --- a/test/spec/ol/parser/ogc/xml/filter_v1_0_0/custombetweendates.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - when - - 2010-11-27 - - - 2011-12-27 - - - From 6c8ec8ed953c79d1baa47dc0d97253edc353e203 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 14 Aug 2013 11:35:44 -0400 Subject: [PATCH 14/14] Test names and instanceof checks --- test/spec/ol/parser/ogc/filter_v1_0_0.test.js | 48 +++++++++---------- test/spec/ol/parser/ogc/filter_v1_1_0.test.js | 22 ++++----- 2 files changed, 35 insertions(+), 35 deletions(-) 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 index 3fb30a9486..be7de99cee 100644 --- a/test/spec/ol/parser/ogc/filter_v1_0_0.test.js +++ b/test/spec/ol/parser/ogc/filter_v1_0_0.test.js @@ -4,9 +4,9 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { var parser = new ol.parser.ogc.Filter_v1_0_0(); - describe('#readwrite', function() { + describe('reading and writing', function() { - it('intersects filter read / written correctly', function(done) { + 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); @@ -23,7 +23,7 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); }); - it('within filter read / written correctly', function(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); @@ -39,7 +39,7 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); }); - it('contains filter read / written correctly', function(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); @@ -56,18 +56,18 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); }); - it('between filter read / written correctly', function(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 instanceof ol.expr.Logical).to.be.ok(); + expect(filter).to.be.a(ol.expr.Logical); expect(filter.getOperator()).to.equal(ol.expr.LogicalOp.AND); - expect(filter.getLeft() instanceof ol.expr.Comparison).to.be.ok(); + 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() instanceof ol.expr.Comparison).to.be.ok(); + 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'); @@ -78,18 +78,18 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); }); - it('between filter read correctly without literals', function(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 instanceof ol.expr.Logical).to.be.ok(); + expect(filter).to.be.a(ol.expr.Logical); expect(filter.getOperator()).to.equal(ol.expr.LogicalOp.AND); - expect(filter.getLeft() instanceof ol.expr.Comparison).to.be.ok(); + 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() instanceof ol.expr.Comparison).to.be.ok(); + 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'); @@ -98,11 +98,11 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); }); - it('null filter read / written correctly', function(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 instanceof ol.expr.Comparison).to.be.ok(); + 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); @@ -111,7 +111,7 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); }); - it('BBOX written correctly', function(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( @@ -126,7 +126,7 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); }); - it('BBOX without geometry name written correctly', function(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( @@ -161,7 +161,7 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); }); - it('DWithin written correctly', function(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( @@ -182,9 +182,9 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { // 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() { + describe('logical fid', function() { - it('logical filter [OR] with fid filter written correctly', function(done) { + 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, @@ -200,7 +200,7 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); }); - it('logical filter [AND] with fid filter written correctly', + it('writes logical [AND] with fid', function(done) { var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/' + 'logicalfeatureidand.xml'; @@ -218,7 +218,7 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); }); - it('logical filter [NOT] with fid filter written correctly', + it('writes logical [NOT] with fid', function(done) { var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/' + 'logicalfeatureidnot.xml'; @@ -234,8 +234,8 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { }); - describe('_expression reader works as expected', function() { - it('_expression reader handles combined propertyname and literal', + describe('_expression reader', function() { + it('handles combined propertyname and literal', function() { var xml = '10'; @@ -243,7 +243,7 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() { '_expression']; var expr = reader.call(parser, goog.dom.xml.loadXml( xml).documentElement); - expect(expr instanceof ol.expr.Literal).to.be.ok(); + expect(expr).to.be.a(ol.expr.Literal); expect(expr.getValue()).to.equal(10); xml = '' + 'fooxbar'; 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 index 9d7d06bd3d..b39fc59a0f 100644 --- a/test/spec/ol/parser/ogc/filter_v1_1_0.test.js +++ b/test/spec/ol/parser/ogc/filter_v1_1_0.test.js @@ -4,9 +4,9 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { var parser = new ol.parser.ogc.Filter_v1_1_0(); - describe('#readwrite', function() { + describe('reading and writing', function() { - it('filter read correctly', function(done) { + 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); @@ -45,7 +45,7 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { }); }); - it('matchCase read correctly', function() { + it('reads matchCase', function() { var cases = [{ str: '' + @@ -119,7 +119,7 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { } }); - it('BBOX filter written correctly', function(done) { + 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); @@ -129,7 +129,7 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { }); }); - it('BBOX filter without property name written correctly', function(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); @@ -139,7 +139,7 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { }); }); - it('Intersects filter read / written correctly', function(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); @@ -149,7 +149,7 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { }); }); - it('Filter functions written correctly', function(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( @@ -165,7 +165,7 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { }); }); - it('Custom filter functions written correctly', function(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, @@ -179,7 +179,7 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { }); }); - it('Nested filter functions written correctly', function(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( @@ -197,7 +197,7 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { }); }); - it('matchCase written correctly on Like filter', function(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( @@ -211,7 +211,7 @@ describe('ol.parser.ogc.Filter_v1_1_0', function() { }); }); - it('sortBy written correctly on Like filter', function(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'];