v.in.wfs.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. #!/usr/bin/env python3
  2. ############################################################################
  3. #
  4. # MODULE: v.in.wfs
  5. # AUTHOR(S): Markus Neteler. neteler itc it
  6. # Hamish Bowman
  7. # Converted to Python by Glynn Clements
  8. # PURPOSE: WFS support
  9. # COPYRIGHT: (C) 2006-2012 Markus Neteler and the GRASS Development Team
  10. #
  11. # This program is free software under the GNU General
  12. # Public License (>=v2). Read the file COPYING that
  13. # comes with GRASS for details.
  14. #
  15. # GetFeature example:
  16. # http://mapserver.gdf-hannover.de/cgi-bin/grassuserwfs?REQUEST=GetFeature&SERVICE=WFS&VERSION=1.0.0
  17. #############################################################################
  18. #
  19. # TODO: suggest to depend on the OWSLib for OGC web service needs
  20. # http://pypi.python.org/pypi/OWSLib
  21. #
  22. # %Module
  23. # % description: Imports GetFeature from a WFS server.
  24. # % keyword: vector
  25. # % keyword: import
  26. # % keyword: OGC web services
  27. # % keyword: OGC WFS
  28. # %end
  29. # %option
  30. # % key: url
  31. # % type: string
  32. # % description: Base URL starting with 'http' and ending in '?'
  33. # % required: yes
  34. # %end
  35. # %option G_OPT_V_OUTPUT
  36. # %end
  37. # %option
  38. # % key: name
  39. # % type: string
  40. # % description: Comma separated names of data layers to download
  41. # % multiple: yes
  42. # % required: no
  43. # %end
  44. # %option
  45. # % key: srs
  46. # % type: string
  47. # % label: Specify alternate spatial reference system (example: EPSG:4326)
  48. # % description: The given code must be supported by the server, consult the capabilities file
  49. # % required: no
  50. # %end
  51. # %option
  52. # % key: maximum_features
  53. # % type: integer
  54. # % label: Maximum number of features to download
  55. # % description: (default: unlimited)
  56. # %end
  57. # %option
  58. # % key: start_index
  59. # % type: integer
  60. # % label: Skip earlier feature IDs and start downloading at this one
  61. # % description: (default: start with the first feature)
  62. # %end
  63. # %option
  64. # % key: username
  65. # % type: string
  66. # % required: no
  67. # % multiple: no
  68. # % label: Username or file with username or environment variable name with username
  69. # %end
  70. # %option
  71. # % key: password
  72. # % type: string
  73. # % required: no
  74. # % multiple: no
  75. # % label: Password or file with password or environment variable name with password
  76. # %end
  77. # %flag
  78. # % key: l
  79. # todo #% description: List available layers and exit
  80. # % description: Download server capabilities to 'wms_capabilities.xml' in the current directory and exit
  81. # % suppress_required: yes
  82. # %end
  83. # %flag
  84. # % key: r
  85. # % description: Restrict fetch to features which touch the current region
  86. # %end
  87. import os
  88. import sys
  89. from grass.script.utils import try_remove
  90. from grass.script import core as grass
  91. try:
  92. from urllib2 import urlopen, URLError, HTTPError
  93. from urllib2 import build_opener, install_opener
  94. from urllib2 import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler
  95. except ImportError:
  96. from urllib.request import urlopen
  97. from urllib.request import build_opener, install_opener
  98. from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler
  99. from urllib.error import URLError, HTTPError
  100. def main():
  101. out = options["output"]
  102. wfs_url = options["url"]
  103. request_base = "REQUEST=GetFeature&SERVICE=WFS&VERSION=1.0.0"
  104. wfs_url += request_base
  105. if options["name"]:
  106. wfs_url += "&TYPENAME=" + options["name"]
  107. if options["srs"]:
  108. wfs_url += "&SRS=" + options["srs"]
  109. if options["maximum_features"]:
  110. wfs_url += "&MAXFEATURES=" + options["maximum_features"]
  111. if int(options["maximum_features"]) < 1:
  112. # GTC Invalid WFS maximum features parameter
  113. grass.fatal(_("Invalid maximum number of features"))
  114. if options["start_index"]:
  115. wfs_url += "&STARTINDEX=" + options["start_index"]
  116. if int(options["start_index"]) < 1:
  117. # GTC Invalid WFS start index parameter
  118. grass.fatal(_('Features begin with index "1"'))
  119. if flags["r"]:
  120. bbox = grass.read_command("g.region", flags="w").split("=")[1]
  121. wfs_url += "&BBOX=" + bbox
  122. if flags["l"]:
  123. wfs_url = options["url"] + "REQUEST=GetCapabilities&SERVICE=WFS&VERSION=1.0.0"
  124. tmp = grass.tempfile()
  125. tmpxml = tmp + ".xml"
  126. grass.debug(wfs_url)
  127. # Set user and password if given
  128. if options["username"] and options["password"]:
  129. grass.message(_("Setting username and password..."))
  130. if os.path.isfile(options["username"]):
  131. with open(options["username"]) as f:
  132. filecontent = f.read()
  133. user = filecontent.strip()
  134. elif options["username"] in os.environ:
  135. user = os.environ[options["username"]]
  136. else:
  137. user = options["username"]
  138. if os.path.isfile(options["password"]):
  139. with open(options["password"]) as f:
  140. filecontent = f.read()
  141. pw = filecontent.strip()
  142. elif options["password"] in os.environ:
  143. pw = os.environ[options["password"]]
  144. else:
  145. pw = options["password"]
  146. passmgr = HTTPPasswordMgrWithDefaultRealm()
  147. passmgr.add_password(None, wfs_url, user, pw)
  148. authhandler = HTTPBasicAuthHandler(passmgr)
  149. opener = build_opener(authhandler)
  150. install_opener(opener)
  151. # GTC Downloading WFS features
  152. grass.message(_("Retrieving data..."))
  153. try:
  154. inf = urlopen(wfs_url)
  155. except HTTPError as e:
  156. # GTC WFS request HTTP failure
  157. grass.fatal(
  158. _("The server couldn't fulfill the request.\nError code: %s") % e.code
  159. )
  160. except URLError as e:
  161. # GTC WFS request network failure
  162. grass.fatal(_("Failed to reach the server.\nReason: %s") % e.reason)
  163. outf = open(tmpxml, "wb")
  164. while True:
  165. s = inf.read()
  166. if not s:
  167. break
  168. outf.write(s)
  169. inf.close()
  170. outf.close()
  171. if flags["l"]:
  172. import shutil
  173. if os.path.exists("wms_capabilities.xml"):
  174. grass.fatal(_('A file called "wms_capabilities.xml" already exists here'))
  175. # os.move() might fail if the temp file is on another volume, so we copy instead
  176. shutil.copy(tmpxml, "wms_capabilities.xml")
  177. try_remove(tmpxml)
  178. sys.exit(0)
  179. grass.message(_("Importing data..."))
  180. try:
  181. grass.run_command("v.in.ogr", flags="o", input=tmpxml, output=out)
  182. grass.message(_("Vector map <%s> imported from WFS.") % out)
  183. except Exception:
  184. grass.message(_("WFS import failed"))
  185. finally:
  186. try_remove(tmpxml)
  187. if __name__ == "__main__":
  188. options, flags = grass.parser()
  189. main()