Changeset 4344 for cows/trunk/cows
- Timestamp:
- 17/10/08 15:07:01 (11 years ago)
- Location:
- cows/trunk/cows
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
cows/trunk/cows/model/filterencoding.py
r4311 r4344 5 5 6 6 """ Classes to handle filter encoding queries as used in WFS """ 7 8 7 9 8 from xml.etree import ElementTree as etree … … 19 18 def GML(tag): 20 19 return "{"+nsGML+"}"+tag 20 21 22 23 class AndOperator(object): 24 """ Return the intersection of two filters""" 25 def __init__(self, elem): 26 self.children=elem.getchildren() 27 28 def evaluate(self, featureset): 29 qp=QueryProcessor() 30 filter=qp.getFilterOrOperator(self.children[0]) 31 set1=filter.evaluate(featureset) 32 filter2=qp.getFilterOrOperator(self.children[1]) 33 set2=filter2.evaluate(featureset) 34 resultset = set1.intersection(set2) 35 return resultset 21 36 22 class FEQuery(object):23 """ Represents a WFS Query string which can contain feature type names and a variety of filters """24 25 def __init__(self, querystring):26 self.querystring=str(querystring) #may be unicode, so convert to string27 self.elem=etree.fromstring(self.querystring)28 log.debug("Query String: %s"%self.querystring)29 log.debug("Query Element: %s"%self.elem)30 37 31 def getTypeName(self): 32 typename=self.elem.get('typeName') 33 log.debug('TypeName = %s'%typename) 34 return typename 35 36 def getFilters(self): 37 """returns parts of query as individual filters which can then be translated into 38 method calls on the wfs_iface. Examples of filters include, getByGMLid, getByBBox, getByTimeRange""" 39 queryfilters=[] 40 for child in self.elem.getchildren(): 41 if child.tag==OGC('Filter'): 42 #break <ogc:Filter> down into single filters. 43 fp=FilterParser(child) 44 for filter in fp.filters: 45 queryfilters.append(filter) 46 return queryfilters 38 class OrOperator(object): 39 """ Return the union of two filters""" 40 def __init__(self, elem): 41 self.children=elem.getchildren() 47 42 48 class FilterParser(object): 49 """ Handles an OGC Filter object which in reality can contain several 'sub-filters'. Breaks this down into individual 'Filters' """ 50 def __init__(self, filterelem): 51 self.filters=[] 52 for elem in filterelem.getchildren(): 53 if elem.tag == OGC('GmlObjectId'): 54 value=elem.get(GML('id')) 55 f=Filter('GmlObjectId', value) 56 self.filters.append(f) 57 elif elem.tag==OGC('BBOX'): 58 value=(1,2,3,4) 59 srsname='WGS84' 60 f=BBoxFilter(srsname, 'BBOX', value) 61 self.filters.append(f) 62 43 def evaluate(self, featureset): 44 qp=QueryProcessor() 45 filter=qp.getFilterOrOperator(self.children[0]) 46 set1=filter.evaluate(featureset) 47 filter2=qp.getFilterOrOperator(self.children[1]) 48 set2=filter2.evaluate(featureset) 49 resultset = set1.union(set2) 50 return resultset 51 52 #TODO: NOT operator 63 53 64 54 class Filter(object): 65 """represents an individual WFS filter (i.e. a filter containing 'And' will be modelled as 2 filters). 66 @ivar filtertype: Type of filter (e.g. 'getByBBox') 67 @ivar fitlervalue: Appropriate value on which to filter (e.g. Bounding box tuple) 68 """ 69 def __init__(self, filtertype, filtervalue): 70 self.filtertype = filtertype 71 self.filtervalue = filtervalue 55 def __init__(self, elem): 56 self.elem=elem 57 58 59 class GMLIdFilter(Filter): 60 def evaluate(self, featureset): 61 log.debug('Value of gml id filter %s'%self.elem.get(GML('id'))) 62 resultset=set([featureset.getFeatureByGMLid(self.elem.get(GML('id')))]) 63 return resultset 72 64 73 65 class BBoxFilter(Filter): 74 """ As Filter, but with additional srsname attribute """ 75 def __init__(self, srsname, *args): 76 super(BBoxFilter, self).__init__(*args) 77 self.srsname=srsname 66 def evaluate(self, featureset): 67 #parse the bbox xml envelope to get values 68 envelope=self.elem.getchildren()[0] 69 srsname=envelope.get('srsName') 70 lowercorner=envelope.getchildren()[0].text.split() 71 uppercorner=envelope.getchildren()[1].text.split() 72 bbtuple=(float(lowercorner[0]),float(lowercorner[1]), float(uppercorner[0]), float(uppercorner[1])) 73 resultset=set(featureset.getFeaturesByBBox(bbtuple, srsname)) 74 return resultset 75 76 class FEQueryProcessor(object): 77 def __init__(self): 78 pass 79 80 def evaluate(self, featureset, queryxml): 81 #The root elem should only have one direct child elemtent. Evaluating this 82 #child element should return the resultset for the entire nested filter. 83 self.rootelem=etree.fromstring(queryxml) 84 log.debug('filter root element %s'%self.rootelem) 85 log.debug('child elements %s'%self.rootelem.getchildren()) 86 filterelem=self.rootelem.getchildren()[0] 87 resultset=set() 88 for filterdef in filterelem.getchildren(): 89 filter=self.getFilterOrOperator(filterdef) 90 filterresult=filter.evaluate(featureset) 91 resultset=resultset.union(filterresult) 92 return resultset 93 94 def getFilterOrOperator(self, filterelem): 95 if filterelem.tag=='And': 96 f=AndOperator(filterelem) 97 elif filterelem.tag=='Or': 98 f=OrOperator(filterelem) 99 elif filterelem.tag ==OGC('GmlObjectId'): 100 f=GMLIdFilter(filterelem) 101 elif filterelem.tag ==OGC('BBOX'): 102 f=BBoxFilter(filterelem) 103 log.debug('Filter tag = %s'%filterelem.tag) 104 return f 78 105 79 class FEQueryProcessor(object): 80 """ Given a Featureset and a list of of Filters, applies the filters 81 to the Featureset and creates a resultset 82 Assumptions: 83 1) GmlObjectId is only used as a filter alone or with other GmlObjectId filters, not with other filter types. 84 2) Other filter types, such as bounding box or temporal range filters only appear once. 85 86 """ 87 88 def __init__(self, featureset, filters): 89 self.featureset=featureset 90 self.resultset=[] 91 temporalrangeresults=[] 92 bboxresults=[] 93 temporalflag=False 94 bboxflag = False 95 for filter in filters: 96 log.debug('Filtertype %s'%filter.filtertype) 97 if filter.filtertype=='GmlObjectId': 98 feature=self.featureset.getFeatureByGMLid(filter.filtervalue) 99 if feature: 100 self.resultset.append(feature) 101 else: 102 #handle other filtertypes, bbox & temporal for now: 103 if filter.filtertype=='BBOX': 104 bboxflag=True 105 bboxresults=self.featureset.getFeaturesByBBox(filter.filtervalue, filter.srsname) 106 elif filter.filtertype=='TemporalRange': 107 temporalflag=True 108 temporalrangeresults=self.featureset.getFeaturesByTemporalRange(filter.filtervalue) 109 110 #Now work out what the overlapping (if appropriate) resultset is. 111 log.debug('bboxflag %s'%bboxflag) 112 if temporalflag and bboxflag: #both filters applied 113 log.debug('results from temporal & bbox filter %s'%self.resultset) 114 self.resultset=self._combineresults([set(temporalrangeresults), set(bboxresults)]) 115 elif temporalflag: #only temporal filter 116 self.resultset=temporalrangeresults 117 log.debug('results from temporal only filter %s'%self.resultset) 118 elif bboxflag: #only bbox filter 119 self.resultset=bboxresults 120 log.debug('results from bbox only filter %s'%self.resultset) 106 121 107 122 log.debug('results from gml filter %s'%self.resultset)123 #TODO, handle null filter124 125 126 def _combineresults(self, results):127 """ combine (AND operation) results from two or more filters """128 baseset=[]129 for set in results:130 if baseset == []:131 baseset = set132 else:133 baseset=baseset.intersection(set)134 return baseset135 136 -
cows/trunk/cows/pylons/wfs_controller.py
r4298 r4344 18 18 19 19 from cows.model.wfs import WfsFeatureSummary 20 from cows.model.filterencoding import FEQuery , FEQueryProcessor20 from cows.model.filterencoding import FEQueryProcessor 21 21 from cows.model import PossibleValues, WGS84BoundingBox, BoundingBox, Contents 22 22 from cows.pylons import ows_controller … … 157 157 158 158 #Parse the query to analyse the filters it contains 159 query=FEQuery(self.getOwsParam('query')) 160 filters=query.getFilters() 159 queryxml=self.getOwsParam('query') 160 qp=FEQueryProcessor() 161 c.resultset=qp.evaluate(self.featureset, queryxml) 162 log.debug('Final resultset from query processor %s'%c.resultset) 161 163 162 #now apply the filters to the featureset 163 qp=FEQueryProcessor(self.featureset, filters) 164 #TODO: Group resultset together in a wfs feature collection (use template) 165 # return qp.resultset 166 c.resultset=qp.resultset 164 165 #Group resultset together in a wfs feature collection (use template) 167 166 response.headers['content-type'] = 'text/xml' 168 167 t = ows_controller.templateLoader.load('wfs_featurecollection.xml')
Note: See TracChangeset
for help on using the changeset viewer.