[GRASS-SVN] r54346 - grass-addons/grass7/raster/r.in.wms2
svn_grass at osgeo.org
svn_grass at osgeo.org
Tue Dec 18 16:53:53 PST 2012
Author: turek
Date: 2012-12-18 16:53:53 -0800 (Tue, 18 Dec 2012)
New Revision: 54346
Added:
grass-addons/grass7/raster/r.in.wms2/wms_cap_parsers.py
Modified:
grass-addons/grass7/raster/r.in.wms2/r.in.wms2.html
grass-addons/grass7/raster/r.in.wms2/r.in.wms2.py
grass-addons/grass7/raster/r.in.wms2/wms_base.py
grass-addons/grass7/raster/r.in.wms2/wms_drv.py
grass-addons/grass7/raster/r.in.wms2/wms_gdal_drv.py
Log:
r.in.wms2: Prepared for WMS integration into wxGUI.
Modified: grass-addons/grass7/raster/r.in.wms2/r.in.wms2.html
===================================================================
--- grass-addons/grass7/raster/r.in.wms2/r.in.wms2.html 2012-12-18 21:49:23 UTC (rev 54345)
+++ grass-addons/grass7/raster/r.in.wms2/r.in.wms2.html 2012-12-19 00:53:53 UTC (rev 54346)
@@ -18,7 +18,7 @@
<a href="http://wms.jpl.nasa.gov/wms.cgi?request=GetCapabilities">example
capabilities request to NASA's OnEarth server</a>.
-<h3>>NASA OnEarth Tiled WMS</h3>
+<h3>NASA OnEarth Tiled WMS</h3>
Into parameter <b>layers</b> insert name of <b>TiledGroup</b> from Tile Service file.
<br>
Modified: grass-addons/grass7/raster/r.in.wms2/r.in.wms2.py
===================================================================
--- grass-addons/grass7/raster/r.in.wms2/r.in.wms2.py 2012-12-18 21:49:23 UTC (rev 54345)
+++ grass-addons/grass7/raster/r.in.wms2/r.in.wms2.py 2012-12-19 00:53:53 UTC (rev 54346)
@@ -153,14 +153,49 @@
#% answer:WMS_GRASS
#%end
+#%option G_OPT_F_INPUT
+#% key: cfile
+#% required: no
+#% gisprompt: old,file,bin_input
+#% description: Capabilities file
+#%end
+#%option G_OPT_F_OUTPUT
+#% key: csfile
+#% required: no
+#% gisprompt: old,file,bin_input
+#% description: File where capabilities will be saved (only with 'c' flag).
+#%end
+
import os
import sys
sys.path.insert(1, os.path.join(os.path.dirname(sys.path[0]), 'etc', 'r.in.wms2'))
import grass.script as grass
+from wms_base import GRASSImporter
+
+def GetRegionParams(opt_region):
+
+ # set region
+ if opt_region:
+ if not grass.find_file(name = opt_region, element = 'windows', mapset = '.' )['name']:
+ grass.fatal(_("Region <%s> not found") % opt_region)
+
+ if opt_region:
+ s = grass.read_command('g.region',
+ quiet = True,
+ flags = 'ug',
+ region = opt_region)
+ region_params = grass.parse_key_val(s, val_type = float)
+ else:
+ region_params = grass.region()
+
+ return region_params
+
def main():
+
+
if 'GRASS' in options['driver']:
grass.debug("Using GRASS driver")
from wms_drv import WMSDrv
@@ -173,10 +208,14 @@
if flags['c']:
wms.GetCapabilities(options)
else:
- wms.GetMap(options, flags)
-
+ options['region'] = GetRegionParams(options['region'])
+ importer = GRASSImporter(options['output'])
+ fetched_map = wms.GetMap(options, flags)
+ importer.ImportMapIntoGRASS(fetched_map)
+
return 0
+
if __name__ == "__main__":
options, flags = grass.parser()
sys.exit(main())
Modified: grass-addons/grass7/raster/r.in.wms2/wms_base.py
===================================================================
--- grass-addons/grass7/raster/r.in.wms2/wms_base.py 2012-12-18 21:49:23 UTC (rev 54345)
+++ grass-addons/grass7/raster/r.in.wms2/wms_base.py 2012-12-19 00:53:53 UTC (rev 54346)
@@ -1,3 +1,21 @@
+"""!
+ at brief Preparation of parameters for drivers, which download it, and managing downloaded data.
+
+List of classes:
+ - wms_base::WMSBase
+ - wms_base::GRASSImporter
+ - wms_base::WMSDriversInfo
+
+(C) 2012 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at TODO use username and password for getting capabilities
+
+ at author Stepan Turek <stepan.turek seznam.cz> (Mentor: Martin Landa)
+"""
+
import os
from math import ceil
@@ -10,54 +28,21 @@
def __init__(self):
# these variables are information for destructor
self.temp_files_to_cleanup = []
- self.cleanup_mask = False
- self.cleanup_layers = False
self.params = {}
self.tile_size = {'bbox' : None}
self.temp_map = None
-
+ self.temp_warpmap = None
+
def __del__(self):
- # removes temporary mask, used for import transparent or warped temp_map
- if self.cleanup_mask:
- # clear temporary mask, which was set by module
- if grass.run_command('r.mask',
- quiet = True,
- flags = 'r') != 0:
- grass.fatal(_('%s failed') % 'r.mask')
- # restore original mask, if exists
- if grass.find_file(self.params['output'] + self.original_mask_suffix, element = 'cell', mapset = '.' )['name']:
- if grass.run_command('g.copy',
- quiet = True,
- rast = self.params['output'] + self.original_mask_suffix + ',MASK') != 0:
- grass.fatal(_('%s failed') % 'g.copy')
-
# tries to remove temporary files, all files should be
# removed before, implemented just in case of unexpected
# stop of module
for temp_file in self.temp_files_to_cleanup:
grass.try_remove(temp_file)
- # remove temporary created rasters
- if self.cleanup_layers:
- maps = []
- for suffix in ('.red', '.green', '.blue', '.alpha', self.original_mask_suffix):
- rast = self.params['output'] + suffix
- if grass.find_file(rast, element = 'cell', mapset = '.')['file']:
- maps.append(rast)
-
- if maps:
- grass.run_command('g.remove',
- quiet = True,
- flags = 'f',
- rast = ','.join(maps))
-
- # deletes environmental variable which overrides region
- if 'GRASS_REGION' in os.environ.keys():
- os.environ.pop('GRASS_REGION')
-
def _debug(self, fn, msg):
grass.debug("%s.%s: %s" %
(self.__class__.__name__, fn, msg))
@@ -66,62 +51,52 @@
self._debug("_initialize_parameters", "started")
# initialization of module parameters (options, flags)
-
self.params['driver'] = options['driver']
+ drv_info = WMSDriversInfo()
+ driver_props = drv_info.GetDrvProperties(options['driver'])
+ self._checkIgnoeredParams(options, flags, driver_props)
+
+ self.params['cfile'] = options['cfile'].strip()
+
+ for key in ['url', 'layers', 'styles', 'method']:
+ self.params[key] = options[key].strip()
+
+ self.params['wms_version'] = options['wms_version']
+ if self.params['wms_version'] == "1.3.0":
+ self.params['proj_name'] = "CRS"
+ else:
+ self.params['proj_name'] = "SRS"
+
self.flags = flags
- if self.flags['o'] and 'WMS' not in self.params['driver']:
- grass.warning(_("Flag '%s' is relevant only for WMS.") % 'o')
- elif self.flags['o']:
+ if self.flags['o']:
self.params['transparent'] = 'FALSE'
else:
self.params['transparent'] = 'TRUE'
- for key in ['url', 'layers', 'styles', 'output', 'method']:
- self.params[key] = options[key].strip()
-
- if self.params['styles'] != "" and 'OnEarth_GRASS' in self.params['driver']:
- grass.warning(_("Parameter '%s' is not relevant for %s driver.") % ('styles', 'OnEarth_GRASS'))
-
for key in ['password', 'username', 'urlparams']:
self.params[key] = options[key]
- if self.params[key] != "" and 'GRASS' not in self.params['driver']:
- grass.warning(_("Parameter '%s' is relevant only for %s drivers.") % (key, '*_GRASS'))
-
+
if (self.params ['password'] and self.params ['username'] == '') or \
(self.params ['password'] == '' and self.params ['username']):
grass.fatal(_("Please insert both %s and %s parameters or none of them." % ('password', 'username')))
self.params['bgcolor'] = options['bgcolor'].strip()
- if self.params['bgcolor'] != "" and 'WMS_GRASS' not in self.params['driver']:
- grass.warning(_("Parameter '%s' is relevant only for %s driver.") % ('bgcolor', 'WMS_GRASS'))
-
- self.params['wms_version'] = options['wms_version']
- if self.params['wms_version'] == "1.3.0":
- self.params['proj_name'] = "CRS"
- else:
- self.params['proj_name'] = "SRS"
-
- if options['format'] == "geotiff":
- self.params['format'] = "image/geotiff"
- elif options['format'] == "tiff":
- self.params['format'] = "image/tiff"
- elif options['format'] == "png":
- self.params['format'] = "image/png"
- elif options['format'] == "jpeg":
- self.params['format'] = "image/jpeg"
+
+ if options['format'] == "jpeg" and \
+ not 'format' in driver_props['ignored_params']:
if not flags['o'] and \
'WMS' in self.params['driver']:
grass.warning(_("JPEG format does not support transparency"))
- elif self.params['format'] == "gif":
- self.params['format'] = "image/gif"
- else:
+
+ self.params['format'] = drv_info.GetFormat(options['format'])
+ if not self.params['format']:
self.params['format'] = self.params['format']
#TODO: get srs from Tile Service file in OnEarth_GRASS driver
self.params['srs'] = int(options['srs'])
- if self.params['srs'] <= 0:
+ if self.params['srs'] <= 0 and not 'srs' in driver_props['ignored_params']:
grass.fatal(_("Invalid EPSG code %d") % self.params['srs'])
# read projection info
@@ -140,22 +115,9 @@
if not self.proj_srs or not self.proj_location:
grass.fatal(_("Unable to get projection info"))
-
- # set region
- self.params['region'] = options['region']
- if self.params['region']:
- if not grass.find_file(name = self.params['region'], element = 'windows', mapset = '.' )['name']:
- grass.fatal(_("Region <%s> not found") % self.params['region'])
-
- if self.params['region']:
- s = grass.read_command('g.region',
- quiet = True,
- flags = 'ug',
- region = self.params['region'])
- self.region = grass.parse_key_val(s, val_type = float)
- else:
- self.region = grass.region()
-
+
+ self.region = options['region']
+
min_tile_size = 100
maxcols = int(options['maxcols'])
if maxcols <= min_tile_size:
@@ -169,26 +131,38 @@
self.tile_size['cols'] = int(self.region['cols'] / ceil(self.region['cols'] / float(maxcols)))
self.tile_size['rows'] = int(self.region['rows'] / ceil(self.region['rows'] / float(maxrows)))
- # suffix for existing mask (during overriding will be saved
- # into raster named:self.params['output'] + this suffix)
- self.original_mask_suffix = "_temp_MASK"
-
- # check names of temporary rasters, which module may create
- maps = []
- for suffix in ('.red', '.green', '.blue', '.alpha', self.original_mask_suffix ):
- rast = self.params['output'] + suffix
- if grass.find_file(rast, element = 'cell', mapset = '.')['file']:
- maps.append(rast)
-
- if len(maps) != 0:
- grass.fatal(_("Please change output name, or change names of these rasters: %s, "
- "module needs to create this temporary maps during runing") % ",".join(maps))
-
# default format for GDAL library
self.gdal_drv_format = "GTiff"
self._debug("_initialize_parameters", "finished")
+ def _checkIgnoeredParams(self, options, flags, driver_props):
+ """!Write warnings for set parameters and flags, which chosen driver does not use."""
+
+ not_relevant_params = []
+ for i_param in driver_props['ignored_params']:
+
+ if options.has_key(i_param) and \
+ options[i_param] and \
+ i_param not in ['srs', 'wms_version', 'format']: # params with default value
+ not_relevant_params.append('<' + i_param + '>')
+
+ if len(not_relevant_params) > 0:
+ grass.warning(_("These parameter are ignored: %s\n\
+ %s driver does not support the parameters." %\
+ (','.join(not_relevant_params), options['driver'])))
+
+ not_relevant_flags = []
+ for i_flag in driver_props['ignored_flags']:
+
+ if flags[i_flag]:
+ not_relevant_flags.append('<' + i_flag + '>')
+
+ if len(not_relevant_flags) > 0:
+ grass.warning(_("These flags are ignored: %s\n\
+ %s driver does not support the flags." %\
+ (','.join(not_relevant_flags), options['driver'])))
+
def GetMap(self, options, flags):
"""!Download data from WMS server and import data
(using GDAL library) into GRASS as a raster map."""
@@ -202,7 +176,9 @@
if not self.temp_map:
return
- self._createOutputMap()
+ self._reprojectMap()
+
+ return self.temp_warpmap
def _fetchCapabilities(self, options):
"""!Download capabilities from WMS server
@@ -216,7 +192,7 @@
cap_url += "?REQUEST=GetTileService"
else:
cap_url += "?SERVICE=WMS&REQUEST=GetCapabilities&VERSION=" + options['wms_version']
-
+
try:
cap = urlopen(cap_url)
except (IOError, HTTPError, HTTPException):
@@ -228,9 +204,22 @@
"""!Get capabilities from WMS server
"""
cap = self._fetchCapabilities(options)
+ csfile = options['csfile'].strip()
+
+ # save to file
+ if csfile:
+ try:
+ temp = open(csfile, "w")
+ temp.write(cap.read())
+ temp.close()
+ return
+ except IOError as error:
+ grass.fatal(_("Unabble to open file '%s'.\n%s\n" % (cap_file, error)))
+
+ # print to output
cap_lines = cap.readlines()
for line in cap_lines:
- print line
+ print line
def _computeBbox(self):
"""!Get region extent for WMS query (bbox)
@@ -308,14 +297,13 @@
return bbox
- def _createOutputMap(self):
- """!Import downloaded data into GRASS, reproject data if needed
- using gdalwarp
+ def _reprojectMap(self):
+ """!Reproject data using gdalwarp if needed
"""
# reprojection of raster
if self.proj_srs != self.proj_location: # TODO: do it better
grass.message(_("Reprojecting raster..."))
- temp_warpmap = self._tempfile()
+ self.temp_warpmap = grass.tempfile()
if int(os.getenv('GRASS_VERBOSE', '2')) <= 2:
nuldev = file(os.devnull, 'w+')
@@ -324,36 +312,126 @@
#"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"
# RGB rasters - alpha layer is added for cropping edges of projected raster
- if self.temp_map_bands_num == 3:
- ps = grass.Popen(['gdalwarp',
- '-s_srs', '%s' % self.proj_srs,
- '-t_srs', '%s' % self.proj_location,
- '-r', self.params['method'], '-dstalpha',
- self.temp_map, temp_warpmap], stdout = nuldev)
- # RGBA rasters
- else:
- ps = grass.Popen(['gdalwarp',
- '-s_srs', '%s' % self.proj_srs,
- '-t_srs', '%s' % self.proj_location,
- '-r', self.params['method'],
- self.temp_map, temp_warpmap], stdout = nuldev)
- ps.wait()
+ try:
+ if self.temp_map_bands_num == 3:
+ ps = grass.Popen(['gdalwarp',
+ '-s_srs', '%s' % self.proj_srs,
+ '-t_srs', '%s' % self.proj_location,
+ '-r', self.params['method'], '-dstalpha',
+ self.temp_map, self.temp_warpmap], stdout = nuldev)
+ # RGBA rasters
+ else:
+ ps = grass.Popen(['gdalwarp',
+ '-s_srs', '%s' % self.proj_srs,
+ '-t_srs', '%s' % self.proj_location,
+ '-r', self.params['method'],
+ self.temp_map, self.temp_warpmap], stdout = nuldev)
+ ps.wait()
+ except OSError, e:
+ grass.fatal('%s \nThis can be caused by missing %s utility. ' % (e, 'gdalwarp'))
if nuldev:
nuldev.close()
if ps.returncode != 0:
grass.fatal(_('%s failed') % 'gdalwarp')
+ grass.try_remove(self.temp_map)
# raster projection is same as projection of location
else:
- temp_warpmap = self.temp_map
+ self.temp_warpmap = self.temp_map
+ self.temp_files_to_cleanup.remove(self.temp_map)
+
+ return self.temp_warpmap
+ def _tempfile(self):
+ """!Create temp_file and append list self.temp_files_to_cleanup
+ with path of file
+
+ @return string path to temp_file
+ """
+ temp_file = grass.tempfile()
+ if temp_file is None:
+ grass.fatal(_("Unable to create temporary files"))
+
+ # list of created tempfiles for destructor
+ self.temp_files_to_cleanup.append(temp_file)
+
+ return temp_file
+
+class GRASSImporter:
+ def __init__(self, opt_output):
+
+ self.cleanup_mask = False
+ self.cleanup_layers = False
+
+ # output map name
+ self.opt_output = opt_output
+
+ # suffix for existing mask (during overriding will be saved
+ # into raster named:self.opt_output + this suffix)
+ self.original_mask_suffix = "_temp_MASK"
+
+ # check names of temporary rasters, which module may create
+ maps = []
+ for suffix in ('.red', '.green', '.blue', '.alpha', self.original_mask_suffix ):
+ rast = self.opt_output + suffix
+ if grass.find_file(rast, element = 'cell', mapset = '.')['file']:
+ maps.append(rast)
+
+ if len(maps) != 0:
+ grass.fatal(_("Please change output name, or change names of these rasters: %s, "
+ "module needs to create this temporary maps during execution.") % ",".join(maps))
+
+ def __del__(self):
+ # removes temporary mask, used for import transparent or warped temp_map
+ if self.cleanup_mask:
+ # clear temporary mask, which was set by module
+ if grass.run_command('r.mask',
+ quiet = True,
+ flags = 'r') != 0:
+ grass.fatal(_('%s failed') % 'r.mask')
+
+ # restore original mask, if exists
+ if grass.find_file(self.opt_output + self.original_mask_suffix, element = 'cell', mapset = '.' )['name']:
+ if grass.run_command('g.copy',
+ quiet = True,
+ rast = self.opt_output + self.original_mask_suffix + ',MASK') != 0:
+ grass.fatal(_('%s failed') % 'g.copy')
+
+
+ # remove temporary created rasters
+ if self.cleanup_layers:
+ maps = []
+ for suffix in ('.red', '.green', '.blue', '.alpha', self.original_mask_suffix):
+ rast = self.opt_output + suffix
+ if grass.find_file(rast, element = 'cell', mapset = '.')['file']:
+ maps.append(rast)
+
+ if maps:
+ grass.run_command('g.remove',
+ quiet = True,
+ flags = 'f',
+ rast = ','.join(maps))
+
+ # delete environmental variable which overrides region
+ if 'GRASS_REGION' in os.environ.keys():
+ os.environ.pop('GRASS_REGION')
+
+ def ImportMapIntoGRASS(self, raster):
+ """!Import raster into GRASS.
+ """
+
grass.message(_("Importing raster map into GRASS..."))
+
+ if not raster:
+ grass.warning(_("Nothing to import.\nNo data has been downloaded from wms server."))
+ return
+
# importing temp_map into GRASS
if grass.run_command('r.in.gdal',
quiet = True,
- input = temp_warpmap,
- output = self.params['output']) != 0:
+ input = raster,
+ output = self.opt_output) != 0:
grass.fatal(_('%s failed') % 'r.in.gdal')
# information for destructor to cleanup temp_layers, created
@@ -361,21 +439,21 @@
self.cleanup_layers = True
# setting region for full extend of imported raster
- if grass.find_file(self.params['output'] + '.red', element = 'cell', mapset = '.')['file']:
- region_map = self.params['output'] + '.red'
+ if grass.find_file(self.opt_output + '.red', element = 'cell', mapset = '.')['file']:
+ region_map = self.opt_output + '.red'
else:
- region_map = self.params['output']
+ region_map = self.opt_output
os.environ['GRASS_REGION'] = grass.region_env(rast = region_map)
# mask created from alpha layer, which describes real extend
# of warped layer (may not be a rectangle), also mask contains
# transparent parts of raster
- if grass.find_file( self.params['output'] + '.alpha', element = 'cell', mapset = '.' )['name']:
+ if grass.find_file( self.opt_output + '.alpha', element = 'cell', mapset = '.' )['name']:
# saving current mask (if exists) into temp raster
if grass.find_file('MASK', element = 'cell', mapset = '.' )['name']:
if grass.run_command('g.copy',
quiet = True,
- rast = 'MASK,' + self.params['output'] + self.original_mask_suffix) != 0:
+ rast = 'MASK,' + self.opt_output + self.original_mask_suffix) != 0:
grass.fatal(_('%s failed') % 'g.copy')
# info for destructor
@@ -385,33 +463,92 @@
overwrite = True,
maskcats = "0",
flags = 'i',
- input = self.params['output'] + '.alpha') != 0:
+ input = self.opt_output + '.alpha') != 0:
grass.fatal(_('%s failed') % 'r.mask')
#TODO one band + alpha band?
- if grass.find_file(self.params['output'] + '.red', element = 'cell', mapset = '.')['file']:
+ if grass.find_file(self.opt_output + '.red', element = 'cell', mapset = '.')['file']:
if grass.run_command('r.composite',
quiet = True,
- red = self.params['output'] + '.red',
- green = self.params['output'] + '.green',
- blue = self.params['output'] + '.blue',
- output = self.params['output'] ) != 0:
+ red = self.opt_output + '.red',
+ green = self.opt_output + '.green',
+ blue = self.opt_output + '.blue',
+ output = self.opt_output ) != 0:
grass.fatal(_('%s failed') % 'r.composite')
-
- grass.try_remove(temp_warpmap)
- grass.try_remove(self.temp_map)
- def _tempfile(self):
- """!Create temp_file and append list self.temp_files_to_cleanup
- with path of file
-
- @return string path to temp_file
+
+class WMSDriversInfo:
+ def __init__(self):
+ """!Provides information about driver parameters.
"""
- temp_file = grass.tempfile()
- if temp_file is None:
- grass.fatal(_("Unable to create temporary files"))
-
- # list of created tempfiles for destructor
- self.temp_files_to_cleanup.append(temp_file)
-
- return temp_file
+
+ # format labels
+ self.f_labels = ["geotiff", "tiff", "png", "jpeg", "gif"]
+
+ # form for request
+ self.formats = ["image/geotiff", "image/tiff", "image/png", "image/jpeg", "image/gif"]
+
+ def GetDrvProperties(self, driver):
+ """!Get information about driver parameters.
+ """
+ if driver == 'WMS_GDAL':
+ return self._GDALDrvProperties()
+ if 'WMS' in driver:
+ return self._WMSProperties()
+ if 'WMTS' in driver:
+ return self._WMTSProperties()
+ if 'OnEarth' in driver:
+ return self._OnEarthProperties()
+
+
+ def _OnEarthProperties(self):
+
+ props = {}
+ props['ignored_flags'] = ['o']
+ props['ignored_params'] = ['bgcolor', 'styles', 'csfile',
+ 'format', 'srs', 'wms_version']
+ props['req_multiple_layers'] = False
+
+ return props
+
+ def _WMSProperties(self):
+
+ props = {}
+ props['ignored_params'] = ['cfile']
+ props['ignored_flags'] = []
+ props['req_multiple_layers'] = True
+
+ return props
+
+ def _WMTSProperties(self):
+
+ props = {}
+ props['ignored_flags'] = ['o']
+ props['ignored_params'] = ['urlparams', 'bgcolor', 'wms_version']
+ props['req_multiple_layers'] = False
+
+ return props
+
+ def _GDALDrvProperties(self):
+
+ props = {}
+ props['ignored_flags'] = []
+ props['ignored_params'] = ['urlparams', 'bgcolor', 'cfile', 'csfile',
+ 'username', 'password']
+ props['req_multiple_layers'] = True
+
+ return props
+
+ def GetFormatLabel(self, format):
+ """!Convert format request form to value in parameter 'format'.
+ """
+ if format in self.formats:
+ return self.f_labels[self.formats.index(format)]
+ return None
+
+ def GetFormat(self, label):
+ """!Convert value in parameter 'format' to format request form.
+ """
+ if label in self.f_labels:
+ return self.formats[self.f_labels.index(label)]
+ return None
Added: grass-addons/grass7/raster/r.in.wms2/wms_cap_parsers.py
===================================================================
--- grass-addons/grass7/raster/r.in.wms2/wms_cap_parsers.py (rev 0)
+++ grass-addons/grass7/raster/r.in.wms2/wms_cap_parsers.py 2012-12-19 00:53:53 UTC (rev 54346)
@@ -0,0 +1,564 @@
+"""!
+ at brief Parsers for WMS capabilities files.
+
+List of classes:
+ - wms_cap_parsers::BaseCapabilitiesTree
+ - wms_cap_parsers::WMSXMLNsHandler
+ - wms_cap_parsers::WMSCapabilitiesTree
+ - wms_cap_parsers::WMTSXMLNsHandler
+ - wms_cap_parsers::WMTSCapabilitiesTree
+ - wms_cap_parsers::OnEarthCapabilitiesTree
+
+(C) 2012 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Stepan Turek <stepan.turek seznam.cz> (Mentor: Martin Landa)
+"""
+
+import xml.etree.ElementTree as etree
+import grass.script as grass
+
+class BaseCapabilitiesTree(etree.ElementTree):
+ def __init__(self, cap_file):
+ """!Initializes xml.etree.ElementTree
+ """
+ try:
+ etree.ElementTree.__init__(self, file = cap_file)
+ except etree.ParseError:
+ raise etree.ParseError(_("Unable to parse XML file"))
+ except IOError as error:
+ raise etree.ParseError(_("Unabble to open XML file '%s'.\n%s\n" % (cap_file, error)))
+
+ if self.getroot() is None:
+ raise etree.ParseError(_("Root node was not found."))
+
+class WMSXMLNsHandler:
+ def __init__(self, caps):
+ """!Handle XML namespaces according to WMS version of capabilities.
+ """
+ self.namespace = "{http://www.opengis.net/wms}"
+
+ if caps.getroot().find("Service") is not None:
+ self.use_ns = False
+ elif caps.getroot().find(self.namespace + "Service") is not None:
+ self.use_ns = True
+ else:
+ raise etree.ParseError(_("Unable to parse capabilities file.\n\
+ Tag <%s> was not found.") % "Service")
+
+ def Ns(self, tag_name):
+ """!Add namespace to tag_name according to version
+ """
+ if self.use_ns:
+ tag_name = self.namespace + tag_name
+ return tag_name
+
+class WMSCapabilitiesTree(BaseCapabilitiesTree):
+ def __init__(self, cap_file, force_version = None):
+ """!Parses WMS capabilities file.
+ If the capabilities file cannot be parsed if it raises xml.etree.ElementTree.ParseError.
+
+ The class manges inheritance in 'Layer' elements. Inherited elements
+ are added to 'Layer' element.
+ The class also removes elements which are in invalid form and are needed
+ by wxGUI capabilities dialog.
+
+ @param cap_file - capabilities file
+ @param force_version - force capabilities file version (1.1.1, 1.3.0)
+ """
+ BaseCapabilitiesTree.__init__(self, cap_file)
+ self.xml_ns = WMSXMLNsHandler(self)
+
+ grass.debug('Checking WMS capabilities tree.', 4)
+
+ if not "version" in self.getroot().attrib:
+ raise etree.ParseError(_("Missing version attribute root node "
+ "in Capabilities XML file"))
+ else:
+ wms_version = self.getroot().attrib["version"]
+
+ if wms_version == "1.3.0":
+ self.proj_tag = "CRS"
+ else:
+ self.proj_tag = "SRS"
+
+ if force_version is not None:
+ if wms_version != force_version:
+ raise etree.ParseError(_("WMS server does not support '%s' version.") % wms_version)
+
+ capability = self._find(self.getroot(), "Capability")
+ root_layer = self._find(capability, "Layer")
+
+ self._checkFormats(capability)
+ self._checkLayerTree(root_layer)
+
+ grass.debug('Checking of WMS capabilities tree was finished.', 4)
+
+ def _checkFormats(self, capability):
+ """!Check if format element is defined.
+ """
+ request = self._find(capability, "Request")
+ get_map = self._find(request, "GetMap")
+ self._find(get_map, "Format")
+
+ def _checkLayerTree(self, parent_layer, first = True):
+ """!Recursively check layer tree and manage inheritance in the tree
+ """
+ if first:
+ self._initLayer(parent_layer, None)
+
+ layers = parent_layer.findall((self.xml_ns.Ns("Layer")))
+
+ for l in layers:
+ self._initLayer(l, parent_layer)
+ self._checkLayerTree(l, False)
+
+ def _initLayer(self, layer, parent_layer):
+ """Inherit elements from parent layer
+
+ @param layer - <Layer> element which inherits
+ @param parent_layer - <Layer> element which is inherited from
+ """
+ if parent_layer is not None:
+ replaced_elements = [ ["EX_GeographicBoundingBox", "replace"],
+ ["Attribution", "replace"],
+ ["MinScaleDenominator", "replace"],
+ ["MaxScaleDenominator", "replace"],
+ ["AuthorityURL", "add"]]
+
+ for element in replaced_elements:
+ elems = layer.findall(self.xml_ns.Ns(element[0]))
+
+ if len(elems) != 0 or element[1] == "add":
+ for e in parent_layer.findall(self.xml_ns.Ns(element[0])):
+ layer.append(e)
+
+ inh_arguments = ["queryable", "cascaded", "opaque",
+ "noSubsets", "fixedWidth", "fixedHeight"]
+
+ for attr in parent_layer.attrib:
+ if attr not in layer.attrib and attr in inh_arguments:
+ layer.attrib[attr] = parent_layer.attrib[attr]
+
+ self._inhNotSame(self.proj_tag, "element_content", layer, parent_layer)
+ self._inhNotSame("BoundingBox", "attribute", layer, parent_layer, self.proj_tag)
+
+ #remove invalid Styles
+ styles = layer.findall(self.xml_ns.Ns('Style'))
+ for s in styles:
+ s_name = s.find(self.xml_ns.Ns('Name'))
+ if s_name is None or not s_name.text:
+ grass.debug('Removed invalid <Style> element.', 4)
+ layer.remove(s)
+
+ self._inhNotSame("Style", "child_element_content", layer, parent_layer, "Name")
+ self._inhNotSame("Dimension", "attribute", layer, parent_layer, "name")
+
+ def _inhNotSame(self, element_name, cmp_type, layer, parent_layer, add_arg = None):
+ """Inherit elements which have unique values.
+
+ @param element_name - name of inherited element
+ @param cmp_type - 'element_content' - the value is text of <Layer> element
+ @param cmp_type - 'child_element_content' - the value is text of a child of the <Layer> element
+ @param cmp_type - 'attribute' - the value is text of the <Layer> element attribute
+ @param layer - <Layer> element which inherits
+ @param parent_layer - <Layer> element which is inherited from
+ @param add_arg - name of child element or attribute
+ """
+ elem = layer.findall(self.xml_ns.Ns(element_name))
+
+ parent_elems = []
+ if parent_layer is not None:
+ parent_elems = parent_layer.findall(self.xml_ns.Ns(element_name))
+
+ for par_elem in parent_elems:
+ parent_cmp_text = ""
+ if cmp_type == "attribute":
+ if add_arg in par_elem.attrib:
+ parent_cmp_text = par_elem.attrib[add_arg];
+
+ elif cmp_type == "element_content":
+ parent_cmp_text = par_elem.text
+
+ elif cmp_type == "child_element_content":
+ parent_cmp_text = par_elem.find(self.xml_ns.Ns(add_arg)).text
+
+ if parent_cmp_text == "":
+ continue
+
+ is_there = False
+ for elem in elem:
+ cmp_text = None
+ if cmp_type == "attribute":
+ if add_arg in elem.attrib:
+ cmp_text = elem.attrib[add_arg]
+
+ elif cmp_type == "element_content":
+ cmp_text = elem.text
+
+ elif cmp_type == "child_element_content":
+ cmp_text = elem.find(self.xml_ns.Ns(add_arg)).text
+
+ if cmp_text.lower() == parent_cmp_text.lower():
+ is_there = True
+ break
+
+ if not is_there:
+ layer.append(par_elem)
+
+ def _find(self, etreeElement, tag):
+ """!Find child element.
+ If the element is not found it raises xml.etree.ElementTree.ParseError.
+ """
+ res = etreeElement.find(self.xml_ns.Ns(tag))
+
+ if res is None:
+ raise etree.ParseError(_("Unable to parse capabilities file. \n\
+ Tag <%s> was not found.") % tag)
+
+ return res
+
+ def _findall(self, etreeElement, tag):
+ """!Find all children element.
+ If no element is found it raises xml.etree.ElementTree.ParseError.
+ """
+ res = etreeElement.findall(self.xml_ns.Ns(tag))
+
+ if not res:
+ raise etree.ParseError(_("Unable to parse capabilities file. \n\
+ Tag <%s> was not found.") % tag)
+
+ return res
+
+ def getprojtag(self):
+ """!Return projection tag according to version of capabilities (CRS/SRS).
+ """
+ return self.proj_tag
+
+ def getxmlnshandler(self):
+ """!Return WMSXMLNsHandler object.
+ """
+ return self.xml_ns
+
+class WMTSXMLNsHandler:
+ """!Handle XML namespaces which are used in WMTS capabilities file.
+ """
+ def NsWmts(self, tag):
+ """!Add namespace.
+ """
+ return "{http://www.opengis.net/wmts/1.0}" + tag
+
+ def NsOws(self, tag):
+ """!Add namespace.
+ """
+ return "{http://www.opengis.net/ows/1.1}" + tag
+
+class WMTSCapabilitiesTree(BaseCapabilitiesTree):
+ def __init__(self, cap_file):
+ """!Parses WMTS capabilities file.
+ If the capabilities file cannot be parsed it raises xml.etree.ElementTree.ParseError.
+
+ The class also removes elements which are in invalid form and are needed
+ by wxGUI capabilities dialog or for creation of GetTile request by GRASS WMS library.
+
+ @param cap_file - capabilities file
+ """
+ BaseCapabilitiesTree.__init__(self, cap_file)
+ self.xml_ns = WMTSXMLNsHandler()
+
+ grass.debug('Checking WMTS capabilities tree.', 4)
+
+ contents = self._find(self.getroot(), 'Contents', self.xml_ns.NsWmts)
+
+ tile_mat_sets = self._findall(contents, 'TileMatrixSet', self.xml_ns.NsWmts)
+
+ for mat_set in tile_mat_sets:
+ if not self._checkMatSet(mat_set):
+ grass.debug('Removed invalid <TileMatrixSet> element.', 4)
+ contents.remove(mat_set)
+
+ # are there any <TileMatrixSet> elements after the check
+ self._findall(contents, 'TileMatrixSet', self.xml_ns.NsWmts)
+
+ layers = self._findall(contents, 'Layer', self.xml_ns.NsWmts)
+
+ for l in layers:
+ if not self._checkLayer(l):
+ grass.debug('Removed invalid <Layer> element.', 4)
+ contents.remove(l)
+
+ # are there any <Layer> elements after the check
+ self._findall(contents, 'Layer', self.xml_ns.NsWmts)
+
+ grass.debug('Checking WMTS capabilities tree was finished.', 4)
+
+ def _checkMatSet(self, mat_set):
+ """!Check <TileMatrixSet>.
+ """
+ mat_set_id = mat_set.find(self.xml_ns.NsOws('Identifier'))
+ if mat_set_id is None or not mat_set_id.text:
+ return False
+
+ mat_set_srs = mat_set.find(self.xml_ns.NsOws('SupportedCRS'))
+ if mat_set_srs is None or \
+ not mat_set_srs.text or \
+ len(mat_set_srs.text) < 6 or \
+ not mat_set_srs.text.lower()[:5] == ("epsg:"):
+ return False
+
+ try:
+ int(mat_set_srs.text[5:])
+ except ValueError:
+ return False
+
+ tile_mats = mat_set.findall(self.xml_ns.NsWmts('TileMatrix'))
+ if not tile_mats:
+ return False
+
+ for t_mat in tile_mats:
+ if not self._checkMat(t_mat):
+ grass.debug('Removed invalid <TileMatrix> element.', 4)
+ mat_set.remove(t_mat)
+
+ tile_mats = mat_set.findall(self.xml_ns.NsWmts('TileMatrix'))
+ if not tile_mats:
+ return False
+
+ return True
+
+ def _checkMat(self, t_mat):
+ """!Check <TileMatrix>.
+ """
+ def _checkElement(t_mat, e, func):
+ element = t_mat.find(self.xml_ns.NsWmts(e))
+ if element is None or not element.text:
+ return False
+
+ try:
+ e = func(element.text)
+ except ValueError:
+ return False
+
+ if e < 0:
+ return False
+ return True
+
+ for e, func in [['ScaleDenominator', float],
+ ['TileWidth', int],
+ ['TileHeight', int]]:
+ if not _checkElement(t_mat, e, func):
+ return False
+
+ tile_mat_id = t_mat.find(self.xml_ns.NsOws('Identifier'))
+ if tile_mat_id is None or not tile_mat_id.text:
+ return False
+
+ tl_str = t_mat.find(self.xml_ns.NsWmts('TopLeftCorner'))
+ if tl_str is None or not tl_str.text:
+ return False
+
+ tl = tl_str.text.split(' ')
+ if len(tl) < 2:
+ return False
+
+ for t in tl:
+ try:
+ t = float(t)
+ except ValueError:
+ return False
+ return True
+
+ def _checkLayer(self, layer):
+ """!Check <Layer> element.
+ """
+ contents = self.getroot().find(self.xml_ns.NsWmts('Contents'))
+ layer_id = layer.find(self.xml_ns.NsOws('Identifier'))
+ if layer_id is None or not layer_id.text:
+ return False
+
+ mat_set_links = layer.findall(self.xml_ns.NsWmts('TileMatrixSetLink'))
+ if not mat_set_links:
+ return False
+
+ styles = layer.findall(self.xml_ns.NsWmts('Style'))
+ if not styles:
+ return False
+
+ for s in styles:
+ s_name = s.find(self.xml_ns.NsOws('Identifier'))
+ if s_name is None or not s_name.text:
+ grass.debug('Removed invalid <Style> element.', 4)
+ layer.remove(s_name)
+
+ tileMatrixSets = contents.findall(self.xml_ns.NsWmts('TileMatrixSet'))
+
+ for link in mat_set_links:
+ found = False
+ mat_set_link_id = link.find(self.xml_ns.NsWmts('TileMatrixSet')).text
+
+ for mat_set in tileMatrixSets:
+ mat_set_id = mat_set.find(self.xml_ns.NsOws('Identifier')).text
+
+ if mat_set_id != mat_set_link_id:
+ continue
+
+ # the link points to existing <TileMatrixSet>
+ found = True
+
+ tile_mat_set_limits = link.find(self.xml_ns.NsWmts('TileMatrixSetLimits'))
+ if tile_mat_set_limits is None:
+ continue
+
+ tile_mat_limits = tile_mat_set_limits.findall(self.xml_ns.NsWmts('TileMatrixLimits'))
+ for limit in tile_mat_limits:
+ if not self._checkMatSetLimit(limit):
+ grass.debug('Removed invalid <TileMatrixLimits> element.', 4)
+ tile_mat_limits.remove(limit)
+
+ # are there any <TileMatrixLimits> elements after the check
+ tile_mat_limits = tile_mat_set_limits.findall(self.xml_ns.NsWmts('TileMatrixLimits'))
+ if not tile_mat_limits:
+ grass.debug('Removed invalid <TileMatrixSetLimits> element.', 4)
+ link.remove(tile_mat_set_limits)
+
+ # TileMatrixSetLink does not point to existing <TileMatrixSet>
+ if not found:
+ grass.debug('Removed invalid <Layer> element.', 4)
+ layer.remove(link)
+
+ return True
+
+ def _checkMatSetLimit(self, limit):
+ """!Check <TileMatrixLimits> element.
+ """
+ limit_tile_mat = limit.find(self.xml_ns.NsWmts('TileMatrix'))
+ if limit_tile_mat is None or not limit_tile_mat.text:
+ return False
+
+ for i in ['MinTileRow', 'MaxTileRow', 'MinTileCol', 'MaxTileCol']:
+ i_tag = limit.find(self.xml_ns.NsWmts(i))
+ if i_tag is None:
+ return False
+ try:
+ int(i_tag.text)
+ except ValueError:
+ return False
+ return True
+
+ def _find(self, etreeElement, tag, ns = None):
+ """!Find child element.
+ If the element is not found it raises xml.etree.ElementTree.ParseError.
+ """
+ if not ns:
+ res = etreeElement.find(tag)
+ else:
+ res = etreeElement.find(ns(tag))
+
+ if res is None:
+ raise etree.ParseError(_("Unable to parse capabilities file. \n\
+ Tag '%s' was not found.") % tag)
+
+ return res
+
+ def _findall(self, etreeElement, tag, ns = None):
+ """!Find all children element.
+ If no element is found it raises xml.etree.ElementTree.ParseError.
+ """
+ if not ns:
+ res = etreeElement.findall(tag)
+ else:
+ res = etreeElement.findall(ns(tag))
+
+ if not res:
+ raise etree.ParseError(_("Unable to parse capabilities file. \n\
+ Tag '%s' was not found.") % tag)
+
+ return res
+
+ def getxmlnshandler(self):
+ """!Return WMTSXMLNsHandler object.
+ """
+ return self.xml_ns
+
+class OnEarthCapabilitiesTree(BaseCapabilitiesTree):
+ def __init__(self, cap_file):
+ """!Parses NASA OnEarth tile service file.
+ If the file cannot be parsed it raises xml.etree.ElementTree.ParseError.
+
+ The class also removes elements which are in invalid form and are needed
+ by wxGUI capabilities dialog or for creation of GetMap request by GRASS WMS library.
+
+ @param cap_file - capabilities file
+ """
+ #TODO check also TilePattern urls
+ BaseCapabilitiesTree.__init__(self, cap_file)
+
+ grass.debug('Checking OnEarth capabilities tree.', 4)
+
+ self._checkLayerTree(self.getroot())
+
+ grass.debug('Checking OnEarth capabilities tree was finished.', 4)
+
+ def _checkLayerTree(self, parent_layer, first = True):
+ """!Recursively check layer tree.
+ """
+ if first:
+ tiled_patterns = self.find(parent_layer, 'TiledPatterns')
+ layers = tiled_patterns.findall('TiledGroup')
+ layers += tiled_patterns.findall('TiledGroups')
+ parent_layer = tiled_patterns
+ else:
+ layers = parent_layer.findall('TiledGroup')
+ layers += parent_layer.findall('TiledGroups')
+
+ for l in layers:
+ if not self._checkLayer(l):
+ grass.debug(('Removed invalid <%s> element.' % l.tag), 4)
+ parent_layer.remove(l)
+ if l.tag == 'TiledGroups':
+ self._checkLayerTree(l, False)
+
+ def find(self, etreeElement, tag):
+ """!Find child element.
+ If the element is not found it raises xml.etree.ElementTree.ParseError.
+ """
+ res = etreeElement.find(tag)
+
+ if res is None:
+ raise etree.ParseError(_("Unable to parse tile service file. \n\
+ Tag <%s> was not found.") % tag)
+
+ return res
+
+ def findall(self, etreeElement, tag):
+ """!Find all children element.
+ If no element is found it raises xml.etree.ElementTree.ParseError.
+ """
+ res = etreeElement.findall(tag)
+
+ if not res:
+ raise etree.ParseError(_("Unable to parse tile service file. \n\
+ Tag <%s> was not found.") % tag)
+
+ return res
+
+ def _checkLayer(self, layer):
+ """!Check <TiledGroup>/<TiledGroups> elements.
+ """
+ if layer.tag == 'TiledGroups':
+ return True
+
+ name = layer.find('Name')
+ if name is None or not name.text:
+ return False
+
+ t_patts = layer.findall('TilePattern')
+
+ if not t_patts:
+ return False
+
+ return True
+
+
Modified: grass-addons/grass7/raster/r.in.wms2/wms_drv.py
===================================================================
--- grass-addons/grass7/raster/r.in.wms2/wms_drv.py 2012-12-18 21:49:23 UTC (rev 54345)
+++ grass-addons/grass7/raster/r.in.wms2/wms_drv.py 2012-12-19 00:53:53 UTC (rev 54346)
@@ -1,4 +1,21 @@
+"""!
+ at brief WMS, WMTS and NASA OnEarth drivers implemented in GRASS using GDAL Python bindings.
+List of classes:
+ - wms_drv::WMSDrv
+ - wms_drv::BaseRequestMgr
+ - wms_drv::WMSRequestMgr
+ - wms_drv::WMTSRequestMgr
+ - wms_drv::OnEarthRequestMgr
+
+(C) 2012 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Stepan Turek <stepan.turek seznam.cz> (Mentor: Martin Landa)
+"""
+
import grass.script as grass
import base64
from urllib2 import urlopen, HTTPError
@@ -11,7 +28,7 @@
grass.fatal(_("Unable to load GDAL python bindings"))
import urllib2
-import xml.etree.ElementTree as etree
+from xml.etree.ElementTree import ParseError
import numpy as Numeric
Numeric.arrayrange = Numeric.arange
@@ -19,6 +36,8 @@
from math import pi, floor
from wms_base import WMSBase
+from wms_cap_parsers import WMTSCapabilitiesTree, OnEarthCapabilitiesTree
+
class WMSDrv(WMSBase):
def _download(self):
"""!Downloads data from WMS server using own driver
@@ -27,13 +46,18 @@
"""
grass.message(_("Downloading data from WMS server..."))
+ if not self.params['cfile']:
+ self.cap_file = self._fetchCapabilities(self.params)
+ else:
+ self.cap_file = self.params['cfile']
+
# initialize correct manager according to chosen OGC service
if self.params['driver'] == 'WMTS_GRASS':
- req_mgr = WMTSRequestMgr(self.params, self.bbox, self.region, self.proj_srs, self._fetchCapabilities(self.params))
+ req_mgr = WMTSRequestMgr(self.params, self.bbox, self.region, self.proj_srs, self.cap_file)
elif self.params['driver'] == 'WMS_GRASS':
req_mgr = WMSRequestMgr(self.params, self.bbox, self.region, self.tile_size, self.proj_srs)
elif self.params['driver'] == 'OnEarth_GRASS':
- req_mgr = OnEarthRequestMgr(self.params, self.bbox, self.region, self.proj_srs, self._fetchCapabilities(self.params))
+ req_mgr = OnEarthRequestMgr(self.params, self.bbox, self.region, self.proj_srs, self.cap_file)
# get information about size in pixels and bounding box of raster, where all tiles will be joined
map_region = req_mgr.GetMapRegion()
@@ -96,12 +120,9 @@
else:
grass.fatal(_("WMS server unknown error") )
- band = tile_dataset_info.GetRasterBand(1)
- cell_type_func = band.__swig_getmethods__["DataType"]#??
- bands_number_func = tile_dataset_info.__swig_getmethods__["RasterCount"]
-
temp_tile_pct2rgb = None
- if bands_number_func(tile_dataset_info) == 1 and band.GetRasterColorTable() is not None:
+ if tile_dataset_info.RasterCount == 1 and \
+ tile_dataset_info.GetRasterBand(1).GetRasterColorTable() is not None:
# expansion of color table into bands
temp_tile_pct2rgb = self._tempfile()
tile_dataset = self._pct2rgb(temp_tile, temp_tile_pct2rgb)
@@ -117,10 +138,10 @@
if not metadata.has_key(gdal.DCAP_CREATE) or \
metadata[gdal.DCAP_CREATE] == 'NO':
grass.fatal(_('Driver %s does not supports Create() method') % drv_format)
-
- self.temp_map_bands_num = bands_number_func(tile_dataset)
+ self.temp_map_bands_num = tile_dataset.RasterCount
temp_map_dataset = driver.Create(temp_map, map_region['cols'], map_region['rows'],
- self.temp_map_bands_num, cell_type_func(band))
+ self.temp_map_bands_num,
+ tile_dataset.GetRasterBand(1).DataType)
init = False
# tile is written into temp_map
@@ -201,7 +222,6 @@
class BaseRequestMgr:
"""!Base class for request managers.
"""
-
def _computeRequestData(self, bbox, tl_corner, tile_span, tile_size, mat_num_bbox):
"""!Initialize data needed for iteration through tiles. Used by WMTS_GRASS and OnEarth_GRASS drivers.
"""
@@ -366,7 +386,7 @@
tile_ref['sizeY'] = self.last_tile_y_size
if self._isGeoProj(self.proj_srs) and self.version == "1.3.0":
- query_bbox = self._flipBbox(self.tile_bbox, self.proj_srs)
+ query_bbox = self._flipBbox(self.tile_bbox, self.proj_srs, self.version)
else:
query_bbox = self.tile_bbox
query_url = self.url + "&" + "BBOX=%s,%s,%s,%s" % ( query_bbox['minx'], query_bbox['miny'], query_bbox['maxx'], query_bbox['maxy'])
@@ -420,7 +440,12 @@
self.pixel_size = 0.00028
# parse capabilities file
- cap_tree = etree.parse(cap_file)
+ try:
+ cap_tree = WMTSCapabilitiesTree(cap_file)
+ except ParseError as error:
+ grass.fatal(_("Unable to parse tile service file.\n%s\n") % str(error))
+ self.xml_ns = cap_tree.getxmlnshandler()
+
root = cap_tree.getroot()
# get layer tile matrix sets with required projection
@@ -429,10 +454,10 @@
# TODO: what if more tile matrix sets have required srs (returned more than 1)?
mat_set = mat_sets[0][0]
mat_set_link = mat_sets[0][1]
- params['tile_matrix_set'] = mat_set.find(self._ns_ows('Identifier')).text
+ params['tile_matrix_set'] = mat_set.find(self.xml_ns.NsOws('Identifier')).text
# find tile matrix with resolution closest and smaller to wanted resolution
- tile_mat = self._findTileMats(mat_set.findall(self._ns_wmts('TileMatrix')), region, bbox)
+ tile_mat = self._findTileMats(mat_set.findall(self.xml_ns.NsWmts('TileMatrix')), region, bbox)
# get extend of data available on server expressed in max/min rows and cols of tile matrix
mat_num_bbox = self._getMatSize(tile_mat, mat_set_link)
@@ -449,38 +474,36 @@
"""!Get matrix sets which are available for chosen layer and have required EPSG.
"""
- contents = self.find(root, 'Contents', self._ns_wmts)
- layers = self.findall(contents, 'Layer', self._ns_wmts)
+ contents = root.find(self.xml_ns.NsWmts('Contents'))
+ layers = contents.findall(self.xml_ns.NsWmts('Layer'))
ch_layer = None
for layer in layers:
- layer_id = layer.find(self._ns_ows('Identifier')).text
- if layer_id and layer_id == layer_name:
+ layer_id = layer.find(self.xml_ns.NsOws('Identifier')).text
+ if layer_id == layer_name:
ch_layer = layer
break
if ch_layer is None:
- grass.fatal(_("Layer '%s' was not found in capabilities file") % params['layers'])
+ grass.fatal(_("Layer '%s' was not found in capabilities file") % layer_name)
- mat_set_links = self.findall(ch_layer, 'TileMatrixSetLink', self._ns_wmts)
+ mat_set_links = ch_layer.findall(self.xml_ns.NsWmts('TileMatrixSetLink'))
suitable_mat_sets = []
- tileMatrixSets = self.findall(contents, 'TileMatrixSet', self._ns_wmts)
+ tileMatrixSets = contents.findall(self.xml_ns.NsWmts('TileMatrixSet'))
for link in mat_set_links:
- mat_set_link_id = link.find(self._ns_wmts('TileMatrixSet')).text
- if not mat_set_link_id:
- continue
+ mat_set_link_id = link.find(self.xml_ns.NsWmts('TileMatrixSet')).text
for mat_set in tileMatrixSets:
- mat_set_id = mat_set.find(self._ns_ows('Identifier')).text
- if mat_set_id and mat_set_id != mat_set_link_id:
+ mat_set_id = mat_set.find(self.xml_ns.NsOws('Identifier')).text
+ if mat_set_id != mat_set_link_id:
continue
- mat_set_srs = mat_set.find(self._ns_ows('SupportedCRS')).text
- if mat_set_srs and mat_set_srs.lower() == ("EPSG:"+ str(srs)).lower():
+ mat_set_srs = mat_set.find(self.xml_ns.NsOws('SupportedCRS')).text
+ if mat_set_srs.lower() == ("EPSG:"+ str(srs)).lower():
suitable_mat_sets.append([mat_set, link])
if not suitable_mat_sets:
- grass.fatal(_("Layer '%s' is not available with %s code.") % (params['layers'], "EPSG:" + str(srs)))
+ grass.fatal(_("Layer '%s' is not available with %s code.") % (layer_name, "EPSG:" + str(srs)))
return suitable_mat_sets # [[TileMatrixSet, TileMatrixSetLink], ....]
@@ -496,7 +519,7 @@
first = True
for t_mat in tile_mats:
- mat_scale_den = float(t_mat.find(self._ns_wmts('ScaleDenominator')).text)
+ mat_scale_den = float(t_mat.find(self.xml_ns.NsWmts('ScaleDenominator')).text)
if first:
best_scale_den = mat_scale_den
best_t_mat = t_mat
@@ -520,8 +543,8 @@
# for geographic projection
if self._isGeoProj(self.proj_srs):
- proj_params = proj_srs.split(' ')
- for param in proj_parmas:
+ proj_params = self.proj_srs.split(' ')
+ for param in proj_params:
if '+a' in param:
a = float(param.split('=')[1])
break
@@ -549,47 +572,38 @@
# general tile matrix size
mat_num_bbox = {}
mat_num_bbox['min_col'] = mat_num_bbox['min_row'] = 0
- mat_num_bbox['max_col'] = int(tile_mat.find(self._ns_wmts('MatrixWidth')).text) - 1
- mat_num_bbox['max_row'] = int(tile_mat.find(self._ns_wmts('MatrixHeight')).text) - 1
+ mat_num_bbox['max_col'] = int(tile_mat.find(self.xml_ns.NsWmts('MatrixWidth')).text) - 1
+ mat_num_bbox['max_row'] = int(tile_mat.find(self.xml_ns.NsWmts('MatrixHeight')).text) - 1
# get extend restriction in TileMatrixSetLink for the tile matrix, if exists
- tile_mat_set_limits = mat_set_link.find((self._ns_wmts('TileMatrixSetLimits')))
+ tile_mat_set_limits = mat_set_link.find((self.xml_ns.NsWmts('TileMatrixSetLimits')))
if tile_mat_set_limits is None:
return mat_num_bbox
- tile_mat_id = tile_mat.find(self._ns_ows('Identifier')).text
- tile_mat_limits = tile_mat_set_limits.findall(self._ns_wmts('TileMatrixLimits'))
+ tile_mat_id = tile_mat.find(self.xml_ns.NsOws('Identifier')).text
+ tile_mat_limits = tile_mat_set_limits.findall(self.xml_ns.NsWmts('TileMatrixLimits'))
for limit in tile_mat_limits:
- limit_tile_mat = limit.find(self._ns_wmts('TileMatrix'))
+ limit_tile_mat = limit.find(self.xml_ns.NsWmts('TileMatrix'))
limit_id = limit_tile_mat.text
- if limit_id is None:
- continue
-
if limit_id == tile_mat_id:
-
for i in [['min_row', 'MinTileRow'], ['max_row', 'MaxTileRow'], \
['min_col', 'MinTileCol'], ['max_col', 'MaxTileCol']]:
- i_tag = limit.find(self._ns_wmts(i[1]))
+ i_tag = limit.find(self.xml_ns.NsWmts(i[1]))
- if i_tag is None:
- continue
- try:
- mat_num_bbox[i[0]] = int(i_tag.text)
- except ValueError:
- continue
+ mat_num_bbox[i[0]] = int(i_tag.text)
break
return mat_num_bbox
def _computeRequestData(self, tile_mat, params, bbox, mat_num_bbox):
"""!Initialize data needed for iteration through tiles.
"""
- scale_den = float(tile_mat.find(self._ns_wmts('ScaleDenominator')).text)
+ scale_den = float(tile_mat.find(self.xml_ns.NsWmts('ScaleDenominator')).text)
pixel_span = scale_den * self.pixel_size / self._getMetersPerUnit()
- tl_str = tile_mat.find(self._ns_wmts('TopLeftCorner')).text.split(' ')
+ tl_str = tile_mat.find(self.xml_ns.NsWmts('TopLeftCorner')).text.split(' ')
tl_corner = {}
tl_corner['minx'] = float(tl_str[0])
@@ -598,16 +612,16 @@
tile_span = {}
self.tile_size = {}
- self.tile_size['x'] = int(tile_mat.find(self._ns_wmts('TileWidth')).text)
+ self.tile_size['x'] = int(tile_mat.find(self.xml_ns.NsWmts('TileWidth')).text)
tile_span['x'] = pixel_span * self.tile_size['x']
- self.tile_size['y'] = int(tile_mat.find(self._ns_wmts('TileHeight')).text)
+ self.tile_size['y'] = int(tile_mat.find(self.xml_ns.NsWmts('TileHeight')).text)
tile_span['y'] = pixel_span * self.tile_size['y']
self.url = params['url'] + ("?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&" \
"LAYER=%s&STYLE=%s&FORMAT=%s&TILEMATRIXSET=%s&TILEMATRIX=%s" % \
(params['layers'], params['styles'], params['format'],
- params['tile_matrix_set'], tile_mat.find(self._ns_ows('Identifier')).text ))
+ params['tile_matrix_set'], tile_mat.find(self.xml_ns.NsOws('Identifier')).text ))
BaseRequestMgr._computeRequestData(self, bbox, tl_corner, tile_span, self.tile_size, mat_num_bbox)
@@ -630,49 +644,17 @@
return query_url, self.tile_ref
- def find(self, etreeElement, tag, ns = None):
- """!Wraper for etree element find method.
- """
- if not ns:
- res = etreeElement.find(tag)
- else:
- res = etreeElement.find(ns(tag))
-
- if res is None:
- grass.fatal(_("Unable to parse capabilities file. \n Tag '%s' was not found.") % tag)
-
- return res
-
- def findall(self, etreeElement, tag, ns = None):
- """!Wraper for etree element findall method.
- """
- if not ns:
- res = etreeElement.findall(tag)
- else:
- res = etreeElement.findall(ns(tag))
-
- if not res:
- grass.fatal(_("Unable to parse capabilities file. \n Tag '%s' was not found.") % tag)
-
- return res
-
- def _ns_wmts(self, tag):
- """!Helper method - XML namespace.
- """
- return "{http://www.opengis.net/wmts/1.0}" + tag
-
- def _ns_ows(self, tag):
- """!Helper method - XML namespace.
- """
- return "{http://www.opengis.net/ows/1.1}" + tag
-
class OnEarthRequestMgr(BaseRequestMgr):
def __init__(self, params, bbox, region, proj_srs, tile_service):
"""!Initializes data needed for iteration through tiles.
"""
- tile_service_tree = etree.parse(tile_service)
- root = tile_service_tree.getroot()
+ try:
+ cap_tree = OnEarthCapabilitiesTree(tile_service)
+ except ParseError as error:
+ grass.fatal(_("Unable to parse tile service file.\n%s\n") % str(error))
+ root = cap_tree.getroot()
+
# parse tile service file and get needed data for making tile requests
url, self.tile_span, t_patt_bbox, self.tile_size = self._parseTileService(root, bbox, region, params)
self.url = url
@@ -688,7 +670,7 @@
def _parseTileService(self, root, bbox, region, params):
"""!Get data from tile service file
"""
- tiled_patterns = self.find(root, 'TiledPatterns')
+ tiled_patterns = root.find('TiledPatterns')
tile_groups = self._getAllTiledGroup(tiled_patterns)
if not tile_groups:
grass.fatal(_("Unable to parse tile service file. \n No tag '%s' was found.") % 'TiledGroup')
@@ -696,14 +678,14 @@
req_group = None
for group in tile_groups:
name = group.find('Name')
- if name is not None and name.text == params['layers']:
+ if name.text == params['layers']:
req_group = group
break
if req_group is None:
grass.fatal(_("Tiled group '%s' was not found in tile service file") % params['layers'])
- group_t_patts = self.findall(req_group, 'TilePattern')
+ group_t_patts = req_group.findall('TilePattern')
best_patt = self._parseTilePattern(group_t_patts, bbox, region)
if best_patt is None:
@@ -723,7 +705,7 @@
tile_span['x'] = abs(t_bbox[0] - t_bbox[2])
tile_span['y'] = abs(t_bbox[1] - t_bbox[3])
- tile_pattern_bbox = self.find(req_group, 'LatLonBoundingBox')
+ tile_pattern_bbox = req_group.find('LatLonBoundingBox')
t_patt_bbox = {}
for s in ['minx', 'miny', 'maxx', 'maxy']:
@@ -736,7 +718,7 @@
return url, tile_span, t_patt_bbox, tile_size
def _getAllTiledGroup(self, parent, tiled_groups = None):
- """!Get all 'TileGroup' tags
+ """!Get all 'TileGroup' elements
"""
if not tiled_groups:
tiled_groups = []
@@ -923,22 +905,3 @@
return query_url, self.tile_ref
- def find(self, etreeElement, tag):
- """!Wraper for etree element find method.
- """
- res = etreeElement.find(tag)
-
- if res is None:
- grass.fatal(_("Unable to parse tile service file. \n Tag '%s' was not found.") % tag)
-
- return res
-
- def findall(self, etreeElement, tag):
- """!Wraper for etree element findall method.
- """
- res = etreeElement.findall(tag)
-
- if not res:
- grass.fatal(_("Unable to parse tile service file. \n Tag '%s' was not found.") % tag)
-
- return res
\ No newline at end of file
Modified: grass-addons/grass7/raster/r.in.wms2/wms_gdal_drv.py
===================================================================
--- grass-addons/grass7/raster/r.in.wms2/wms_gdal_drv.py 2012-12-18 21:49:23 UTC (rev 54345)
+++ grass-addons/grass7/raster/r.in.wms2/wms_gdal_drv.py 2012-12-19 00:53:53 UTC (rev 54346)
@@ -1,3 +1,18 @@
+"""!
+ at brief GDAL WMS driver.
+
+List of classes:
+ - wms_drv::NullDevice
+ - wms_drv::WMSGdalDrv
+
+(C) 2012 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Stepan Turek <stepan.turek seznam.cz> (Mentor: Martin Landa)
+"""
+
import os
import grass.script as grass
More information about the grass-commit
mailing list