fix Filter namespace handling for WFS 2.0 requests

This commit is contained in:
Jannes Bolling
2020-10-15 18:50:55 +02:00
parent 7261e25566
commit b271536b8b
2 changed files with 191 additions and 76 deletions

View File

@@ -1104,11 +1104,8 @@ function writeDuringFilter(node, filter, objectStack) {
const parent = /** @type {Object} */ (objectStack[objectStack.length - 1]);
const context = parent['context'];
const version = context['version'];
const ns = FESNS[version];
const valueReference = createElementNS(ns, 'ValueReference');
writeStringTextNode(valueReference, filter.propertyName);
node.appendChild(valueReference);
writePropertyName(version, node, filter.propertyName);
const timePeriod = createElementNS(GMLNS, 'TimePeriod');
node.appendChild(timePeriod);
@@ -1176,12 +1173,11 @@ function writeComparisonFilter(node, filter, objectStack) {
const parent = /** @type {Object} */ (objectStack[objectStack.length - 1]);
const context = parent['context'];
const version = context['version'];
const ns = OGCNS[context['version']];
if (filter.matchCase !== undefined) {
node.setAttribute('matchCase', filter.matchCase.toString());
}
writePropertyName(version, node, filter.propertyName);
writeOgcLiteral(ns, node, '' + filter.expression);
writeLiteral(version, node, '' + filter.expression);
}
/**
@@ -1205,17 +1201,17 @@ function writeIsBetweenFilter(node, filter, objectStack) {
const parent = /** @type {Object} */ (objectStack[objectStack.length - 1]);
const context = parent['context'];
const version = context['version'];
const ns = OGCNS[context['version']];
const ns = getFilterNS(version);
writePropertyName(version, node, filter.propertyName);
const lowerBoundary = createElementNS(ns, 'LowerBoundary');
node.appendChild(lowerBoundary);
writeOgcLiteral(ns, lowerBoundary, '' + filter.lowerBoundary);
writeLiteral(version, lowerBoundary, '' + filter.lowerBoundary);
const upperBoundary = createElementNS(ns, 'UpperBoundary');
node.appendChild(upperBoundary);
writeOgcLiteral(ns, upperBoundary, '' + filter.upperBoundary);
writeLiteral(version, upperBoundary, '' + filter.upperBoundary);
}
/**
@@ -1227,7 +1223,6 @@ function writeIsLikeFilter(node, filter, objectStack) {
const parent = /** @type {Object} */ (objectStack[objectStack.length - 1]);
const context = parent['context'];
const version = context['version'];
const ns = OGCNS[version];
node.setAttribute('wildCard', filter.wildCard);
node.setAttribute('singleChar', filter.singleChar);
node.setAttribute('escapeChar', filter.escapeChar);
@@ -1235,7 +1230,7 @@ function writeIsLikeFilter(node, filter, objectStack) {
node.setAttribute('matchCase', filter.matchCase.toString());
}
writePropertyName(version, node, filter.propertyName);
writeOgcLiteral(ns, node, '' + filter.pattern);
writeLiteral(version, node, '' + filter.pattern);
}
/**
@@ -1244,12 +1239,21 @@ function writeIsLikeFilter(node, filter, objectStack) {
* @param {Node} node Node.
* @param {string} value Value.
*/
function writeOgcExpression(ns, tagName, node, value) {
function writeExpression(ns, tagName, node, value) {
const property = createElementNS(ns, tagName);
writeStringTextNode(property, value);
node.appendChild(property);
}
/**
* @param {string} version Version.
* @param {Node} node Node.
* @param {string} value PropertyName value.
*/
function writeLiteral(version, node, value) {
writeExpression(getFilterNS(version), 'Literal', node, value);
}
/**
* @param {string} version Version.
* @param {Node} node Node.
@@ -1257,30 +1261,12 @@ function writeOgcExpression(ns, tagName, node, value) {
*/
function writePropertyName(version, node, value) {
if (version === '2.0.0') {
writeFesValueReference(FESNS[version], node, value);
writeExpression(FESNS[version], 'ValueReference', node, value);
} else {
writeOgcExpression(OGCNS[version], 'PropertyName', node, value);
writeExpression(OGCNS[version], 'PropertyName', node, value);
}
}
/**
* @param {string} ns Namespace.
* @param {Node} node Node.
* @param {string} value PropertyName value.
*/
function writeFesValueReference(ns, node, value) {
writeOgcExpression(ns, 'ValueReference', node, value);
}
/**
* @param {string} ns Namespace.
* @param {Node} node Node.
* @param {string} value PropertyName value.
*/
function writeOgcLiteral(ns, node, value) {
writeOgcExpression(ns, 'Literal', node, value);
}
/**
* @param {Node} node Node.
* @param {string} time PropertyName value.

View File

@@ -687,7 +687,7 @@ describe('ol.format.WFS', function () {
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('creates a dwithin filter for WFS 1.x', function () {
it('creates a dwithin filter', function () {
const text =
'<wfs:Query xmlns:wfs="http://www.opengis.net/wfs" ' +
' typeName="area" srsName="EPSG:4326" ' +
@@ -729,55 +729,13 @@ describe('ol.format.WFS', function () {
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('creates a dwithin filter for WFS 2.0', function () {
const text =
'<wfs:Query xmlns:wfs="http://www.opengis.net/wfs/2.0" ' +
' typeNames="area" srsName="EPSG:4326" ' +
' xmlns:topp="http://www.openplans.org/topp">' +
' <fes:Filter xmlns:fes="http://www.opengis.net/fes/2.0">' +
' <fes:DWithin>' +
' <fes:ValueReference>the_geom</fes:ValueReference>' +
' <gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2">' +
' <gml:exterior>' +
' <gml:LinearRing>' +
' <gml:posList srsDimension="2">' +
' 10 20 10 25 15 25 15 20 10 20' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' </gml:Polygon>' +
' <fes:Distance uom="m">10</fes:Distance>' +
' </fes:DWithin>' +
' </fes:Filter>' +
'</wfs:Query>';
const serialized = new WFS({version: '2.0.0'}).writeGetFeature({
srsName: 'EPSG:4326',
featureTypes: ['area'],
filter: dwithinFilter(
'the_geom',
new Polygon([
[
[10, 20],
[10, 25],
[15, 25],
[15, 20],
[10, 20],
],
]),
10,
'm'
),
});
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('creates During property filter', function () {
const text =
'<wfs:Query xmlns:wfs="http://www.opengis.net/wfs" ' +
' typeName="states" srsName="EPSG:4326">' +
' <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">' +
' <ogc:During>' +
' <fes:ValueReference xmlns:fes="http://www.opengis.net/fes">date_prop</fes:ValueReference>' +
' <ogc:PropertyName>date_prop</ogc:PropertyName>' +
' <gml:TimePeriod xmlns:gml="http://www.opengis.net/gml">' +
' <gml:begin>' +
' <gml:TimeInstant>' +
@@ -1680,5 +1638,176 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
expect(serialized).to.xmleql(parse(text));
});
});
it('creates a dwithin filter', function () {
const text =
'<wfs:Query xmlns:wfs="http://www.opengis.net/wfs/2.0" ' +
' typeNames="area" srsName="EPSG:4326" ' +
' xmlns:topp="http://www.openplans.org/topp">' +
' <fes:Filter xmlns:fes="http://www.opengis.net/fes/2.0">' +
' <fes:DWithin>' +
' <fes:ValueReference>the_geom</fes:ValueReference>' +
' <gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2">' +
' <gml:exterior>' +
' <gml:LinearRing>' +
' <gml:posList srsDimension="2">' +
' 10 20 10 25 15 25 15 20 10 20' +
' </gml:posList>' +
' </gml:LinearRing>' +
' </gml:exterior>' +
' </gml:Polygon>' +
' <fes:Distance uom="m">10</fes:Distance>' +
' </fes:DWithin>' +
' </fes:Filter>' +
'</wfs:Query>';
const serialized = new WFS({version: '2.0.0'}).writeGetFeature({
srsName: 'EPSG:4326',
featureTypes: ['area'],
filter: dwithinFilter(
'the_geom',
new Polygon([
[
[10, 20],
[10, 25],
[15, 25],
[15, 20],
[10, 20],
],
]),
10,
'm'
),
});
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('creates isLike property filter', function () {
const text =
'<wfs:Query xmlns:wfs="http://www.opengis.net/wfs/2.0" ' +
' typeNames="topp:states" srsName="urn:ogc:def:crs:EPSG::4326" ' +
' xmlns:topp="http://www.openplans.org/topp">' +
' <fes:Filter xmlns:fes="http://www.opengis.net/fes/2.0">' +
' <fes:PropertyIsLike wildCard="*" singleChar="." escapeChar="!">' +
' <fes:ValueReference>name</fes:ValueReference>' +
' <fes:Literal>New*</fes:Literal>' +
' </fes:PropertyIsLike>' +
' </fes:Filter>' +
'</wfs:Query>';
const serialized = new WFS({version: '2.0.0'}).writeGetFeature({
srsName: 'urn:ogc:def:crs:EPSG::4326',
featureNS: 'http://www.openplans.org/topp',
featurePrefix: 'topp',
featureTypes: ['states'],
filter: likeFilter('name', 'New*'),
});
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('creates isBetween property filter', function () {
const text =
'<wfs:Query xmlns:wfs="http://www.opengis.net/wfs/2.0" ' +
' typeNames="topp:states" srsName="urn:ogc:def:crs:EPSG::4326" ' +
' xmlns:topp="http://www.openplans.org/topp">' +
' <fes:Filter xmlns:fes="http://www.opengis.net/fes/2.0">' +
' <fes:PropertyIsBetween>' +
' <fes:ValueReference>area</fes:ValueReference>' +
' <fes:LowerBoundary><fes:Literal>100</fes:Literal></fes:LowerBoundary>' +
' <fes:UpperBoundary><fes:Literal>1000</fes:Literal></fes:UpperBoundary>' +
' </fes:PropertyIsBetween>' +
' </fes:Filter>' +
'</wfs:Query>';
const serialized = new WFS({version: '2.0.0'}).writeGetFeature({
srsName: 'urn:ogc:def:crs:EPSG::4326',
featureNS: 'http://www.openplans.org/topp',
featurePrefix: 'topp',
featureTypes: ['states'],
filter: betweenFilter('area', 100, 1000),
});
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('creates greater/less than property filters', function () {
const text =
'<wfs:Query xmlns:wfs="http://www.opengis.net/wfs/2.0" ' +
' typeNames="topp:states" srsName="urn:ogc:def:crs:EPSG::4326" ' +
' xmlns:topp="http://www.openplans.org/topp">' +
' <fes:Filter xmlns:fes="http://www.opengis.net/fes/2.0">' +
' <fes:Or>' +
' <fes:And>' +
' <fes:PropertyIsGreaterThan>' +
' <fes:ValueReference>area</fes:ValueReference>' +
' <fes:Literal>100</fes:Literal>' +
' </fes:PropertyIsGreaterThan>' +
' <fes:PropertyIsGreaterThanOrEqualTo>' +
' <fes:ValueReference>pop</fes:ValueReference>' +
' <fes:Literal>20000</fes:Literal>' +
' </fes:PropertyIsGreaterThanOrEqualTo>' +
' </fes:And>' +
' <fes:And>' +
' <fes:PropertyIsLessThan>' +
' <fes:ValueReference>area</fes:ValueReference>' +
' <fes:Literal>100</fes:Literal>' +
' </fes:PropertyIsLessThan>' +
' <fes:PropertyIsLessThanOrEqualTo>' +
' <fes:ValueReference>pop</fes:ValueReference>' +
' <fes:Literal>20000</fes:Literal>' +
' </fes:PropertyIsLessThanOrEqualTo>' +
' </fes:And>' +
' </fes:Or>' +
' </fes:Filter>' +
'</wfs:Query>';
const serialized = new WFS({version: '2.0.0'}).writeGetFeature({
srsName: 'urn:ogc:def:crs:EPSG::4326',
featureNS: 'http://www.openplans.org/topp',
featurePrefix: 'topp',
featureTypes: ['states'],
filter: orFilter(
andFilter(
greaterThanFilter('area', 100),
greaterThanOrEqualToFilter('pop', 20000)
),
andFilter(
lessThanFilter('area', 100),
lessThanOrEqualToFilter('pop', 20000)
)
),
});
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
it('creates During property filter', function () {
const text =
'<wfs:Query xmlns:wfs="http://www.opengis.net/wfs/2.0" ' +
' typeNames="states" srsName="EPSG:4326">' +
' <fes:Filter xmlns:fes="http://www.opengis.net/fes/2.0">' +
' <fes:During>' +
' <fes:ValueReference>date_prop</fes:ValueReference>' +
' <gml:TimePeriod xmlns:gml="http://www.opengis.net/gml">' +
' <gml:begin>' +
' <gml:TimeInstant>' +
' <gml:timePosition>2010-01-20T00:00:00Z</gml:timePosition>' +
' </gml:TimeInstant>' +
' </gml:begin>' +
' <gml:end>' +
' <gml:TimeInstant>' +
' <gml:timePosition>2012-12-31T00:00:00Z</gml:timePosition>' +
' </gml:TimeInstant>' +
' </gml:end>' +
' </gml:TimePeriod>' +
' </fes:During>' +
' </fes:Filter>' +
'</wfs:Query>';
const serialized = new WFS({version: '2.0.0'}).writeGetFeature({
srsName: 'EPSG:4326',
featureTypes: ['states'],
filter: duringFilter(
'date_prop',
'2010-01-20T00:00:00Z',
'2012-12-31T00:00:00Z'
),
});
expect(serialized.firstElementChild).to.xmleql(parse(text));
});
});
});