Example #1
0
    def test_wfs_build_getfeature_request_filter(self):
        """Test the owsutil.wfs_build_getfeature_request method with an
        attribute filter.

        Test whether the XML of the WFS GetFeature call is generated correctly.

        """
        query = PropertyIsEqualTo(propertyname='gemeente',
                                  literal='Herstappe')
        filter_request = FilterRequest()
        filter_request = filter_request.setConstraint(query)
        try:
            filter_request = etree.tostring(filter_request,
                                            encoding='unicode')
        except LookupError:
            # Python2.7 without lxml uses 'utf-8' instead.
            filter_request = etree.tostring(filter_request,
                                            encoding='utf-8')

        xml = owsutil.wfs_build_getfeature_request(
            'dov-pub:Boringen', filter=filter_request)
        assert clean_xml(etree.tostring(xml).decode('utf8')) == clean_xml(
            '<wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs" '
            'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            'service="WFS" version="1.1.0" '
            'xsi:schemaLocation="http://www.opengis.net/wfs '
            'http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"> <wfs:Query '
            'typeName="dov-pub:Boringen"> <ogc:Filter> '
            '<ogc:PropertyIsEqualTo> '
            '<ogc:PropertyName>gemeente</ogc:PropertyName> '
            '<ogc:Literal>Herstappe</ogc:Literal> </ogc:PropertyIsEqualTo> '
            '</ogc:Filter> </wfs:Query> </wfs:GetFeature>')
Example #2
0
    def test_wfs_build_getfeature_request_bbox_filter(self):
        """Test the owsutil.wfs_build_getfeature_request method with an
        attribute filter, a box and a geometry_column.

        Test whether the XML of the WFS GetFeature call is generated correctly.

        """
        query = PropertyIsEqualTo(propertyname='gemeente', literal='Herstappe')
        filter_request = FilterRequest()
        filter_request = filter_request.setConstraint(query)
        filter_request = etree.tostring(filter_request, encoding='unicode')

        xml = owsutil.wfs_build_getfeature_request(
            'dov-pub:Boringen',
            filter=filter_request,
            location=Within(Box(151650, 214675, 151750, 214775)),
            geometry_column='geom')
        assert clean_xml(etree.tostring(xml).decode('utf8')) == clean_xml(
            '<wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs" '
            'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            'service="WFS" version="1.1.0" '
            'xsi:schemaLocation="http://www.opengis.net/wfs '
            'http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"> <wfs:Query '
            'typeName="dov-pub:Boringen"> <ogc:Filter> <ogc:And> '
            '<ogc:PropertyIsEqualTo> '
            '<ogc:PropertyName>gemeente</ogc:PropertyName> '
            '<ogc:Literal>Herstappe</ogc:Literal> </ogc:PropertyIsEqualTo> '
            '<ogc:Within> <ogc:PropertyName>geom</ogc:PropertyName> '
            '<gml:Envelope xmlns:gml="http://www.opengis.net/gml" '
            'srsDimension="2" '
            'srsName="http://www.opengis.net/gml/srs/epsg.xml#31370"> '
            '<gml:lowerCorner>151650.000000 214675.000000</gml:lowerCorner> '
            '<gml:upperCorner>151750.000000 214775.000000</gml:upperCorner> '
            '</gml:Envelope> </ogc:Within> </ogc:And> </ogc:Filter> '
            '</wfs:Query> </wfs:GetFeature>')
Example #3
0
    def _search(self, location=None, query=None, return_fields=None,
                sort_by=None, max_features=None, extra_wfs_fields=[]):
        """Perform the WFS search by issuing a GetFeature request.

        Parameters
        ----------
        location : pydov.util.location.AbstractLocationFilter
            Location filter limiting the features to retrieve.
        query : owslib.fes.OgcExpression
            OGC filter expression to use for searching. This can contain any
            combination of filter elements defined in owslib.fes. The query
            should use the fields provided in `get_fields()`. Note that not
            all fields are currently supported as a search parameter.
        return_fields : list<str>
            A list of fields to be returned in the output data. This should
            be a subset of the fields provided in `get_fields()`. Note that
            not all fields are currently supported as return fields.
        sort_by : owslib.fes.SortBy, optional
            List of properties to sort by.
        max_features : int
            Limit the maximum number of features to request.
        extra_wfs_fields: list<str>
            A list of extra fields to be included in the WFS requests,
            regardless whether they're needed as return field. Optional,
            defaults to an empty list.

        Returns
        -------
        etree.Element
            XML tree of the WFS response containing the features matching
            the location or the query.

        Raises
        ------
        pydov.util.errors.InvalidSearchParameterError
            When not one of `location`, `query` or `max_features` is provided.

        pydov.util.errors.InvalidFieldError
            When at least one of the fields in `return_fields` is unknown.

            When a field that is only accessible as return field is used as
            a query parameter.

            When a field that can only be used as a query parameter is used as
            a return field.

        pydov.util.errors.FeatureOverflowError
            When the number of features to be returned is equal to the
            maxFeatures limit of the WFS server.

        """
        self._pre_search_validation(location, query, sort_by, return_fields,
                                    max_features)
        self._init_namespace()
        self._init_wfs()

        filter_request = None
        if query is not None:
            filter_request = FilterRequest()
            filter_request = filter_request.setConstraint(query)

        if filter_request is not None:
            for property_name in filter_request.findall(
                    './/{http://www.opengis.net/ogc}PropertyName'):
                property_name.text = self._map_df_wfs_source.get(
                    property_name.text, property_name.text)

            try:
                filter_request = etree.tostring(filter_request,
                                                encoding='unicode')
            except LookupError:
                # Python2.7 without lxml uses 'utf-8' instead.
                filter_request = etree.tostring(filter_request,
                                                encoding='utf-8')

        if return_fields is None:
            wfs_property_names = [
                f['sourcefield'] for f in self._type.get_fields(
                    source=('wfs',)).values() if not f.get(
                    'wfs_injected', False)]
        else:
            wfs_property_names = [self._map_df_wfs_source[i]
                                  for i in self._map_df_wfs_source
                                  if i.startswith('pkey')]
            wfs_property_names.extend([self._map_df_wfs_source[i]
                                       for i in self._map_df_wfs_source
                                       if i in return_fields])

        wfs_property_names.extend(extra_wfs_fields)
        wfs_property_names = list(set(wfs_property_names))

        if sort_by is not None:
            sort_by_xml = sort_by.toXML()
            for property_name in sort_by_xml.findall(
                    './/{http://www.opengis.net/ogc}PropertyName'):
                property_name.text = self._map_df_wfs_source.get(
                    property_name.text, property_name.text)

            try:
                sort_by = etree.tostring(sort_by_xml, encoding='unicode')
            except LookupError:
                # Python2.7 without lxml uses 'utf-8' instead.
                sort_by = etree.tostring(sort_by_xml, encoding='utf-8')

        fts = self._get_remote_wfs_feature(
            wfs=self.__wfs,
            typename=self._layer,
            location=location,
            filter=filter_request,
            sort_by=sort_by,
            max_features=max_features,
            propertyname=wfs_property_names,
            geometry_column=self._geometry_column)

        tree = etree.fromstring(fts)

        if tree.get('numberOfFeatures') is None:
            raise WfsGetFeatureError(
                'Error retrieving features from DOV WFS server:\n{}'.format(
                    etree.tostring(tree).decode('utf8')))

        if int(tree.get('numberOfFeatures')) == 10000:
            raise FeatureOverflowError(
                'Reached the limit of {:d} returned features. Please split up '
                'the query to ensure getting all results.'.format(10000))

        for hook in pydov.hooks:
            hook.wfs_search_result(int(tree.get('numberOfFeatures')))

        return tree
Example #4
0
    def _pre_search_validation(self, location, query, sort_by,
                               return_fields, max_features):
        """Perform validation on the parameters of the search query.

        Parameters
        ----------
        location : pydov.util.location.AbstractLocationFilter
            Location filter limiting the features to retrieve.
        query : owslib.fes.OgcExpression
            OGC filter expression to use for searching. This can contain any
            combination of filter elements defined in owslib.fes. The query
            should use the fields provided in `get_fields()`. Note that not
            all fields are currently supported as a search parameter.
        sort_by : owslib.fes.SortBy, optional
            List of properties to sort by.
        return_fields : list<str> or tuple<str> or set<str>
            A list of fields to be returned in the output data. This should
            be a subset of the fields provided in `get_fields()`.
        max_features : int
            Limit the maximum number of features to request.

        Raises
        ------
        pydov.util.errors.InvalidSearchParameterError
            When not one of `location`, `query` or `max_features` is provided.

        pydov.util.errors.InvalidFieldError
            When at least one of the fields in `return_fields` is unknown.

            When a field that is only accessible as return field is used as
            a query parameter.

        """
        if location is None and query is None and max_features is None:
            raise InvalidSearchParameterError(
                'Provide either the location or the query parameter or the '
                'max_features parameter.'
            )

        if query is not None:
            if not isinstance(query, owslib.fes.OgcExpression):
                raise InvalidSearchParameterError(
                    "Query should be an owslib.fes.OgcExpression.")

            filter_request = FilterRequest()
            filter_request = filter_request.setConstraint(query)

            self._init_fields()
            for property_name in filter_request.findall(
                    './/{http://www.opengis.net/ogc}PropertyName'):
                name = property_name.text
                if name not in self._map_df_wfs_source \
                        and name not in self._wfs_fields:
                    if name in self._fields:
                        raise InvalidFieldError(
                            "Cannot use return field '{}' in query.".format(
                                name))
                    raise InvalidFieldError(
                        "Unknown query parameter: '{}'".format(name))

        if location is not None:
            self._init_fields()

        if sort_by is not None:
            if not isinstance(sort_by, owslib.fes.SortBy):
                raise InvalidSearchParameterError(
                    "SortBy should be an owslib.fes.SortBy")

            self._init_fields()
            for property_name in sort_by.toXML().findall(
                    './/{http://www.opengis.net/ogc}PropertyName'):
                name = property_name.text
                if name not in self._map_df_wfs_source \
                        and name not in self._wfs_fields:
                    if name in self._fields:
                        raise InvalidFieldError(
                            "Cannot use return field '{}' for sorting.".format(
                                name))
                    raise InvalidFieldError(
                        "Unknown query parameter: '{}'".format(name))

        if return_fields is not None:
            if type(return_fields) not in (list, tuple, set):
                raise AttributeError('return_fields should be a list, '
                                     'tuple or set')

            self._init_fields()
            for rf in return_fields:
                if rf not in self._fields:
                    if rf in self._map_wfs_source_df:
                        raise InvalidFieldError(
                            "Unknown return field: "
                            "'{}'. Did you mean '{}'?".format(
                                rf, self._map_wfs_source_df[rf]))
                    if rf.lower() in [i.lower() for i in
                                      self._map_wfs_source_df.keys()]:
                        sugg = [i for i in self._map_wfs_source_df.keys() if
                                i.lower() == rf.lower()][0]
                        raise InvalidFieldError(
                            "Unknown return field: "
                            "'{}'. Did you mean '{}'?".format(rf, sugg))
                    raise InvalidFieldError(
                        "Unknown return field: '{}'".format(rf))
Example #5
0
    def _pre_search_validation(self,
                               location=None,
                               query=None,
                               return_fields=None):
        """Perform validation on the parameters of the search query.

        Parameters
        ----------
        location : tuple<minx,miny,maxx,maxy>
            The bounding box limiting the features to retrieve.
        query : owslib.fes.OgcExpression
            OGC filter expression to use for searching. This can contain any
            combination of filter elements defined in owslib.fes. The query
            should use the fields provided in `get_fields()`. Note that not
            all fields are currently supported as a search parameter.
        return_fields : list<str> or tuple<str> or set<str>
            A list of fields to be returned in the output data. This should
            be a subset of the fields provided in `get_fields()`.

        Raises
        ------
        pydov.util.errors.InvalidSearchParameterError
            When not one of `location` or `query` is provided.

        pydov.util.errors.InvalidFieldError
            When at least one of the fields in `return_fields` is unknown.

            When a field that is only accessible as return field is used as
            a query parameter.

        """
        if location is None and query is None:
            raise InvalidSearchParameterError(
                'Provide either the location or the query parameter.')

        if query is not None:
            if not isinstance(query, owslib.fes.OgcExpression):
                raise InvalidSearchParameterError(
                    "Query should be an owslib.fes.OgcExpression.")

            filter_request = FilterRequest()
            filter_request = filter_request.setConstraint(query)

            self._init_fields()
            for property_name in filter_request.findall(
                    './/{http://www.opengis.net/ogc}PropertyName'):
                name = property_name.text
                if name not in self._map_df_wfs_source \
                        and name not in self._wfs_fields:
                    if name in self._fields:
                        raise InvalidFieldError(
                            "Cannot use return field '%s' in query." % name)
                    raise InvalidFieldError("Unknown query parameter: '%s'" %
                                            name)

        if location is not None:
            self._init_fields()

        if return_fields is not None:
            if type(return_fields) not in (list, tuple, set):
                raise AttributeError('return_fields should be a list, '
                                     'tuple or set')

            self._init_fields()
            for rf in return_fields:
                if rf not in self._fields:
                    if rf in self._map_wfs_source_df:
                        raise InvalidFieldError(
                            "Unknown return field: '%s'. Did you mean '%s'?" %
                            (rf, self._map_wfs_source_df[rf]))
                    if rf.lower() in [
                            i.lower() for i in self._map_wfs_source_df.keys()
                    ]:
                        sugg = [
                            i for i in self._map_wfs_source_df.keys()
                            if i.lower() == rf.lower()
                        ][0]
                        raise InvalidFieldError(
                            "Unknown return field: '%s'. Did you mean '%s'?" %
                            (rf, sugg))
                    raise InvalidFieldError("Unknown return field: '%s'" % rf)