Merge pull request #3 from tschaub/bartvde-ogcfilter2

Suggestions for filter encoding
This commit is contained in:
Bart van den Eijnden
2013-08-15 02:12:03 -07:00
5 changed files with 87 additions and 96 deletions

View File

@@ -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 = {
@@ -217,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'));
}
}
@@ -328,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) {

View File

@@ -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(
@@ -140,7 +140,28 @@ describe('ol.parser.ogc.Filter_v1_0_0', function() {
});
});
it('DWithin written correctly', function(done) {
it('reads DWithin', function(done) {
var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/dwithin.xml';
afterLoadXml(url, function(xml) {
var filter = parser.read(xml);
expect(filter).to.be.a(ol.expr.Call);
var callee = filter.getCallee();
expect(callee).to.be.a(ol.expr.Identifier);
var name = callee.getName();
expect(name).to.equal(ol.expr.functions.DWITHIN);
var args = filter.getArgs();
expect(args.length).to.equal(5);
var distance = args[1];
expect(distance).to.be.a(ol.expr.Literal);
expect(distance.getValue()).to.equal(1000);
var units = args[2];
expect(units).to.be.a(ol.expr.Literal);
expect(units.getValue()).to.equal('m');
done();
});
});
it('writes DWithin', function(done) {
var url = 'spec/ol/parser/ogc/xml/filter_v1_0_0/dwithin.xml';
afterLoadXml(url, function(xml) {
var filter = new ol.expr.Call(new ol.expr.Identifier(
@@ -161,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,
@@ -179,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';
@@ -197,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';
@@ -213,30 +234,8 @@ 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',
describe('_expression reader', function() {
it('handles combined propertyname and literal',
function() {
var xml = '<ogc:UpperBoundary xmlns:ogc="' +
'http://www.opengis.net/ogc">10</ogc:UpperBoundary>';
@@ -244,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 = '<ogc:UpperBoundary xmlns:ogc="http://www.opengis.net/ogc">' +
'foo<ogc:PropertyName>x</ogc:PropertyName>bar</ogc:UpperBoundary>';

View File

@@ -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:
'<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">' +
@@ -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'];

View File

@@ -1,11 +0,0 @@
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/ogc http://schemas.opengis.net/filter/1.0.0/filter.xsd">
<ogc:PropertyIsBetween>
<ogc:PropertyName>when</ogc:PropertyName>
<ogc:LowerBoundary>
<ogc:Literal>2010-11-27T18:19:15.123Z</ogc:Literal>
</ogc:LowerBoundary>
<ogc:UpperBoundary>
<ogc:Literal>2011-12-27T18:19:15.123Z</ogc:Literal>
</ogc:UpperBoundary>
</ogc:PropertyIsBetween>
</ogc:Filter>

View File

@@ -1,11 +0,0 @@
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:PropertyIsBetween>
<ogc:PropertyName>when</ogc:PropertyName>
<ogc:LowerBoundary>
<ogc:Literal>2010-11-27</ogc:Literal>
</ogc:LowerBoundary>
<ogc:UpperBoundary>
<ogc:Literal>2011-12-27</ogc:Literal>
</ogc:UpperBoundary>
</ogc:PropertyIsBetween>
</ogc:Filter>