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))
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
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)