cap_interface.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. """
  2. @package web_services.cap_interface
  3. @brief Provides common interface for GUI web_services.widgets to capabilities data of web services.
  4. List of classes:
  5. - cap_interface::CapabilitiesBase
  6. - cap_interface::LayerBase
  7. - cap_interface::WMSCapabilities
  8. - cap_interface::WMSLayer
  9. - cap_interface::WMTSCapabilities
  10. - cap_interface::WMTSLayer
  11. - cap_interface::OnEarthCapabilities
  12. - cap_interface::OnEarthLayer
  13. (C) 2012 by the GRASS Development Team
  14. This program is free software under the GNU General Public License
  15. (>=v2). Read the file COPYING that comes with GRASS for details.
  16. @author Stepan Turek <stepan.turek seznam.cz> (Mentor: Martin Landa)
  17. """
  18. import os
  19. import sys
  20. WMSLibPath = os.path.join(os.getenv("GISBASE"), "etc", "r.in.wms")
  21. if WMSLibPath not in sys.path:
  22. sys.path.append(WMSLibPath)
  23. from wms_cap_parsers import WMSCapabilitiesTree, \
  24. WMTSCapabilitiesTree, \
  25. OnEarthCapabilitiesTree
  26. class CapabilitiesBase:
  27. def GetLayerByName(self, name):
  28. """Find layer by name
  29. """
  30. for l in self.layers_by_id:
  31. if name == l.GetLayerData('name'):
  32. return l
  33. return None
  34. def GetRootLayer(self):
  35. """Get children layers
  36. """
  37. if self.layers_by_id:
  38. return self.layers_by_id[0]
  39. else:
  40. return None
  41. class LayerBase:
  42. def GetId(self):
  43. """Get layer id
  44. """
  45. return self.id
  46. def GetChildren(self):
  47. """Get children layers
  48. """
  49. return self.child_layers
  50. def GetLayerNode(self):
  51. """Get layer node
  52. """
  53. return self.layer_node
  54. def AddChildLayer(self, layer):
  55. """Add child layer
  56. """
  57. self.child_layers.append(layer)
  58. class WMSCapabilities(CapabilitiesBase, WMSCapabilitiesTree):
  59. def __init__(self, cap_file, force_version=None):
  60. """Create common interface for web_services.widgets to WMS
  61. capabilities data
  62. """
  63. # checks all elements needed for creation of GetMap requests
  64. # by r.in.wms/d.wms modules, invalid elements are removed
  65. WMSCapabilitiesTree.__init__(self, cap_file, force_version)
  66. self.cap_node = self.getroot().find(self.xml_ns.Ns("Capability"))
  67. self.root_layer = self.cap_node.find(self.xml_ns.Ns("Layer"))
  68. self.layers_by_id = {}
  69. self._initializeLayerTree(self.root_layer)
  70. def _initializeLayerTree(self, parent_layer, id=0):
  71. """Build tree, which represents layers
  72. """
  73. if id == 0:
  74. parent_layer = WMSLayer(parent_layer, id, self)
  75. self.layers_by_id[id] = parent_layer
  76. id += 1
  77. layer_nodes = parent_layer.GetLayerNode().findall((self.xml_ns.Ns("Layer")))
  78. for l in layer_nodes:
  79. layer = WMSLayer(l, id, self)
  80. parent_layer.AddChildLayer(layer)
  81. self.layers_by_id[id] = layer
  82. id += 1
  83. id = self._initializeLayerTree(layer, id)
  84. return id
  85. def GetFormats(self):
  86. """Get supported formats
  87. """
  88. request_node = self.cap_node.find(self.xml_ns.Ns("Request"))
  89. get_map_node = request_node.find(self.xml_ns.Ns("GetMap"))
  90. format_nodes = get_map_node.findall(self.xml_ns.Ns("Format"))
  91. formats = []
  92. for node in format_nodes:
  93. formats.append(node.text)
  94. return formats
  95. class WMSLayer(LayerBase):
  96. def __init__(self, layer_node, id, cap):
  97. """Common interface for web_services.widgets to WMS
  98. capabilities <Layer> element
  99. """
  100. self.id = id
  101. self.cap = cap
  102. self.child_layers = []
  103. self.layer_node = layer_node
  104. self.xml_ns = self.cap.getxmlnshandler()
  105. def GetLayerData(self, param):
  106. """Get layer data"""
  107. title = self.xml_ns.Ns("Title")
  108. name = self.xml_ns.Ns("Name")
  109. if param == 'title':
  110. title_node = self.layer_node.find(title)
  111. if title_node is not None:
  112. return title_node.text
  113. else:
  114. return None
  115. if param == 'name':
  116. name_node = self.layer_node.find(name)
  117. if name_node is not None:
  118. return name_node.text
  119. else:
  120. return None
  121. if param == 'format':
  122. return self.cap.GetFormats()
  123. if param == 'styles':
  124. styles = []
  125. style = self.xml_ns.Ns("Style")
  126. for style_node in self.layer_node.findall(style):
  127. style_name = ''
  128. style_title = ''
  129. if style_node.find(title) is not None:
  130. style_title = style_node.find(title).text
  131. if style_node.find(name) is not None:
  132. style_name = style_node.find(name).text
  133. styles.append({'title': style_title,
  134. 'name': style_name,
  135. 'isDefault': False})
  136. return styles
  137. if param == 'srs':
  138. projs_nodes = self.layer_node.findall(
  139. self.xml_ns.Ns(self.cap.getprojtag()))
  140. projs = []
  141. if projs_nodes is None:
  142. return projs
  143. for p in projs_nodes:
  144. projs.append(p.text.strip())
  145. return projs
  146. def IsRequestable(self):
  147. """Is it possible to use the layer for WMS GetMap request?
  148. """
  149. name = self.xml_ns.Ns("Name")
  150. name_node = self.layer_node.find(name)
  151. if name_node is not None:
  152. return True
  153. else:
  154. return False
  155. class WMTSCapabilities(CapabilitiesBase, WMTSCapabilitiesTree):
  156. def __init__(self, cap_file):
  157. """Create common interface for web_services.widgets to WMTS
  158. capabilities data
  159. """
  160. # checks all elements needed for creation of GetTile requests
  161. # by r.in.wms/d.wms modules, invalid elements are removed
  162. WMTSCapabilitiesTree.__init__(self, cap_file)
  163. contents = self._find(self.getroot(), 'Contents', self.xml_ns.NsWmts)
  164. layers = self._findall(contents, 'Layer', self.xml_ns.NsWmts)
  165. self.layers_by_id = {}
  166. id = 0
  167. root_layer = WMTSLayer(None, id, self)
  168. self.layers_by_id[id] = root_layer
  169. for layer_node in layers:
  170. id += 1
  171. self.layers_by_id[id] = WMTSLayer(layer_node, id, self)
  172. root_layer.child_layers.append(self.layers_by_id[id])
  173. class WMTSLayer(LayerBase):
  174. def __init__(self, layer_node, id, cap):
  175. """Common interface for web_services.widgets to WMTS
  176. capabilities <Layer> element
  177. """
  178. self.id = id
  179. self.cap = cap
  180. self.child_layers = []
  181. self.layer_node = layer_node
  182. self.xml_ns = self.cap.getxmlnshandler()
  183. self.projs = self._getProjs()
  184. def GetLayerData(self, param):
  185. """Get layer data
  186. """
  187. title = self.xml_ns.NsOws("Title")
  188. name = self.xml_ns.NsOws("Identifier")
  189. if self.layer_node is None and param in ['title', 'name']:
  190. return None
  191. elif self.layer_node is None:
  192. return []
  193. if param == 'title':
  194. title_node = self.layer_node.find(title)
  195. if title_node is not None:
  196. return title_node.text
  197. else:
  198. return None
  199. if param == 'name':
  200. name_node = self.layer_node.find(name)
  201. if name_node is not None:
  202. return name_node.text
  203. else:
  204. return None
  205. if param == 'styles':
  206. styles = []
  207. for style_node in self.layer_node.findall(
  208. self.xml_ns.NsWmts("Style")):
  209. style_name = ''
  210. style_title = ''
  211. if style_node.find(title) is not None:
  212. style_title = style_node.find(title).text
  213. if style_node.find(name) is not None:
  214. style_name = style_node.find(name).text
  215. is_def = False
  216. if 'isDefault' in style_node.attrib and\
  217. style_node.attrib['isDefault'] == 'true':
  218. is_def = True
  219. styles.append({'title': style_title,
  220. 'name': style_name,
  221. 'isDefault': is_def})
  222. return styles
  223. if param == 'format':
  224. formats = []
  225. for frmt in self.layer_node.findall(self.xml_ns.NsWmts('Format')):
  226. formats.append(frmt.text.strip())
  227. return formats
  228. if param == 'srs':
  229. return self.projs
  230. def _getProjs(self):
  231. """Get layer projections
  232. """
  233. layer_projs = []
  234. if self.layer_node is None:
  235. return layer_projs
  236. mat_set_links = self.layer_node.findall(
  237. self.xml_ns.NsWmts('TileMatrixSetLink'))
  238. contents = self.cap.getroot().find(self.xml_ns.NsWmts('Contents'))
  239. tileMatrixSets = contents.findall(self.xml_ns.NsWmts('TileMatrixSet'))
  240. for link in mat_set_links:
  241. mat_set_link_id = link.find(
  242. self.xml_ns.NsWmts('TileMatrixSet')).text
  243. if not mat_set_link_id:
  244. continue
  245. for mat_set in tileMatrixSets:
  246. mat_set_id = mat_set.find(self.xml_ns.NsOws('Identifier')).text
  247. if mat_set_id and mat_set_id != mat_set_link_id:
  248. continue
  249. mat_set_srs = mat_set.find(
  250. self.xml_ns.NsOws('SupportedCRS')).text.strip()
  251. layer_projs.append(mat_set_srs)
  252. return layer_projs
  253. def IsRequestable(self):
  254. """Is it possible to use the layer for WMTS request?
  255. """
  256. if self.layer_node is None:
  257. return False
  258. else:
  259. return True
  260. class OnEarthCapabilities(CapabilitiesBase, OnEarthCapabilitiesTree):
  261. def __init__(self, cap_file):
  262. """Create Common interface for web_services.widgets to
  263. NASA OnEarth tile service data (equivalent to WMS, WMTS
  264. capabilities data)
  265. """
  266. # checks all elements needed for creation of GetMap requests
  267. # by r.in.wms/d.wms modules, invalid elements are removed
  268. OnEarthCapabilitiesTree.__init__(self, cap_file)
  269. self.layers_by_id = {}
  270. self._initializeLayerTree(self.getroot())
  271. def _initializeLayerTree(self, parent_layer, id=0):
  272. """Build tree, which represents layers
  273. """
  274. if id == 0:
  275. tiled_patterns = parent_layer.find('TiledPatterns')
  276. layer_nodes = tiled_patterns.findall('TiledGroup')
  277. layer_nodes += tiled_patterns.findall('TiledGroups')
  278. parent_layer = OnEarthLayer(None, None, id, self)
  279. self.layers_by_id[id] = parent_layer
  280. id += 1
  281. else:
  282. layer_nodes = parent_layer.layer_node.findall('TiledGroup')
  283. layer_nodes += parent_layer.layer_node.findall('TiledGroups')
  284. for layer_node in layer_nodes:
  285. layer = OnEarthLayer(layer_node, parent_layer, id, self)
  286. self.layers_by_id[id] = layer
  287. id += 1
  288. parent_layer.child_layers.append(layer)
  289. if layer_node.tag == 'TiledGroups':
  290. id = self._initializeLayerTree(layer, id)
  291. return id
  292. class OnEarthLayer(LayerBase):
  293. def __init__(self, layer_node, parent_layer, id, cap):
  294. """Common interface for web_services.widgets to NASA Earth
  295. capabilities <TiledGroup>\<TiledGroups> element
  296. (equivalent to WMS, WMTS <Layer> element)
  297. """
  298. self.id = id
  299. self.cap = cap
  300. self.layer_node = layer_node
  301. self.child_layers = []
  302. self.parent_layer = parent_layer
  303. def IsRequestable(self):
  304. """Is it possible to use the layer for NASA OnEarth GetMap request?
  305. """
  306. if self.layer_node is None or \
  307. self.layer_node.tag == 'TiledGroups':
  308. return False
  309. else:
  310. return True
  311. def GetLayerData(self, param):
  312. """Get layer data
  313. """
  314. if self.layer_node is None and param in ['title', 'name']:
  315. return None
  316. elif self.layer_node is None:
  317. return []
  318. if param == 'title':
  319. title_node = self.layer_node.find("Title")
  320. if title_node is not None:
  321. return title_node.text
  322. else:
  323. return None
  324. if param == 'name':
  325. name_node = self.layer_node.find("Name")
  326. if name_node is not None:
  327. return name_node.text
  328. else:
  329. return None
  330. if param == 'styles':
  331. return []
  332. if param == 'format':
  333. return []
  334. if param == 'srs':
  335. return []