Coverage for gws-app/gws/plugin/ows_client/wmts/caps.py: 100%
55 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
1"""WMTS capabilities parser."""
3import gws
4import gws.base.ows.client
5import gws.lib.crs
6import gws.gis.source
7import gws.gis.zoom
8import gws.lib.xmlx as xmlx
9import gws.base.ows.client.parseutil as u
12# http://portal.opengeospatial.org/files/?artifact_id=35326
15def parse(xml: str) -> gws.OwsCapabilities:
16 """Read WMTS capabilities from the GetCapabilities XML.
18 Matrices in each tile matrix set are sorted from the coarsest to the finest
19 scale. Each source layer refers to the tile matrix sets it is linked to.
21 Args:
22 xml: GetCapabilities XML.
24 Returns:
25 The parsed capabilities, including the tile matrix sets.
26 """
27 caps_el = xmlx.from_string(xml, gws.XmlOptions(compactWhitespace=True, removeNamespaces=True))
28 tms_lst = [_tile_matrix_set(el) for el in caps_el.findall('Contents/TileMatrixSet')]
29 tms_dct = {tms.identifier: tms for tms in tms_lst}
30 sls = gws.gis.source.check_layers(_layer(el, tms_dct) for el in caps_el.findall('Contents/Layer'))
31 return gws.OwsCapabilities(
32 tileMatrixSets=tms_lst,
33 metadata=u.service_metadata(caps_el),
34 operations=u.service_operations(caps_el),
35 sourceLayers=sls,
36 version=caps_el.get('version'),
37 )
40def _layer(layer_el: gws.XmlElement, tms_dct):
41 """Create a source layer from a ``Layer`` element."""
42 # <Layer>
43 # <ows:Title>...
44 # <Style>...
45 # <Format>...
46 # <TileMatrixSetLink>
47 # <TileMatrixSet>...
49 sl = gws.SourceLayer()
51 sl.metadata = u.element_metadata(layer_el)
52 sl.name = sl.metadata.get('name', '')
53 sl.title = sl.metadata.get('title', '')
55 sl.styles = [u.parse_style(e) for e in layer_el.findall('Style')]
56 sl.defaultStyle = u.default_style(sl.styles)
57 if sl.defaultStyle:
58 sl.legendUrl = sl.defaultStyle.legendUrl
60 sl.tileMatrixIds = [el.textof('TileMatrixSet') for el in layer_el.findall('TileMatrixSetLink')]
61 sl.tileMatrixSets = [tms_dct[tid] for tid in sl.tileMatrixIds]
63 extra_crsids = [tms.crs.srid for tms in sl.tileMatrixSets]
64 wgs_extent = u.wgs_extent(layer_el)
65 crs_list = u.supported_crs(layer_el, extra_crsids)
67 sl.supportedCrs = crs_list or [gws.lib.crs.WGS84]
68 sl.wgsExtent = wgs_extent or gws.lib.crs.WGS84.extent
70 sl.isImage = True
71 sl.isVisible = True
73 sl.imageFormat = layer_el.textof('Format')
75 sl.resourceUrls = {e.get('resourceType'): e.get('template') for e in layer_el.findall('ResourceURL')}
77 return sl
80def _tile_matrix_set(tms_el: gws.XmlElement):
81 """Create a tile matrix set from a ``TileMatrixSet`` element."""
82 # <TileMatrixSet>
83 # <ows:Identifier>...
84 # <ows:SupportedCRS>...
85 # <TileMatrix>
86 # ...
88 tms = gws.TileMatrixSet()
90 tms.identifier = tms_el.textof('Identifier')
91 tms.crs = gws.lib.crs.require(tms_el.textof('SupportedCRS'))
92 tms.matrices = sorted([_tile_matrix(e, tms.crs) for e in tms_el.findall('TileMatrix')], key=lambda m: -m.scale)
94 return tms
97def _tile_matrix(tm_el: gws.XmlElement, crs: gws.Crs):
98 """Create a tile matrix from a ``TileMatrix`` element."""
99 # <TileMatrix>
100 # <ows:Identifier>
101 # <ScaleDenominator>
102 # ...
104 tm = gws.TileMatrix()
105 tm.identifier = tm_el.textof('Identifier')
106 tm.scale = u.to_float(tm_el.textof('ScaleDenominator'))
107 tm.resolution = gws.gis.zoom.scale_to_res(tm.scale, crs)
109 p = u.to_float_pair(tm_el.textof('TopLeftCorner'))
110 tm.x = p[0]
111 tm.y = p[1]
113 tm.width = u.to_int(tm_el.textof('MatrixWidth'))
114 tm.height = u.to_int(tm_el.textof('MatrixHeight'))
116 tm.tileWidth = u.to_int(tm_el.textof('TileWidth'))
117 tm.tileHeight = u.to_int(tm_el.textof('TileHeight'))
119 # see http://portal.opengeospatial.org/files/?artifact_id=35326 page 8
120 res = tm.resolution
121 tm.extent = (
122 tm.x,
123 tm.y - res * tm.height * tm.tileHeight,
124 tm.x + res * tm.width * tm.tileWidth,
125 tm.y,
126 )
128 return tm