08 June 2014

Chris Herwig erkennt drei Hauptgruppen von Open Government Daten Benutzer:

  1. Gelegenheitsuser

  2. Benutzer, die mittels einer API Zugriff auf die Daten wünschen.

  3. «Bulk»-Datenuser: Diese User wollen grosse Datenmengen (und auch komplette Datensätze) herunterladen.

Ein möglicher technischer Umsetzungsansatz ist das Verbinden von Gruppe 2 und 3. Der Webdienst von Gruppe 2 wird verwendet, um die vorgefertigten Datensätze für Gruppe 3 herzustellen.

Anlass für das Rumspielen war ebenfalls das neue Geodatenformat Geopackage, das seit Version 1.11 in GDAL/OGR unterstützt wird. Da QGIS ebenfalls GDAL/OGR einsetzt, wird das Datenformat auch in QGIS unterstützt.

Als Webdienst wird der MOpublic-WFS verwendet. Das Herstellen der einzelnen Datensätze/Geopackages übernimmt ein kleines Pythonskript:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import os
import osgeo.gdal
from osgeo import ogr


# VARS
GPKG_DIR = "/opt/Geodaten/ch/so/kva/av/mopublic/gpkg/lv03/d/"

# Enable exceptions
ogr.UseExceptions()

# Get all the layer names
layer_list = []
driver = ogr.GetDriverByName('WFS')
ds_mopublic = driver.Open("WFS:http://www.catais.org/wfs/mopublic?")

for i in range(0, ds_mopublic.GetLayerCount()):
    layer = ds_mopublic.GetLayerByIndex(i)
    layer_list.append(layer.GetName())

ds_mopublic.Destroy()

# Export new deliveries
ds_lieferungen = driver.Open("WFS:http://www.catais.org/wfs/av_lieferungen?")
layer_lieferungen = ds_lieferungen.GetLayerByName('lieferungen_heute')

for feature in layer_lieferungen:
    gem_bfs = feature.GetField('gem_bfs')

    out = os.path.join(GPKG_DIR, str(gem_bfs) + ".gpkg")
    out_driver = ogr.GetDriverByName("GPKG")

    if os.path.exists(out):
        out_driver.DeleteDataSource(out)

    out_datasource = out_driver.CreateDataSource(out)

    filter = "&FILTER=%3Cogc:Filter%20xmlns:ogc=%22http://www.opengis.net/ogc%22%3E%0A%20%3Cogc:PropertyIsEqualTo%3E%0A%20%20%3Cogc:PropertyName%3Ebfsnr%3C/ogc:PropertyName%3E%0A%20%20%3Cogc:Literal%3E" + str(gem_bfs) + "%3C/ogc:Literal%3E%0A%20%3C/ogc:PropertyIsEqualTo%3E%0A%3C/ogc:Filter%3E%0A"

    for i in range(len(layer_list)):
        wfs_string = "WFS:http://www.catais.org/wfs/mopublic?TYPENAME" + layer_list[i] + filter
        ds_mopublic = driver.Open(wfs_string)
        layer_mopublic = ds_mopublic.GetLayerByName(layer_list[i])
        out_layer = out_datasource.CopyLayer(layer_mopublic, layer_list[i])

        ds_mopublic.Destroy()

ds_lieferungen.Destroy()


# Export whole canton
ds_mopublic = driver.Open("WFS:http://www.catais.org/wfs/mopublic?")

out = os.path.join(GPKG_DIR,  "kanton.gpkg")
out_driver = ogr.GetDriverByName("GPKG")

if os.path.exists(out):
    out_driver.DeleteDataSource(out)

out_datasource = out_driver.CreateDataSource(out)

for i in range(len(layer_list)):
    layer_mopublic = ds_mopublic.GetLayerByName(layer_list[i])
    out_layer = out_datasource.CopyLayer(layer_mopublic, layer_list[i])

ds_mopublic.Destroy()

Zeile 16 - 24: Es werden zuerst alle Layernamen des WFS in eine Liste geschrieben. Diese Layer werden später gemeindeweise angefordert und als GeoPackage gespeichert.

Zeile 27 - 28: Ein weiterer WFS liefert die neuen Datenlieferungen (Gemeinden, die heute Nacht geliefert wurden).

Zeile 30 - 49: Die Layer werden nun gemeindeweise angefordert und pro Gemeinde in eine GeoPackage-Datei gespeichert.

OGR hat eine Methode layer.SetAttributeFilter("gem_bfs = 2549"), die Datensätze nach Attribute filtern kann. Dies funktioniert beim OGR-WFS-Treiber entweder auf der Serverseite (bevorzugt) oder auf der Klientenseite. Da QGIS-Server (hier als WFS-Server eingesetzt) in der GetCapabilities-Antwort die «LogicalOperators» nicht auflistet, sie aber versteht, verwendet OGR nur das klientenseitige Filtern. Das hat zur Folge, dass zuerst immer sämtliche Daten vom Server geholt werden müssen. Um dies zu verhindern, kann der Filter direkt in der URL angegeben werden (Zeile 41 und 44/45).

Zeile 55 - 69: Nach dem gemeindeweisen Erstellen der GeoPackages wird ein GeoPackage für den ganzen Kanton Solothurn erstellt.

Funktionierts?

Das Skript lokal ausgeführt braucht circa 1.5 Stunden für das Erstellen sämtlicher 109 Gemeinden. Das Skript auf dem gleichen Server ausgeführt, auf dem der WFS läuft, dauert länger (circa 2.5 Stunden). Der lokale Rechner hat im Gegensatz zum Server eine SSD. Eventuell kann das ein Flaschenhals sein. Interessanterweise macht die kürzere Downloadzeit das nicht wett.

Laden, Zoomen und Pannen funktioniert in QGIS 2.3 (kompiliert mit GDAL/OGR 2.0.0dev) tadellos und sehr schnell. Einzig das Scrollen in der Attributtabelle ist einiges zäher und käsiger als mit Postgis.

Die Daten können hier heruntergeladen werden.

Posted by Stefan Ziegler. | Downloaddienst , Webdienst , Bulkdownload , WFS , OGR , GeoPackage , QGIS , Amtliche-Vermessung