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