Changeset 1095
- Timestamp:
- 05/09/08 07:16:18
- Files:
-
- OWSLib/trunk/owslib/coverage (added)
- OWSLib/trunk/owslib/coverage/__init__.py (added)
- OWSLib/trunk/owslib/coverage/wcs100.py (added)
- OWSLib/trunk/owslib/coverage/wcs110.py (added)
- OWSLib/trunk/owslib/coverage/wcsBase.py (added)
- OWSLib/trunk/owslib/coverage/wcsdecoder.py (added)
- OWSLib/trunk/owslib/interfaces.py (modified) (3 diffs)
- OWSLib/trunk/owslib/wcs.py (added)
- OWSLib/trunk/owslib/wfs.py (modified) (9 diffs)
- OWSLib/trunk/owslib/wms.py (modified) (17 diffs)
- OWSLib/trunk/tests/JPLCapabilities.txt (deleted)
- OWSLib/trunk/tests/JPLCapabilities.xml (deleted)
- OWSLib/trunk/tests/JPLMap.txt (deleted)
- OWSLib/trunk/tests/MapServerWFSCapabilities.txt (deleted)
- OWSLib/trunk/tests/MapServerWFSFeature.txt (deleted)
- OWSLib/trunk/tests/TelaCapabilities.txt (deleted)
- OWSLib/trunk/tests/wcs_newiface.txt (added)
- OWSLib/trunk/tests/wcs_rectifiedgrid.txt (copied) (copied from OWSLib/branches/wcstemp/tests/wcs_rectifiedgrid.txt)
- OWSLib/trunk/tests/wcs.txt (deleted)
- OWSLib/trunk/tests/wfs_MapServerWFSCapabilities.txt (copied) (copied from OWSLib/branches/wcstemp/tests/wfs_MapServerWFSCapabilities.txt)
- OWSLib/trunk/tests/wfs_MapServerWFSFeature.txt (copied) (copied from OWSLib/branches/wcstemp/tests/wfs_MapServerWFSFeature.txt)
- OWSLib/trunk/tests/wms_JPLCapabilities.txt (copied) (copied from OWSLib/branches/wcstemp/tests/wms_JPLCapabilities.txt) (1 diff)
- OWSLib/trunk/tests/wms_TelaCapabilities.txt (copied) (copied from OWSLib/branches/wcstemp/tests/wms_TelaCapabilities.txt)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
OWSLib/trunk/owslib/interfaces.py
r954 r1095 1 # Do not import zope.interfaces 1 2 # Follows the 4 aspects of service metadata 3 4 class IServiceIdentificationMetadata: 5 """OO-interface to service identification metadata. 6 """ 7 8 type = property("""Service name (string): "WMS", "WFS", or "WCS".""") 9 version = property("""Version of service protocol (string).""") 10 title = property("""Human-targeted title of service (string).""") 11 abstract = property("""Text describing the service (string).""") 12 keywords = property("""Keyword list (list).""") 13 accessconstraints = property("""Explanation of access constraints associated with service (string).""") 14 fees = property("""Explanation of fees associated with service (string).""") 15 16 17 class IServiceProviderMetadata: 18 """OO-interface to service provider metadata. 19 """ 20 21 name = property("""Provider's name (string).""") 22 url = property("""URL for provider's web site (string).""") 23 contact = property("""How to contact the service provider (string).""") 2 24 3 25 4 class IService: 26 class IServiceOperations: 27 """OO-interface to service operations metadata. 28 """ 29 30 operations = property("""List of operation descriptors (list). These must implement IOperationMetadata (below).""") 31 exceptions = property("""List of exception formats (list).""") 32 33 34 class IServiceContents: 35 """OO-interface to service contents metadata. 36 """ 37 38 contents = property("""List of content descriptors (list). These must implement IServiceContent (below).""") 39 40 41 # IServiceMetadata aggregates the 4 aspects above 42 43 class IServiceMetadata(IServiceOperations, IServiceContents): 44 """OWS Metadata. 45 46 operations and contents properties are inherited. 47 """ 48 49 identification = property("""Object that implements IServiceIdentificationMetadata.""") 50 provider = property("""Object that implements IServiceProviderMetadata.""") 51 52 53 # A Service has an online resource URL as well as metadata collections 54 55 class IService(IServiceMetadata): 5 56 """The OGC Web Service interface. 6 57 """ 7 58 8 59 url = property("""Online resource URL (string)""") 9 # XXX: here or in capabilities?10 version = property("""Protocol version (string)""")11 capabilities = property("""Implementation of IServiceMetadata (object)""")12 60 61 62 # 3 specific service types are described below: WMS, WFS, and WCS 13 63 14 64 class IWebMapService(IService): … … 48 98 pass 49 99 50 51 # Follows the 4 aspects of service metadata52 53 class IServiceIdentificationMetadata:54 """OO-interface to service identification metadata.55 """56 57 service = property("""Service name (string): "WMS", "WFS", or "WCS".""")58 # XXX: here or in service root?59 version = property("""Version of service protocol (string).""")60 title = property("""Human-targeted title of service (string).""")61 abstract = property("""Text describing the service (string).""")62 keywords = property("""Keyword list (list).""")63 rights = property("""Explanation of rights associated with service (string).""")64 65 66 class IServiceProviderMetadata:67 """OO-interface to service provider metadata.68 """69 70 provider = property("""Provider's name (string).""")71 url = property("""URL for provider's web site (string).""")72 contact = property("""How to contact the service provider (string).""")73 74 75 class IServiceOperationsMetadata:76 """OO-interface to service operations metadata.77 """78 79 operations = property("""List of operation descriptors (list). These must implement IOperationMetadata (below).""")80 exceptions = property("""List of exception formats (list).""")81 82 83 class IServiceContentsMetadata:84 """OO-interface to service contents metadata.85 """86 87 contents = property("""List of content descriptors (list). These must implement IServiceContent (below).""")88 89 90 # IServiceMetadata aggregates the 4 aspects above91 92 class IServiceMetadata(93 IServiceIdentificationMetadata, IServiceProviderMetadata,94 IServiceOperationsMetadata, IServiceContentsMetadata95 ):96 """OWS Metadata.97 """98 100 99 101 … … 145 147 email : string 146 148 """ 147 148 149 OWSLib/trunk/owslib/wfs.py
r660 r1095 47 47 """ 48 48 49 def __getitem__(self,name): 50 ''' check contents dictionary to allow dict like access to service layers''' 51 if name in self.__getattribute__('contents').keys(): 52 return self.__getattribute__('contents')[name] 53 else: 54 raise KeyError, "No content named %s" % name 55 56 49 57 def __init__(self, url, version='1.0.0', xml=None): 50 58 """Initialize.""" … … 52 60 self.version = version 53 61 self._capabilities = None 62 reader = WFSCapabilitiesReader(self.version) 54 63 if xml: 55 reader = WFSCapabilitiesReader(self.version) 56 self._capabilities = ServiceMetadata(reader.readString(xml)) 57 58 def _getcapproperty(self): 59 if not self._capabilities: 60 reader = WFSCapabilitiesReader(self.version) 61 self._capabilities = ServiceMetadata(reader.read(self.url)) 62 return self._capabilities 63 capabilities = property(_getcapproperty, None) 64 64 self._capabilities = reader.readString(xml) 65 else: 66 self._capabilities = reader.read(self.url) 67 self._buildMetadata() 68 69 def _buildMetadata(self): 70 '''set up capabilities metadata objects: ''' 71 72 #serviceIdentification metadata 73 serviceelem=self._capabilities.find(nspath('Service')) 74 self.identification=ServiceIdentification(serviceelem, self.version) 75 76 #serviceProvider metadata 77 self.provider=ServiceProvider(serviceelem) 78 79 #serviceOperations metadata 80 self.operations=[] 81 for elem in self._capabilities.find(nspath('Capability/Request')).getchildren(): 82 self.operations.append(OperationMetadata(elem)) 83 84 #serviceContents metadata: our assumption is that services use a top-level 85 #layer as a metadata organizer, nothing more. 86 87 self.contents={} 88 featuretypelist=self._capabilities.find(nspath('FeatureTypeList')) 89 features = self._capabilities.findall(nspath('FeatureTypeList/FeatureType')) 90 for feature in features: 91 cm=ContentMetadata(feature, featuretypelist) 92 self.contents[cm.id]=cm 93 94 #exceptions 95 self.exceptions = [f.text for f \ 96 in self._capabilities.findall('Capability/Exception/Format')] 97 65 98 def getcapabilities(self): 66 99 """Request and return capabilities document from the WFS as a 67 file-like object.""" 100 file-like object. 101 NOTE: this is effectively redundant now""" 68 102 reader = WFSCapabilitiesReader(self.version) 69 103 return urlopen(reader.capabilities_url(self.url)) 104 105 def items(self): 106 '''supports dict-like items() access''' 107 items=[] 108 for item in self.contents: 109 items.append((item,self.contents[item])) 110 return items 70 111 71 112 def getfeature(self, typename=None, filter=None, bbox=None, featureid=None, … … 99 140 3) featureid (direct access to known features) 100 141 """ 101 md = self.capabilities 102 base_url = md.getOperationByName('{http://www.opengis.net/wfs}GetFeature').methods[method]['url'] 142 base_url = self.getOperationByName('{http://www.opengis.net/wfs}GetFeature').methods[method]['url'] 103 143 request = {'service': 'WFS', 'version': self.version, 'request': 'GetFeature'} 104 144 … … 149 189 return u 150 190 151 152 class ServiceMetadata(object):153 """Abstraction for WFS metadata.154 155 Implements IServiceMetadata.156 """157 158 def __init__(self, infoset):159 """Initialize from an element tree."""160 self._root = infoset.getRoot()161 # properties162 self.service = self._root.find(nspath('Service/Name')).text163 self.title = self._root.find(nspath('Service/Title')).text164 self.abstract = self._root.find(nspath('Service/Abstract')).text165 self.link = self._root.find(nspath('Service/OnlineResource')).text166 167 # operations []168 self.operations = []169 for elem in self._root.findall(nspath('Capability/Request/*')):170 self.operations.append(OperationMetadata(elem))171 172 # contents: our assumption is that services use a top-level layer173 # as a metadata organizer, nothing more.174 self.contents = []175 top = self._root.find(nspath('FeatureTypeList'))176 for elem in self._root.findall(nspath('FeatureTypeList/FeatureType')):177 self.contents.append(ContentMetadata(elem, top))178 179 # keywords180 self.keywords = []181 182 self.provider = ContactMetadata(self._root.find('Service/ContactInformation'))183 184 def getContentByName(self, name):185 """Return a named content item."""186 for item in self.contents:187 if item.name == name:188 return item189 raise KeyError, "No content named %s" % name190 191 191 def getOperationByName(self, name): 192 192 """Return a named content item.""" … … 196 196 raise KeyError, "No operation named %s" % name 197 197 198 class ServiceIdentification(object): 199 ''' Implements IServiceIdentificationMetadata ''' 200 201 def __init__(self, infoset, version): 202 self._root=infoset 203 self.type = self._root.find(nspath('Name')).text 204 self.version = version 205 self.title = self._root.find(nspath('Title')).text 206 abstract = self._root.find(nspath('Abstract')) 207 if abstract is not None: 208 self.abstract = abstract.text 209 else: 210 self.abstract = None 211 self.keywords = [f.text for f in self._root.findall(nspath('Keywords'))] 212 accessconstraints=self._root.find(nspath('AccessConstraints')) 213 if accessconstraints is not None: 214 self.accessconstraints = accessconstraints.text 215 else: 216 accessconstraints=None 217 fees = self._root.find(nspath('Fees')) 218 if fees is not None: 219 self.fees = fees.text 220 221 class ServiceProvider(object): 222 ''' Implements IServiceProviderMetatdata ''' 223 def __init__(self, infoset): 224 self._root=infoset 225 name=self._root.find(nspath('ContactInformation/ContactPersonPrimary/ContactOrganization')) 226 if name is not None: 227 self.name=name.text 228 else: 229 self.name=None 230 self.url=self._root.find(nspath('OnlineResource')).attrib.get('{http://www.w3.org/1999/xlink}href', '') 231 if self.url == '': 232 self.url=self._root.find(nspath('OnlineResource')).text 233 #contact metadata 234 contact = self._root.find('ContactInformation') 235 ## sometimes there is a contact block that is empty, so make 236 ## sure there are children to parse 237 if contact is not None and contact.getchildren(): 238 self.contact = ContactMetadata(contact) 239 else: 240 self.contact = None 241 242 class ContactMetadata: 243 """Abstraction for contact details advertised in GetCapabilities. 244 Not fully tested due to lack of Contact info in test capabilities doc. 245 """ 246 def __init__(self, elem): 247 name = elem.find(nspath('ContactPersonPrimary/ContactPerson')) 248 if name is not None: 249 self.name=name.text 250 else: 251 self.name=None 252 email = elem.find(nspath('ContactElectronicMailAddress')) 253 if email is not None: 254 self.email=email.text 255 else: 256 self.email=None 257 258 self.address = self.city = self.region = None 259 self.postcode = self.country = None 260 261 address = elem.find(nspath('ContactAddress')) 262 if address is not None: 263 street = address.find(nspath('Address')) 264 if street is not None: self.address = street.text 265 266 city = address.find(nspath('City')) 267 if city is not None: self.city = city.text 268 269 region = address.find(nspath('StateOrProvince')) 270 if region is not None: self.region = region.text 271 272 postcode = address.find(nspath('PostCode')) 273 if postcode is not None: self.postcode = postcode.text 274 275 country = address.find(nspath('Country')) 276 if country is not None: self.country = country.text 277 278 organization = elem.find(nspath('ContactPersonPrimary/ContactOrganization')) 279 if organization is not None: self.organization = organization.text 280 else:self.organization = None 281 282 position = elem.find(nspath('ContactPosition')) 283 if position is not None: self.position = position.text 284 else: self.position = None 285 198 286 199 287 class ContentMetadata: … … 205 293 def __init__(self, elem, parent): 206 294 """.""" 207 self. name= elem.find(nspath('Name')).text295 self.id = elem.find(nspath('Name')).text 208 296 self.title = elem.find(nspath('Title')).text 209 297 # bboxes … … 249 337 250 338 251 class ContactMetadata:252 """Abstraction for contact details advertised in GetCapabilities.253 """254 # TODO: refactor with class from wfs255 256 def __init__(self, elem):257 self.name = None258 self.email = None259 260 if elem:261 self.name = elem.find('ContactPersonPrimary/ContactPerson').text262 self.organization = elem.find('ContactPersonPrimary/ContactOrganization').text263 address = elem.find('ContactAddress')264 if address is not None:265 try:266 self.address = address.find('Address').text267 self.city = address.find('City').text268 self.region = address.find('StateOrProvince').text269 self.postcode = address.find('Postcode').text270 self.country = address.find('Country').text271 except: pass272 self.email = elem.find('ContactElectronicMailAddress').text273 274 275 class WFSCapabilitiesInfoset(object):276 """High-level container for WFS Capabilities based on lxml.etree277 """278 279 def __init__(self, infoset):280 """Initialize"""281 self._infoset = infoset282 283 #284 # XML Node accessors285 #286 287 def getRoot(self):288 """289 Returns the root node of the capabilities document.290 """291 return self._infoset292 293 def getServiceNode(self):294 """295 Returns the <Service> node of the capabilities document.296 """297 return self.getRoot().find(nspath('Service'))298 299 def getCapabilitiesNode(self):300 """301 Returns the <Capability> node of the capabilities document.302 """303 return self.getRoot().find(nspath('Capability'))304 305 def getFeatureTypeNode(self):306 """307 Returns the <FeatureTypeList> node of the capabilities document.308 """309 return self.getRoot().find(nspath('FeatureTypeList'))310 311 def getFilterNode(self):312 """313 Returns the <Filter_Capabilities> node of the capabilities document.314 """315 return self.getRoot().find(nspath('Filter_Capabilities'))316 317 #318 # Info accessors319 #320 321 def getServiceInfo(self):322 """323 Returns the WFS Service information packed in a dictionary.324 """325 service = self.getServiceNode()326 info = {}327 for tag in ('Name', 'Title', 'Abstract', 'Keyword', 'OnlineResource',328 'Fees', 'AccessConstraints'):329 info[tag.lower()] = service.findtext(nspath(tag))330 return info331 332 def getCapabilityInfo(self):333 """334 Returns the WFS Capability information packed in a dictionary.335 """336 # Simplify the resource URLs, favoring GET over POST.337 # Assume GML2.338 capabilities = self.getCapabilitiesNode()339 info = {}340 341 for key, path_id in [('capabilities', 'GetCapabilities'),342 ('description', 'DescribeFeatureType'),343 ('features', 'GetFeature')]:344 get_path = nspath('Request/%s/DCPType/HTTP/Get' % path_id)345 post_path = nspath('Request/%s/DCPType/HTTP/Post' % path_id)346 347 node = capabilities.find(get_path) or capabilities.find(post_path)348 info[key] = node.get('onlineResource', None)349 return info350 351 def getFeatureTypeInfo(self):352 """353 Returns the WFS Feature type information as a list of dictionaries.354 """355 # Assume XMLSchema is used as the schema description language.356 info = []357 for featuretype in self.getFeatureTypeNode().getiterator(nspath('FeatureType')):358 entry = {}359 # Loop over simple text nodes360 for tag in ('Name', 'Title', 'Abstract', 'SRS'):361 entry[tag.lower()] = featuretype.findtext(nspath(tag))362 363 # LatLongBoundingBox364 entry['latlongboundingbox'] = []365 for latlong in featuretype.findall(nspath('LatLongBoundingBox')):366 entry['latlongboundingbox'].append('%s,%s,%s,%s' % (latlong.get('minx'),367 latlong.get('miny'),368 latlong.get('maxx'),369 latlong.get('maxy')))370 371 # MetadataURL372 entry['metadataurl'] = []373 for metadataurl in featuretype.findall(nspath('MetadataURL')):374 entry['metadataurl'].append(metadataurl.text)375 376 info.append(entry)377 return info378 379 380 339 class WFSCapabilitiesReader(object): 381 340 """Read and parse capabilities document into a lxml.etree infoset … … 417 376 request = self.capabilities_url(url) 418 377 u = urlopen(request) 419 return WFSCapabilitiesInfoset(etree.fromstring(u.read()))378 return etree.fromstring(u.read()) 420 379 421 380 def readString(self, st): … … 427 386 if not isinstance(st, str): 428 387 raise ValueError("String must be of type string, not %s" % type(st)) 429 return WFSCapabilitiesInfoset(etree.fromstring(st))430 388 return etree.fromstring(st) 389 OWSLib/trunk/owslib/wms.py
r1092 r1095 41 41 """ 42 42 43 def __getitem__(self,name): 44 ''' check contents dictionary to allow dict like access to service layers''' 45 if name in self.__getattribute__('contents').keys(): 46 return self.__getattribute__('contents')[name] 47 else: 48 raise KeyError, "No content named %s" % name 49 50 43 51 def __init__(self, url, version='1.1.1', xml=None, 44 username=None, password=None45 ):52 username=None, password=None 53 ): 46 54 """Initialize.""" 47 55 self.url = url … … 51 59 self._capabilities = None 52 60 self._open = urlopen 53 61 54 62 if self.username and self.password: 55 63 # Provide login information in order to use the WMS server … … 61 69 opener = build_opener(auth_handler) 62 70 self._open = opener.open 63 64 # initialize from saved capability document65 elif xml:66 71 reader = WMSCapabilitiesReader( 67 72 self.version, url=self.url, un=self.username, pw=self.password 68 73 ) 69 self._capabilities = ServiceMetadata(reader.readString(xml)) 74 self._capabilities = reader.readString(self.url) 75 else: 76 reader = WMSCapabilitiesReader(self.version) 77 if xml: 78 #read from stored xml 79 self._capabilities = reader.readString(xml) 80 else: 81 #read from non-password protected server 82 self._capabilities = reader.read(self.url) 83 84 85 #build metadata objects 86 self._buildMetadata() 70 87 71 88 def _getcapproperty(self): … … 77 94 return self._capabilities 78 95 capabilities = property(_getcapproperty, None) 96 97 def _buildMetadata(self): 98 ''' set up capabilities metadata objects ''' 99 100 #serviceIdentification metadata 101 serviceelem=self._capabilities.find('Service/') 102 self.identification=ServiceIdentification(serviceelem, self.version) 103 104 #serviceProvider metadata 105 self.provider=ServiceProvider(serviceelem) 79 106 107 #serviceOperations metadata 108 self.operations=[] 109 for elem in self._capabilities.find('Capability/Request').getchildren(): 110 self.operations.append(OperationMetadata(elem)) 111 112 #serviceContents metadata: our assumption is that services use a top-level 113 #layer as a metadata organizer, nothing more. 114 self.contents={} 115 caps = self._capabilities.find('Capability') 116 for elem in caps.findall('Layer'): 117 cm=ContentMetadata(elem) 118 self.contents[cm.id]=cm 119 for subelem in elem.findall('Layer'): 120 subcm=ContentMetadata(subelem, cm) 121 self.contents[subcm.id]=subcm 122 123 #exceptions 124 self.exceptions = [f.text for f \ 125 in self._capabilities.findall('Capability/Exception/Format')] 126 127 128 def items(self): 129 '''supports dict-like items() access''' 130 items=[] 131 for item in self.contents: 132 items.append((item,self.contents[item])) 133 return items 134 80 135 def getcapabilities(self): 81 136 """Request and return capabilities document from the WMS as a 82 file-like object.""" 137 file-like object. 138 NOTE: this is effectively redundant now""" 83 139 84 140 reader = WMSCapabilitiesReader( … … 139 195 140 196 """ 141 md = self.capabilities 142 base_url = md.getOperationByName('GetMap').methods[method]['url'] 197 base_url = self.getOperationByName('GetMap').methods[method]['url'] 143 198 request = {'version': self.version, 'request': 'GetMap'} 144 199 … … 182 237 def getfeatureinfo(self): 183 238 raise NotImplementedError 184 185 186 class ServiceMetadata(object): 187 """Abstraction for WMS metadata. 188 189 Implements IServiceMetadata. 190 """ 191 192 def __init__(self, infoset): 193 """Initialize from an element tree.""" 194 self._root = infoset.getroot() 195 # properties 196 self.service = self._root.find('Service/Name').text 197 self.title = self._root.find('Service/Title').text 198 abstract = self._root.find('Service/Abstract') 239 240 def getOperationByName(self, name): 241 """Return a named content item.""" 242 for item in self.operations: 243 if item.name == name: 244 return item 245 raise KeyError, "No operation named %s" % name 246 247 class ServiceIdentification(object): 248 ''' Implements IServiceIdentificationMetadata ''' 249 250 def __init__(self, infoset, version): 251 self._root=infoset 252 self.type = self._root.find('Name').text 253 self.version = version 254 self.title = self._root.find('Title').text 255 abstract = self._root.find('Abstract') 199 256 if abstract is not None: 200 self.abstract = self._root.find('Service/Abstract').text257 self.abstract = abstract.text 201 258 else: 202 259 self.abstract = None 203 self.link = self._root.find('Service/OnlineResource').attrib.get('{http://www.w3.org/1999/xlink}href', '') 204 205 # operations [] 206 self.operations = [] 207 for elem in self._root.findall('Capability/Request/*'): 208 self.operations.append(OperationMetadata(elem)) 209 210 # exceptions 211 self.exceptions = [f.text for f \ 212 in self._root.findall('Capability/Exception/Format')] 213 214 # contents: our assumption is that services use a top-level layer 215 # as a metadata organizer, nothing more. 216 caps = self._root.find('Capability') 217 self.layers = [] 218 for elem in caps.findall('Layer'): 219 self.layers.append(ContentMetadata(elem)) 220 221 # keywords 222 self.keywords = [f.text for f in self._root.findall('Service/KeywordList/Keyword')] 223 224 # contact person 225 contact = self._root.find('Service/ContactInformation') 260 self.keywords = [f.text for f in self._root.findall('KeywordList/Keyword')] 261 accessconstraints=self._root.find('AccessConstraints') 262 if accessconstraints is not None: 263 self.accessconstraints = accessconstraints.text 264 fees = self._root.find('Fees') 265 if fees is not None: 266 self.fees = fees.text 267 268 class ServiceProvider(object): 269 ''' Implements IServiceProviderMetatdata ''' 270 def __init__(self, infoset): 271 self._root=infoset 272 name=self._root.find('ContactInformation/ContactPersonPrimary/ContactOrganization') 273 if name is not None: 274 self.name=name.text 275 else: 276 self.name=None 277 self.url=self._root.find('OnlineResource').attrib.get('{http://www.w3.org/1999/xlink}href', '') 278 #contact metadata 279 contact = self._root.find('ContactInformation') 226 280 ## sometimes there is a contact block that is empty, so make 227 281 ## sure there are children to parse 228 if contact is not None and contact.getchildren() :229 self. provider= ContactMetadata(contact)282 if contact is not None and contact.getchildren() != []: 283 self.contact = ContactMetadata(contact) 230 284 else: 231 self.provider = None 232 233 @property 234 def contents(self): 235 """backwards compatible flat list of contents""" 236 return list(self._rcontents(self)) 237 def _rcontents(self, layer): 238 for l in layer.layers: 239 yield l 240 for l in self._rcontents(l): 241 yield l 285 self.contact = None 242 286 243 287 def getContentByName(self, name): … … 255 299 raise KeyError, "No operation named %s" % name 256 300 257 258 301 class ContentMetadata: 259 302 """ 260 Abstraction for WMS metadata.261 262 Implements I Metadata.303 Abstraction for WMS layer metadata. 304 305 Implements IContentMetadata. 263 306 """ 264 307 def __init__(self, elem, parent=None): … … 272 315 else: 273 316 setattr(self, key.lower(), None) 274 317 self.id=self.name #conform to new interface 275 318 # bboxes 276 319 b = elem.find('BoundingBox') 277 if b is not None: 320 self.boundingBox = None 321 if b is not None: 278 322 self.boundingBox = ( 279 323 float(b.attrib['minx']), … … 284 328 ) 285 329 elif self.parent: 330 if hasattr(self.parent, 'boundingBox'): 286 331 self.boundingBox = self.parent.boundingBox 287 else: 288 self.boundingBox = None 289 332 290 333 b = elem.find('LatLonBoundingBox') 291 334 if b is not None: … … 300 343 else: 301 344 self.boundingBoxWGS84 = None 302 303 345 # crs options 304 346 self.crsOptions = [] … … 311 353 self.crsOptions.append(srs) 312 354 elif self.parent: 313 self.crsOptions = self.parent.crsOptions355 self.crsOptions = self.parent.crsOptions 314 356 else: 315 357 raise ValueError('%s no SRS available!?' % (elem,)) … … 341 383 342 384 class OperationMetadata: 343 """Abstraction for WMS metadata.344 345 Implements I Metadata.385 """Abstraction for WMS OperationMetadata. 386 387 Implements IOperationMetadata. 346 388 """ 347 389 def __init__(self, elem): … … 360 402 """ 361 403 def __init__(self, elem): 362 self.name = elem.find('ContactPersonPrimary/ContactPerson').text 363 self.email = elem.find('ContactElectronicMailAddress').text 364 404 name = elem.find('ContactPersonPrimary/ContactPerson') 405 if name is not None: 406 self.name=name.text 407 else: 408 self.name=None 409 email = elem.find('ContactElectronicMailAddress') 410 if email is not None: 411 self.email=email.text 412 else: 413 self.email=None 365 414 self.address = self.city = self.region = None 366 415 self.postcode = self.country = None … … 392 441 393 442 394 class WMSCapabilitiesInfoset:395 """High-level container for WMS Capabilities based on lxml.etree396 """397 398 def __init__(self, infoset):399 """Initialize"""400 self._infoset = infoset401 402 def getroot(self):403 return self._infoset404 405 def getservice(self):406 return self._infoset.find('Service')407 408 def servicename(self):409 e_service = self.getservice()410 return e_service.find('Name').text411 412 def servicetitle(self):413 e_service = self.getservice()414 return e_service.find('Title').text415 416 def getmapformats(self):417 e_getmap = self._infoset.find('Capability/Request/GetMap')418 formats = ()419 for f in e_getmap.getiterator('Format'):420 formats = formats + (f.text,)421 return formats422 423 def layersrs(self):424 e_layer = self._infoset.find('Capability/Layer')425 srs = ()426 for s in e_layer.getiterator('SRS'):427 srs = srs + (s.text,)428 return srs429 430 def layernames(self):431 names = ()432 for n in self._infoset.findall('Capability/Layer/Layer/Name'):433 names = names + (n.text,)434 return names435 436 def layertitles(self):437 titles = ()438 for n in self._infoset.findall('Capability/Layer/Layer/Title'):439 titles = titles + (n.text,)440 return titles441 442 def getLayerInfo(self):443 info = {}444 for layer in self._infoset.findall('Capability/Layer/Layer'):445 if layer.findall('Title'):446 info[layer.findall('Title')[0].text] = layer.findall('Style')447 return info448 449 def bounds(self, name):450 """Returns the bounds of the specified layer as a tuple.451 452 Like (minx, miny, maxx, maxy, epsg)453 """454 top_layer = self._infoset.find('Capability/Layer')455 for layer in top_layer.findall('Layer'):456 n = layer.find('Name')457 if n.text == name:458 # First check for a BoundingBox459 b = layer.find('BoundingBox')460 if b is not None:461 return (float(b.attrib['minx']), float(b.attrib['miny']),462 float(b.attrib['maxx']), float(b.attrib['maxy']),463 b.attrib['SRS'])464 else:465 b = layer.find('LatLonBoundingBox')466 #import pdb; pdb.set_trace()467 if b is not None:468 return (float(b.attrib['minx']),float(b.attrib['miny']),469 float(b.attrib['maxx']),float(b.attrib['maxy']),470 'EPSG:4326')471 # Look at the top level layer472 b = top_layer.find('BoundingBox')473 if b is not None:474 return (float(b.attrib['minx']), float(b.attrib['miny']),475 float(b.attrib['maxx']), float(b.attrib['maxy']),476 b.attrib['SRS'])477 else:478 b = top_layer.find('LatLonBoundingBox')479 if b is not None:480 return (float(b.attrib['minx']),float(b.attrib['miny']),481 float(b.attrib['maxx']),float(b.attrib['maxy']),482 'EPSG:4326')483 # If we haven't returned a bbox, raise an exception484 raise CapabilitiesError, "No bounding box specified for layer %s" % name485 486 443 487 444 class WMSCapabilitiesReader: … … 529 486 def read(self, service_url): 530 487 """Get and parse a WMS capabilities document, returning an 531 instance of WMSCapabilitiesInfoset488 elementtree instance 532 489 533 490 service_url is the base url, to which is appended the service, … … 536 493 request = self.capabilities_url(service_url) 537 494 u = self._open(request) 538 return WMSCapabilitiesInfoset(etree.fromstring(u.read()))495 return etree.fromstring(u.read()) 539 496 540 497 def readString(self, st): 541 """Parse a WMS capabilities document, returning an 542 instance of WMSCapabilitiesInfoset 498 """Parse a WMS capabilities document, returning an elementtree instance 543 499 544 500 string should be an XML capabilities document … … 546 502 if not isinstance(st, str): 547 503 raise ValueError("String must be of type string, not %s" % type(st)) 548 return WMSCapabilitiesInfoset(etree.fromstring(st))504 return etree.fromstring(st) 549 505 550 506
