This Jupyter notebook can be used to generate a template using a WMS Server.
Click on the cell below and click on "Run" to import the necessary libraries.
import xml.etree.ElementTree as ET
from io import StringIO
import requests
from collections import OrderedDict
import json
from urllib.parse import urlparse, parse_qsl, urlencode, urlunparse
def parse_wms(xml):
""" Rudimentary parsing of WMS Layers from GetCapabilites Request
owslib.wms seems to have problems parsing some weird not relevant metadata.
This function aims at only parsing relevant layer metadata
"""
wms = {}
try:
it = ET.iterparse(StringIO(xml))
for _, el in it:
prefix, has_namespace, postfix = el.tag.partition('}')
if has_namespace:
el.tag = postfix
root = it.root
except:
raise RuntimeError("Could not parse XML.")
root_tag = root.tag.rpartition("}")[-1]
if root_tag in {'ServiceExceptionReport', 'ServiceException'}:
raise RuntimeError("WMS service exception")
if root_tag not in {'WMT_MS_Capabilities', 'WMS_Capabilities'}:
raise RuntimeError("No Capabilities Element present: Root tag: {}".format(root_tag))
if 'version' not in root.attrib:
raise RuntimeError("WMS version cannot be identified.")
version = root.attrib['version']
wms['version'] = version
layers = {}
def parse_layer(element, crs=set(), styles={}):
new_layer = {'CRS': crs,
'Styles': {}}
new_layer['Styles'].update(styles)
for tag in ['Name', 'Title', 'Abstract']:
e = element.find("./{}".format(tag))
if e is not None:
new_layer[e.tag] = e.text
for tag in ['CRS', 'SRS']:
es = element.findall("./{}".format(tag))
for e in es:
new_layer["CRS"].add(e.text.upper())
for tag in ['Style']:
es = element.findall("./{}".format(tag))
for e in es:
new_style = {}
for styletag in ['Title', 'Name']:
new_style[styletag] = e.find("./{}".format(styletag)).text
new_layer["Styles"][new_style['Name']] = new_style
if 'Name' in new_layer:
layers[new_layer['Name']] = new_layer
for sl in element.findall("./Layer"):
parse_layer(sl,
new_layer['CRS'].copy(),
new_layer['Styles'])
# Find child layers. CRS and Styles are inherited from parent
top_layers = root.findall(".//Capability/Layer")
for top_layer in top_layers:
parse_layer(top_layer)
wms['layers'] = layers
# Parse formats
formats = []
for es in root.findall(".//Capability/Request/GetMap/Format"):
formats.append(es.text)
wms['formats'] = formats
return wms
Update wms_url in the following cell. Then activate the cell and click on "Run".
wms_url = 'https://wms.zh.ch/OGDLidarZH?SERVICE=WMS&Request=GetCapabilities'
Next, activate the following cell and click on "Run". At the end of the cell you can then select the required properties of the service.
wms_args = {}
u = urlparse(wms_url)
url_parts = list(u)
for k, v in parse_qsl(u.query):
wms_args[k.lower()] = v
def get_getcapabilitie_url():
get_capabilities_args = {'service': 'WMS',
'request': 'GetCapabilities'}
if 'version' in wms_args:
get_capabilities_args['version'] = wms_args['version']
# Some server only return capabilities when the map parameter is specified
if 'map' in wms_args:
get_capabilities_args['map'] = wms_args['map']
url_parts[4] = urlencode(list(get_capabilities_args.items()))
return urlunparse(url_parts)
url = get_getcapabilitie_url()
r = requests.get(url)
xml = r.text
wms = parse_wms(xml)
print("Layers:")
layers = list(wms['layers'].keys())
for i, layer in enumerate(layers):
print("{}: {} ({})".format(i,
layers[i],
wms['layers'][layer]['Title']))
print(" ")
selected_layer_idx = int(input("Select Layer: "))
print(" ")
assert 0 <= selected_layer_idx < len(layers)
selected_layer = layers[selected_layer_idx]
description = ''
if 'Abstract' in wms['layers'][selected_layer]:
description = wms['layers'][selected_layer]['Abstract']
layer_title = ''
if 'Title' in wms['layers'][selected_layer]:
layer_title = wms['layers'][selected_layer]['Title']
crs_options = wms['layers'][selected_layer]['CRS']
styles = list(wms['layers'][selected_layer]['Styles'].keys())
selected_style = None
if len(styles) > 0:
print("Styles:")
for i, style in enumerate(styles):
print("{}: {} ({})".format(i, style, (wms['layers'][selected_layer]['Styles'][style]['Title'])))
print(" ")
selected_style_idx = int(input("Select Style: "))
print(" ")
assert 0 <= selected_style_idx < len(styles)
selected_style = styles[selected_style_idx]
else:
selected_style = ''
print("Image formats:")
format_options = wms['formats']
for i, format_option in enumerate(format_options):
print("{}: {}".format(i, format_option))
print(" ")
selected_format_idx = int(input("Select Format: "))
print(" ")
assert 0 <= selected_format_idx < len(format_options)
selected_format = format_options[selected_format_idx]
wms_paramters = {}
wms_paramters['LAYERS'] = selected_layer
if selected_style is not None:
wms_paramters['STYLES'] = selected_style
wms_paramters['FORMAT'] = selected_format
wms_paramters['CRS'] = '{proj}'
wms_paramters['WIDTH'] = '{width}'
wms_paramters['HEIGHT'] = '{height}'
wms_paramters['BBOX'] = '{bbox}'
wms_paramters['VERSION'] = wms['version']
wms_paramters['SERVICE'] = 'WMS'
wms_paramters['REQUEST'] = 'GetMap'
baseurl = wms_url.split("?")[0]
service_url = baseurl + "?" + "&".join(["{}={}".format(key, value) for key, value in wms_paramters.items()])
result = OrderedDict()
result['type'] = 'Feature'
result['properties'] = OrderedDict()
result['properties']['name'] = layer_title
result['properties']['type'] = 'wms'
result['properties']['url'] = service_url
result['properties']['license_url'] = ''
result['properties']['privacy_policy_url'] = ''
result['properties']['id'] = ''
result['properties']['description'] = description
result['properties']['country_code'] = ''
result['properties']['best'] = False
result['properties']['start_date'] = ''
result['properties']['end_date'] = ''
result['properties']['category'] = ''
result['properties']['available_projections'] = list(crs_options)
result['properties']['attribution'] = {'url': '',
'text': '',
'html': '',
'required': True}
result['geometry'] = ''
print("")
print("Copy the following output:")
print("-------------------------")
print(json.dumps(result,
indent=4,
sort_keys=False))
print("-------------------------")
Layers: 0: OGDLidarZH (Digitale Höhenmodelle 2014 ZH) 1: dtm2014hillshade (Terrainschummerung) 2: dom2014hillshade (Oberflächenschummerung) 3: blatteinteilung-lidar (Blatteinteilung Lidar) 4: blatteinteilung-dtm (Digitales Terrain Modell (DTM)/Digitales Oberflächenmodell (DOM)) 5: gemeindegrenzen (Gemeindegrenzen) 6: blatteinteilung-labels_lidar (LIDAR Beschriftung) 7: blatteinteilung-labels_dtm (DTM/DOM Beschriftung) Select Layer: 1 Image formats: 0: image/png 1: image/jpeg 2: image/png; mode=8bit 3: application/x-pdf 4: image/svg+xml 5: image/tiff 6: application/vnd.google-earth.kml+xml 7: application/vnd.google-earth.kmz Select Format: 1 Copy the following output: ------------------------- { "type": "Feature", "properties": { "name": "Terrainschummerung", "type": "wms", "url": "https://wms.zh.ch/OGDLidarZH?LAYERS=dtm2014hillshade&STYLES=&FORMAT=image/jpeg&CRS={proj}&WIDTH={width}&HEIGHT={height}&BBOX={bbox}&VERSION=1.3.0&SERVICE=WMS&REQUEST=GetMap", "license_url": "", "privacy_policy_url": "", "id": "", "description": "", "country_code": "", "best": false, "start_date": "", "end_date": "", "category": "", "available_projections": [ "EPSG:31297", "EPSG:21782", "EPSG:2056", "EPSG:21781", "EPSG:21780", "EPSG:4326", "EPSG:4258", "EPSG:3857" ], "attribution": { "url": "", "text": "", "html": "", "required": true } }, "geometry": "" } -------------------------