def _map_layers(root_el: gws.XmlElement, props) -> t.Dict[str, gws.SourceLayer]: no_wms_layers = set(_pval(props, 'WMSRestrictedLayers') or []) use_layer_ids = _pval(props, 'WMSUseLayerIDs') map_layers = {} for el in xml2.all(root_el, 'projectlayers maplayer'): sl = _map_layer(el) if not sl: continue title = sl.metadata.get('title') # no_wms_layers always contains titles, not ids (=names) if title in no_wms_layers: continue uid = xml2.text(el, 'id') if use_layer_ids: name = uid else: name = xml2.text(el, 'shortname') or xml2.text(el, 'layername') sl.title = title sl.name = name sl.metadata.set('name', name) map_layers[uid] = sl return map_layers
def service_metadata(root_el: gws.XmlElement) -> gws.lib.metadata.Metadata: # wms # # <Capabilities # <Service... # <Name>... # <Title>... # <ContactInformation>... # # ows # # <Capabilities # <ows:ServiceIdentification> # <ows:Title>.... # <ows:ServiceProvider> # <ows:ProviderName>... # <ows:ServiceContact>... d = _metadata_dict(xml2.first(root_el, 'Service', 'ServiceIdentification')) d.update(_contact_dict(root_el)) d['contactProviderName'] = xml2.text(root_el, 'ServiceProvider ProviderName') d['contactProviderSite'] = xml2.text(root_el, 'ServiceProvider ProviderSite') # <Capabilities # <ServiceMetadataURL link = _parse_link(xml2.first(root_el, 'ServiceMetadataURL')) if link: d['metaLinks'] = [link] return gws.lib.metadata.from_dict(gws.strip(d))
def _f_GeoBAK(el: gws.XmlElement, fallback_crs, **kwargs): # GeoBAK (https://www.egovernment.sachsen.de/geodaten.html) # # <geobak_20:Sachdatenabfrage... # <geobak_20:Kartenebene>.... # <geobak_20:Inhalt> # <geobak_20:Datensatz> # <geobak_20:Attribut> # <geobak_20:Name>... # <geobak_20:Wert>... # <geobak_20:Inhalt> # <geobak_20:Datensatz> # ... # if not xml2.element_is(el, 'Sachdatenabfrage'): return None features = [] layer_name = xml2.text(el, 'Kartenebene') for content_el in xml2.all(el, 'Inhalt'): for feature_el in xml2.all(content_el, 'Datensatz'): atts = { xml2.text(a, 'Name').strip(): xml2.text(a, 'Wert').strip() for a in xml2.all(feature_el, 'Attribut') } features.append( gws.gis.feature.from_args(category=layer_name, attributes=atts)) return features
def _layer(el: gws.XmlElement, parent: t.Optional[gws.SourceLayer] = None) -> gws.SourceLayer: sl = gws.SourceLayer() sl.is_queryable = xml2.attr(el, 'queryable') == '1' sl.is_visible = True sl.metadata = u.element_metadata(el) sl.name = sl.metadata.get('name', '') sl.styles = [u.parse_style(e) for e in xml2.all(el, 'Style')] sl.supported_bounds = u.supported_bounds(el) sl.title = sl.metadata.get('title', '') if not sl.name: # some folks have unnamed layers in their caps # we can't render or query them sl.is_queryable = False sl.is_image = False # @TODO: support ScaleHint (WMS 1.1) smin = xml2.text(el, 'MinScaleDenominator') smax = xml2.text(el, 'MaxScaleDenominator') if smax: sl.scale_range = [u.to_int(smin), u.to_int(smax)] # OGC 06-042, 7.2.4.8 Inheritance of layer properties if parent: crs = set(b.crs for b in sl.supported_bounds) for b in parent.supported_bounds: if b.crs not in crs: sl.supported_bounds.append(b) names = set(s.name for s in sl.styles) for s in parent.styles: if s.name not in names: sl.styles.append(s) sl.metadata.extend(parent.metadata) sl.layers = [_layer(e, sl) for e in xml2.all(el, 'Layer')] sl.is_group = len(sl.layers) > 0 sl.is_image = len(sl.layers) == 0 sl.default_style = u.default_style(sl.styles) if sl.default_style: sl.legend_url = sl.default_style.legend_url return sl
def _tile_matrix_set(el: gws.XmlElement): # <TileMatrixSet> # <ows:Identifier>... # <ows:SupportedCRS>... # <TileMatrix> # ... tms = gws.TileMatrixSet() tms.uid = xml2.text(el, 'Identifier') tms.crs = gws.gis.crs.require(xml2.text(el, 'SupportedCRS')) tms.matrices = sorted( [_tile_matrix(e) for e in xml2.all(el, 'TileMatrix')], key=lambda m: int('1' + m.uid)) return tms
def _metadata_dict(el: gws.XmlElement) -> dict: if not el: return {} d = { 'abstract': xml2.text(el, 'Abstract'), 'accessConstraints': xml2.text(el, 'AccessConstraints'), 'attribution': xml2.text(el, 'Attribution Title'), 'fees': xml2.text(el, 'Fees'), 'keywords': xml2.text_list(el, 'Keywords', 'KeywordList', deep=True), 'name': xml2.text(el, 'Name') or xml2.text(el, 'Identifier'), 'title': xml2.text(el, 'Title'), 'metaLinks': gws.compact(_parse_link(e) for e in xml2.all(el, 'MetadataURL')), } e = xml2.first(el, 'AuthorityURL') if e: d['authorityUrl'] = _parse_url(e) d['authorityName'] = xml2.attr(e, 'name') e = xml2.first(el, 'Identifier') if e: d['authorityIdentifier'] = e.text return gws.strip(d)
def _layer(el: gws.XmlElement, tms_map): # <Layer> # <ows:Title>... # <Style>... # <Format>... # <TileMatrixSetLink> # <TileMatrixSet>... sl = gws.SourceLayer() sl.metadata = u.element_metadata(el) sl.name = sl.metadata.get('name', '') sl.title = sl.metadata.get('title', '') sl.styles = [u.parse_style(e) for e in xml2.all(el, 'Style')] sl.default_style = u.default_style(sl.styles) if sl.default_style: sl.legend_url = sl.default_style.legend_url sl.tile_matrix_ids = [ xml2.text(e, 'TileMatrixSet') for e in xml2.all(el, 'TileMatrixSetLink') ] sl.tile_matrix_sets = [tms_map[tid] for tid in sl.tile_matrix_ids] extra_crsids = [tms.crs.srid for tms in sl.tile_matrix_sets] sl.supported_bounds = u.supported_bounds(el, extra_crsids) sl.is_image = True sl.is_visible = True sl.image_format = xml2.text(el, 'Format') sl.resource_urls = { xml2.attr(e, 'resourceType'): xml2.attr(e, 'template') for e in xml2.all(el, 'ResourceURL') } return sl
def _map_layer(layer_el: gws.XmlElement): sl = gws.SourceLayer() sl.metadata = _map_layer_metadata(layer_el) sl.supported_bounds = [] crs = gws.gis.crs.get(xml2.text(layer_el, 'srs spatialrefsys authid')) ext = xml2.first(layer_el, 'extent') if crs and ext: sl.supported_bounds.append( gws.Bounds(crs=crs, extent=( _parse_float(xml2.text(ext, 'xmin')), _parse_float(xml2.text(ext, 'ymin')), _parse_float(xml2.text(ext, 'xmax')), _parse_float(xml2.text(ext, 'ymax')), ))) if layer_el.attributes.get('hasScaleBasedVisibilityFlag') == '1': # in qgis, maxScale < minScale a = _parse_float(layer_el.attributes.get('maxScale')) z = _parse_float(layer_el.attributes.get('minScale')) if z > a: sl.scale_range = [a, z] prov = xml2.text(layer_el, 'provider').lower() ds = _parse_datasource(prov, xml2.text(layer_el, 'datasource')) if ds and 'provider' not in ds: ds['provider'] = prov sl.data_source = ds s = xml2.text(layer_el, 'layerOpacity') if s: sl.opacity = _parse_float(s) s = xml2.text(layer_el, 'flags Identifiable') sl.is_queryable = s == '1' return sl
def _parse_link(el: gws.XmlElement) -> t.Optional[gws.MetadataLink]: # <MetadataURL type="... # <Format... # <OnlineResource... if not el: return None d = gws.strip({ 'url': _parse_url(el), 'type': xml2.attr(el, 'type'), 'formatName': xml2.text(el, 'Format'), }) if d: return gws.MetadataLink(d)
def _parse_bbox(el: gws.XmlElement): # note: bboxes are always converted to (x1, y1, x2, y2) with x1 < x2, y1 < y2 # <BoundingBox/LatLonBoundingBox CRS="..." minx="0" miny="1" maxx="2" maxy="3"/> if xml2.attr(el, 'minx'): return [ to_float(xml2.attr(el, 'minx')), to_float(xml2.attr(el, 'miny')), to_float(xml2.attr(el, 'maxx')), to_float(xml2.attr(el, 'maxy')), ] # <ows:BoundingBox/WGS84BoundingBox # <ows:LowerCorner> 0 1 # <ows:UpperCorner> 2 3 if xml2.first(el, 'LowerCorner'): x1, y1 = to_float_pair(xml2.text(el, 'LowerCorner')) x2, y2 = to_float_pair(xml2.text(el, 'UpperCorner')) return [ min(x1, x2), min(y1, y2), max(x1, x2), max(y1, y2), ] # <EX_GeographicBoundingBox> # <westBoundLongitude> 0 # <eastBoundLongitude> 2 # <southBoundLatitude> 1 # <northBoundLatitude> 3 if xml2.first(el, 'westBoundLongitude'): x1 = to_float(xml2.text(el, 'eastBoundLongitude')) y1 = to_float(xml2.text(el, 'southBoundLatitude')) x2 = to_float(xml2.text(el, 'westBoundLongitude')) y2 = to_float(xml2.text(el, 'northBoundLatitude')) return [ min(x1, x2), min(y1, y2), max(x1, x2), max(y1, y2), ]
def parse(xml: str) -> Caps: root_el = xml2.from_string(xml, sort_atts=True, strip_ns=True, to_lower=True) ver = root_el.attributes.get('version', '').split('-')[0] if not ver.startswith('3'): raise gws.Error(f'unsupported QGIS version {ver!r}') caps = Caps(version=ver) caps.properties = _properties(xml2.first(root_el, 'properties')) caps.metadata = _project_meta_from_props(caps.properties) caps.project_crs = gws.gis.crs.get( xml2.text(root_el, 'projectCrs spatialrefsys authid')) caps.print_templates = _layouts(root_el) map_layers = _map_layers(root_el, caps.properties) root_group = _map_layer_tree(xml2.first(root_el, 'layer-tree-group'), map_layers) caps.source_layers = gws.gis.source.check_layers(root_group.layers) return caps
def _tile_matrix(el: gws.XmlElement): # <TileMatrix> # <ows:Identifier> # <ScaleDenominator> # ... tm = gws.TileMatrix() tm.uid = xml2.text(el, 'Identifier') tm.scale = u.to_float(xml2.text(el, 'ScaleDenominator')) p = u.to_float_pair(xml2.text(el, 'TopLeftCorner')) tm.x = p[0] tm.y = p[1] tm.width = u.to_int(xml2.text(el, 'MatrixWidth')) tm.height = u.to_int(xml2.text(el, 'MatrixHeight')) tm.tile_width = u.to_int(xml2.text(el, 'TileWidth')) tm.tile_height = u.to_int(xml2.text(el, 'TileHeight')) tm.extent = _extent_for_matrix(tm) return tm
def tx(s): return xml2.text(layer_el, s)