cap_interface.py 13 KB

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