Motivation: |
X-path expressions can return multiple values. Comparison operators on values (=, <, >, etc) and geometries (overlaps, intersects, etc...) in the filters currently do not handle multiple values as input. |
|
|---|---|---|
Contact: |
||
Tracker: |
||
Tagline: |
|
This page represents the current plan; for discussion please check the tracker link above.
|
The proposal is to modify the following filters:
To allow collections of values as input, besides single values. if an expression returns a collection of values rather than just a single value, the filters will be able to handle it. The OGC Filter standard specifies that the way to deal with multiple values can be modified using the "matchAction" flag:
|
7.7.3.3 EXAMPLE The following example illustrates the use of the matchAction attribute. Consider the following XML
And consider the following filter expression:
If the value of the matchAction attribute is set to Any, this predicate will evaluate to true since there is at least |
The default value of "matchAction" is "Any" i.e. the result will be the OR-ed aggregation of all possible combinations. For example, if we compare the following values
(x, y, z) = (a, b)
the result will be true if x=a OR x=b OR y=a OR y=b OR z=a OR z=b.
The plan is to introduce an Enum MatchAction for ANY, ALL, ONE.
The update is limited to:
Update FilterFactory and FilterFactory2 interfaces to allow MatchAction to be supplied.
For reference here is a code example showing how things stand:
Filter filter1 = ff.equals( expr1, expr2); // assume default case sensitive match Filter filter2 = ff.equals( expr1, expr2, false ); // case insensitive match |
The idea is to explicitly allow for MatchCase enumeration:
Filter filter3 = ff.equals( expr1, expr2, MatchCase.ANY ); Filter filter4 = ff.equals( expr1, expr2, true, MatchCase.ONE ); |
Inside the implementation of equals we will need to update the code to expect a List of values (rather than a single value).
Here is an example of how any filter implementation can be made compatible with multiple values:
public boolean evaluate(Object feature) {
final Object object1 = eval(expression1, feature);
final Object object2 = eval(expression2, feature);
if(!(object1 instanceof Collection) && !(object2 instanceof Collection)) {
return evaluateInternal(value1, value2);
}
Collection<Object> leftValues = object1 instanceof Collection ? (Collection<Object>) object1
: Collections.singletonList(object1);
Collection<Object> rightValues = object2 instanceof Collection ? (Collection<Object>) object2
: Collections.singletonList(object2);
int count = 0;
for (Object value1 : leftValues) {
for (Object value2 : rightValues) {
boolean temp = evaluateInternal(value1, value2)) {
if (temp) {
count++;
}
switch (matchAction){
case ONE: if (count > 1) return false; break;
case ALL: if (!temp) return false; break;
case ANY: if (temp) return true; break;
}
}
}
switch (matchAction){
case ONE: return (count == 1);
case ALL: return true;
case ANY: return false;
}
}
public abstract boolean evaluateInternal(Object value1, Object value2);
|
Proposal accepted, work is proceeding on the 8.x branch:
|
no progress |
|
done |
|
impeded |
|
lack mandate/funds/time |
|
volunteer needed |
|---|
BEFORE:
interface FilterFactory {
...
PropertyIsEqualTo equals(Expression expr1, Expression expr2);
PropertyIsEqualTo equal(Expression expr1, Expression expr2, boolean matchCase);
...
}
|
AFTER:
interface FilterFactory {
...
PropertyIsEqualTo equals(Expression expr1, Expression expr2);
PropertyIsEqualTo equal(Expression expr1, Expression expr2, boolean matchCase);
PropertyIsEqualTo equal(Expression expr1, Expression expr2, boolean matchCase, MatchAction matchAction);
...
}
|
(This is done for any filter that supports matchAction).
BEFORE:
public interface BinaryComparisonOperator extends Filter {
...
}
public interface PropertyIsBetween extends Filter {
...
}
public interface PropertyIsLike extends Filter {
...
}
public interface SpatialOperator extends Filter {
...
}
|
AFTER:
public interface MultiValuedFilter extends Filter {
enum MatchAction {ANY, ALL, ONE};
MatchAction getMatchAction();
}
public interface BinaryComparisonOperator extends MultiValuedFilter {
...
}
public interface PropertyIsBetween extends MultiValuedFilter {
...
}
public interface PropertyIsLike extends MultiValuedFilter {
...
}
public interface SpatialOperator extends MultiValuedFilter {
...
}
|
(The same is done for PropertyIsBetween, PropertyIsLike and SpatialOperator )