[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