Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I have two OGC filters client side:

<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
    <ogc:PropertyIsEqualTo matchCase="true">
        <ogc:PropertyName>code</ogc:PropertyName>
        <ogc:Literal>secret</ogc:Literal>
    </ogc:PropertyIsEqualTo>
</ogc:Filter>   

<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
    <ogc:Intersects>
        <ogc:PropertyName>geom</ogc:PropertyName>
        <gml:Box xmlns:gml="http://www.opengis.net/gml">
            <gml:coordinates decimal="." cs="," ts=" ">1298543.0367787,7107400.531374 1299312.4070614,7203464.9016567</gml:coordinates>
        </gml:Box>
    </ogc:Intersects>
</ogc:Filter>

I have both filters represented as strings and I want to combine them into one filter. I can see in the documentation that OpenLayers can create a Filter Object from a string, but it doesn't seem to work for me.

Am I doing something wrong and/or how should I do it?

share|improve this question

2 Answers 2

up vote 7 down vote accepted

To read a filter from a string should look something like:

var my_filter_xml, parser, xml;

parser = new OpenLayers.Format.Filter.v1_1_0 ();
xml = new OpenLayers.Format.XML();
my_filter_xml = '<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc"><ogc:PropertyIsEqualTo matchCase="true"><ogc:PropertyName>code</ogc:PropertyName><ogc:Literal>secret</ogc:Literal></ogc:PropertyIsEqualTo></ogc:Filter>'; //your filter string

var x = xml.read(my_filter_xml).documentElement
var filter1 = parser.read(x);
console.log(filter1);

This should return you an OpenLayers.Filter object. Do this for both your filters so you have two filter objects.

Finally create a new "parent" filter (which can be AND, OR, etc.) which combines the two:

    var parent_filter = new OpenLayers.Filter.Logical({
        type: OpenLayers.Filter.Logical.AND,
        filters: [filter1, filter2]
    });
share|improve this answer
    
It looks good, but it doesn't work for me. The first filter returns undefined by the parser.read() and the second returns TypeError: filter.components is undefined - in both cases the xml.read works fine. –  Chau Jul 26 '11 at 10:42
    
@Chau - try with the v1_1_0 filter. –  geographika Jul 26 '11 at 17:00
    
I already tried the v1_1_0 filter, which makes sense to use due to its builtin support for the GML tag (which is missing in the v1 filter). It still doesn't work, but the v1_0_0 filter does!!! I haven't debugged through the v1_1_0 filter to determine the problem though. Since the v1_0_0 filter inherits from GML2 and v1_1_0 from GML3, it might be a problem with my filters not complying to the GML3 standard. –  Chau Jul 28 '11 at 8:28
    
@Chau - I did try the code above with a new build of OpenLayers (2.11), and it created a valid object for the first filter (after stripping whitespace). What error are you getting? –  geographika Jul 28 '11 at 8:37
1  
The problem is that the GML2 implementation supports the gml:Box element and the the GML3 doesn't. So even though the v1_1_0 filter finds a spacial component, it fails to parse it and cannot return the filter due to its contents never was created. I am using OL 2.10 until the 2.11 is released as the stable version. For me using the v1_0_0 is just fine :) –  Chau Jul 28 '11 at 9:00

Try this:

<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
    <ogc:And>
        <ogc:Or>
            <ogc:PropertyIsEqualTo matchCase="true">
                <ogc:PropertyName>code</ogc:PropertyName>
                <ogc:Literal>secret</ogc:Literal>
            </ogc:PropertyIsEqualTo>
        </ogc:Or>
        <ogc:Or>
            <ogc:Intersects>
                <ogc:PropertyName>geom</ogc:PropertyName>
                <gml:Box xmlns:gml="http://www.opengis.net/gml">
                    <gml:coordinates decimal="." cs="," ts=" ">1298543.0367787,7107400.531374 1299312.4070614,7203464.9016567</gml:coordinates>
                </gml:Box>
            </ogc:Intersects>
        </ogc:Or>
    </ogc:And>
</ogc:Filter>

EDIT #1: Here's my code in case it helps any :

MyApp.Search.GetWFSSpatialFilters = function () {

    function getOtherAttributesFilter() {
        var _filters = [];
        //If txtMyAppID has a value, add them.
        var MyAppIDs = $.trim($("#txtMyAppID").val()).split(",");

        if (MyAppIDs != "") {

            for (r in MyAppIDs) {
                _filters.push(
                    new OpenLayers.Filter.Comparison({
                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
                        property: "id",
                        value: MyAppIDs[r]
                    })
                );
            }

        }

        return _filters;
    }

    function getDateFilter() {
        var _filters = [];
        //If startTime OR endTime fall between search times, it's a match.
        _filters.push(
            new OpenLayers.Filter.Comparison({
                type: OpenLayers.Filter.Comparison.BETWEEN,
                property: "startDate",
                lowerBoundary: MyApp.Util.ISODateString(MyApp.UI.ControlPanel.DateRange.getDateFrom()),
                upperBoundary: MyApp.Util.ISODateString(MyApp.UI.ControlPanel.DateRange.getDateTo())
            })
        );
        _filters.push(
            new OpenLayers.Filter.Comparison({
                type: OpenLayers.Filter.Comparison.BETWEEN,
                property: "endDate",
                lowerBoundary: MyApp.Util.ISODateString(MyApp.UI.ControlPanel.DateRange.getDateFrom()),
                upperBoundary: MyApp.Util.ISODateString(MyApp.UI.ControlPanel.DateRange.getDateTo())
            })
        );
        return _filters;
    }
    function getSatFilter() {
        var _filters = [];

        //gather all satellites 
        $.each(MyApp.Satellites.Items, function (index, satellite) {

            if (satellite.checked) {
                //console.log("(" + satellite.name.toString() + ")");

                _filters.push(
                    new OpenLayers.Filter.Comparison({
                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
                        property: "platformName",
                        value: satellite.name.toString()
                    })
                );
            }
        });

        return _filters;
    }

    function getSpatialFilter() {
        var _filters = [];

        //console.log(MyApp.Region.Items);

        //if there aren't any regions defined, use viewport.
        if (MyApp.Region.Items.length > 0) {
            //gather all regions

            $.each(MyApp.Region.Items, function (index, region) {

                _filters.push(
                    new OpenLayers.Filter.Spatial({
                        //property: "boundsText",
                        type: OpenLayers.Filter.Spatial.INTERSECTS,
                        value: region.feature[0].geometry.clone().transform(MyApp.UI.Map.Projections.Mercator, MyApp.UI.Map.Projections.Geographic),
                        projection: "EPSG:4326"
                    })
                );

            });

        } else {
            // use viewport not to go over maxExtent.
            var boundsViewport = MyApp.UI.Map.getMap().getExtent().toGeometry().clone().transform(MyApp.UI.Map.Projections.Mercator, MyApp.UI.Map.Projections.Geographic).getBounds();
            var maxExtent = MyApp.UI.Map.getMap().maxExtent.toGeometry().clone().transform(MyApp.UI.Map.Projections.Mercator, MyApp.UI.Map.Projections.Geographic).getBounds();

            var geometryToUse;

            if (maxExtent.containsBounds(boundsViewport, false, true)) {
                geometryToUse = MyApp.UI.Map.getMap().getExtent().toGeometry().clone().transform(MyApp.UI.Map.Projections.Mercator, MyApp.UI.Map.Projections.Geographic);
            } else {
                geometryToUse = MyApp.UI.Map.getMap().maxExtent.toGeometry().clone().transform(MyApp.UI.Map.Projections.Mercator, MyApp.UI.Map.Projections.Geographic);
            }

            _filters.push(
                new OpenLayers.Filter.Spatial({
                    //property: "boundsText",
                    type: OpenLayers.Filter.Spatial.INTERSECTS,
                    value: geometryToUse,
                    projection: "EPSG:4326"
                })
            );

        }


        return _filters;
    }



    var _filters = [];


    //create sat filter.
    _filters.push(
        new OpenLayers.Filter.Logical({
            type: OpenLayers.Filter.Logical.OR,
            filters: getSatFilter()
        })
    );

    //create date filter.
    _filters.push(
        new OpenLayers.Filter.Logical({
            type: OpenLayers.Filter.Logical.OR,
            filters: getDateFilter()
        })
    );

    //create spatial filter.
    _filters.push(
        new OpenLayers.Filter.Logical({
            type: OpenLayers.Filter.Logical.OR,
            filters: getSpatialFilter()
        })
    );

    //create Other attributes filter.
    var attributefilter = getOtherAttributesFilter();
    if (attributefilter.length > 0) {
        _filters.push(
            new OpenLayers.Filter.Logical({
                type: OpenLayers.Filter.Logical.OR,
                filters: attributefilter
            })
        );
    }



    return _filters;
};


var searchFilter = new OpenLayers.Filter.Logical({
    type: OpenLayers.Filter.Logical.AND,
    filters: MyApp.Search.GetWFSSpatialFilters()
})

//console.log(myFilters);
var protocol = new OpenLayers.Protocol.WFS({
    version: "1.1.0",
    url: MyApp.MapBase.Configuration.GeoServer.WFS_Service.EndPointURL,
    featurePrefix: MyApp.MapBase.Configuration.GeoServer.WFS_Service.featurePrefix,
    featureType: MyApp.MapBase.Configuration.GeoServer.WFS_Service.featureType,
    featureNS: MyApp.MapBase.Configuration.GeoServer.WFS_Service.featureNS,
    geometryName: MyApp.MapBase.Configuration.GeoServer.WFS_Service.geometryName,
    defaultFilter: searchFilter,
    srsName: MyApp.UI.Map.Projections.Mercator
});

var response = protocol.read({
    maxFeatures: MyApp.Search.Properties.maxResults,
    callback: MyApp.Search.SearchComplete_CallBack
});
share|improve this answer
    
Wouldn't that work without the Or tags too? –  underdark Jul 26 '11 at 15:00
    
It could, but if he has an array of properties like "code" or geometries to intersect he's going to want to wrap them in the "Or" tag. Just wanna cover all bases. –  CaptDragon Jul 26 '11 at 15:04

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.