KAIandClaude Opus 5.5 8253f4f863 Fassung 0.7.1: Liste der Geodienste gehoert zur Auswahl
Nach einem Wechsel von Verfahren oder Landkreis blieb die geholte Liste
stehen; "Ausgewaehlte laden" lud sie dann unter dem Namen der neuen
Auswahl. Jetzt merkt sich die Seitenleiste, fuer welche Auswahl die
Liste geholt wurde, und leert sie bei jedem Wechsel (auch beim stillen
Wiederherstellen aus der Projektdatei). Ein Filter, der die Auswahl
behaelt, laesst sie stehen. Die Meldung nach "Liste holen" nennt beim
Landkreis den Landkreis statt "dieses Verfahren".

Gefunden am 07.10.2026 bei der Aufnahme des Erklaervideos Linkliste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:12:29 +02:00

API_Karte_QGISDemo — Beispiel: Karten-API des VLN Managers aus QGIS ansteuern

Dieses Repository zeigt an einem lauffähigen QGIS-Plugin, wie die Karten-API des VLN Managers (https://api.flurneuordnung-sachsen.de/v2) aus QGIS bzw. PyQGIS angesteuert wird: Anmeldung, Laden der Verfahrens-Layer als editierbare QGIS-Layer und Zurückschreiben der Änderungen. Es liest und schreibt dieselben Daten, die auch das Web-GIS (karte.flurneuordnung-sachsen.de) verwendet.

Der Code ist bewusst als Referenz-Implementierung gehalten — wer eine eigene Integration (Plugin, Skript, Processing-Werkzeug) bauen will, findet hier alle Bausteine.

Die Ansteuerung in Kürze

So sieht der minimale Ablauf in PyQGIS aus (vollständige, robuste Fassung in vln_karten/api_client.py):

import json
from qgis.PyQt.QtCore import QUrl
from qgis.PyQt.QtNetwork import QNetworkRequest
from qgis.core import QgsBlockingNetworkRequest

BASE = "https://api.flurneuordnung-sachsen.de/v2"

def request(method, path, payload=None, api_key=None):
    req = QNetworkRequest(QUrl(BASE + path))
    req.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, "application/json")
    if api_key:
        req.setRawHeader(b"X-API-Key", api_key.encode())
    blk = QgsBlockingNetworkRequest()
    body = json.dumps(payload).encode() if payload is not None else b""
    getattr(blk, method)(req, *([body] if method != "get" else []))
    return json.loads(bytes(blk.reply().content()) or b"null")

# 1) Login: liefert das userauth-Token = API-Key
login = request("post", "/person/login",
                {"mail": "...", "password": "..."})
api_key = login["data"]["userauth"]

# 2) Layer lesen: GeoJSON FeatureCollection in EPSG:25833
fc = request("get", "/maps/p41?vkz=22017&limit=2000&offset=0",
             api_key=api_key)

# 3) Layer schreiben: PUT ersetzt den kompletten Bestand dieser VKZ!
request("put", "/maps/p41/22017", payload=fc, api_key=api_key)

Die drei Stolpersteine, die das Beispiel-Plugin jeweils sauber löst:

  1. CRS: Die API liefert/erwartet EPSG:25833 (ETRS89/UTM33), nicht WGS84 wie in RFC 7946 üblich. GeoJSON-Export aus QGIS daher mit QgsJsonExporter.setTransformGeometries(False).
  2. Gemischte Geometrietypen: Eine FeatureCollection kann Punkte, Linien und Flächen zugleich enthalten — QGIS-Layer können das nicht. Über die OGC API stellt sich die Frage nicht mehr: der Server bietet je Sammlung drei Familien an (-punkt, -linie, -flaeche), und jede wird ein eigener Layer.
  3. PUT ersetzt alles: Der Schreibendpunkt legt einen neuen Snapshot an und ersetzt den kompletten Layer-Bestand der VKZ. Immer den vollständigen Datensatz senden — Teilmengen löschen den Rest serverseitig.

API-Kommunikation

POST /person/login
  Body:     {"mail": "...", "password": "..."}
  Antwort:  {"data": {"userauth": "<url_token>", "id": ...}}
  userauth = API-Key, danach Header "X-API-Key: <userauth>"

GET  /tgen                              Verfahren/TGs (Auth nötig)

GET  /maps/<layer>?vkz=&limit=&offset=  Layer lesen, mit Paging
GET  /maps/<layer>/{vkz}                Layer lesen, ohne Paging
  layer:    umringe | p41 | st | kas | we
  Auth:     umringe/p41/st öffentlich, kas/we mit X-API-Key
  Antwort:  GeoJSON FeatureCollection in EPSG:25833

PUT  /maps/<layer>/{vkz}                Layer schreiben (Auth nötig)
  Body:     GeoJSON (ersetzt den Layer dieser VKZ, neuer Snapshot)
  Antwort:  {"data": {"vkz","layer","art","speicher_id"}, "status":"ok"}

Fehlerformat: RFC 7807 (application/problem+json)
Leerer vkz-Parameter (?vkz=) wird mit HTTP 400 abgelehnt.

OGC API Features — laden, bearbeiten, zurückspeichern (empfohlen)

Seit dem 07.09.2026 spricht die API OGC API Features (Part 1 Core, Part 2 CRS, Part 3 Queryables, Part 4 CRUD) unter https://api.flurneuordnung-sachsen.de/v2/ogc. Das ist der Weg für alle, die nur einen Manager-Login haben: QGIS lädt die Layer nativ, und jede Änderung im Bearbeitungsmodus geht beim Speichern einzeln an die API (POST/PUT/PATCH/DELETE je Feature) — kein Vollersetzen, kein Memory-Layer.

Ohne Plugin (QGIS 3.28+ / QGIS 4)

  1. Layer → Datenquellenverwaltung → WFS / OGC API - Features → Neu

    • Name: VLN Manager, URL: https://api.flurneuordnung-sachsen.de/v2/ogc
    • Version: OGC API - Features
    • Authentifizierung: Basic (E-Mail + Passwort des Managers) — oder Methode API-Header mit X-API-Key (Wert = userauth aus POST /person/login bzw. ein vlnk_…-Schlüssel aus meinVLN → API-Keys)
  2. Verbinden → die Sammlungen des eigenen Verfahrens erscheinen, z. B.

    Sammlung Inhalt Speicher-CRS
    umringe-27998-flaeche, p41-…, st-…, kas-…, we-…, ngg-…, biotop-… jüngster Stand des Layers (wie im Web-GIS) EPSG:25833
    `vorerhebung-27998--punkt -linie -flaeche`
    `massnahmeblatt-27998-linie -flaeche -punkt`

    Jede Sammlung gibt es je Geometriefamilie (-punkt, -linie, -flaeche): QGIS-Layer sind eintypig, die Stände des Web-GIS mischen Punkte, Linien und Flächen. Die Queryables nennen je Familie den Geometrietyp und die Felder — so lassen sich auch leere Layer direkt bearbeiten. Die Basis ohne Suffix (st-27998) ist nicht gelistet, aber lesbar.

  3. Layer hinzufügen → Bearbeitungsmodus → zeichnen/ändern → Layer-Änderungen speichern. QGIS schickt Content-Crs mit; die API rechnet in PostGIS um (EPSG:25833 ↔ CRS84).

Wer nur seine Verfahren sieht: Vorsitz, Kassenbetreuer und Stellvertreter der TG; Verbandsmitarbeiter alle (?vkz= in /ogc/collections grenzt ein).

Mit dem Plugin

Knopf „Layer laden" in der Seitenleiste: legt nach dem Login eine QGIS-Authentifizierungskonfiguration API-Header (X-API-Key) an — das Passwort bleibt draußen —, holt GET /ogc/collections?vkz=… und hängt jede Sammlung als OAPIF-Layer in eine Gruppe „VLN " (Untergruppen Vorerhebung / Maßnahmenblätter / Verfahren). Code: vln_karten/ogc_layers.py.

from qgis.core import QgsDataSourceUri, QgsVectorLayer
uri = QgsDataSourceUri()
uri.setParam("url", "https://api.flurneuordnung-sachsen.de/v2/ogc")
uri.setParam("typename", "p41-27998-flaeche")
uri.setParam("pagingEnabled", "true")
uri.setParam("srsname", "EPSG:25833")
uri.setAuthConfigId("<authcfg-id>")          # APIHeader (X-API-Key) oder Basic
layer = QgsVectorLayer(uri.uri(False), "Plan 41 · 27998 · Flächen", "OAPIF")

Wenn das Laden quälend langsam ist

Nicht die API: ein System-Proxy (PAC-Datei), den macOS nicht ausführen kann, lässt jede Qt-Anfrage in einen Timeout laufen (~10 s statt 0,3 s) — QGIS wirkt dann hängend, obwohl der Server jede Anfrage mit 200 beantwortet. Prüfen und abschalten:

networksetup -getautoproxyurl Wi-Fi          # Enabled: Yes + unerreichbare .pac-Datei?
networksetup -setautoproxystate Wi-Fi off    # nur wenn im Netz kein Proxy nötig ist

In der QGIS-Meldungsleiste steht dann Execution of PAC script … failed (…-1002).

Stile (QML) — mitgeladen und zurückspeicherbar

Jede Sammlung hat einen Stil: GET …/collections/{cid}/style.qml. Der Server liefert den für die Sammlung gespeicherten Stil, sonst die Vorlage der Art (kas-*-flaeche gilt für die Karte alter Stand aller Verfahren), sonst einen erzeugten Standard — kategorisiert nach typ mit den Farben des Web-GIS (Wege dunkel, Wasser blau, Ökologie grün, Problemstellen rot).

  • Plugin: wendet den Stil beim Laden automatisch an. Der Knopf „Stil des aktiven Layers speichern“ in der Seitenleiste schreibt den in QGIS eingestellten Stil zurück; mit dem Häkchen „als Vorlage für alle Verfahren“ (oder gedrückter Umschalttaste) gilt er für die ganze Art.
  • Ohne Plugin: Layer → Eigenschaften → Stil → Stil laden … bzw. die QML-Datei von der URL holen. Zurückschreiben geht per PUT (z. B. curl -T stil.qml -H "X-API-Key: …").
  • Berechtigung: Lesen darf jeder, der die Sammlung sieht. Speichern und Löschen nur Verbandsmitarbeiter oder Mitglieder der Gruppe MODUL_KARTENSTIL; sonst HTTP 403. Ob der eigene Zugang darf, steht in der Sammlung als vln:styleWritable und in der Kopfzeile X-Stil-Schreibbar der QML-Antwort.
GET    /ogc/collections/{cid}/style.qml             Stil (Kopfzeile X-Stil-Quelle: sammlung|vorlage|standard)
PUT    /ogc/collections/{cid}/style.qml[?vorlage=1] Stil speichern (Gruppe MODUL_KARTENSTIL)
DELETE /ogc/collections/{cid}/style.qml[?vorlage=1] gespeicherten Stil entfernen

Regeln beim Schreiben

  • Geometriefamilie: in …-punkt nur Punkte, in …-linie nur Linien, in …-flaeche nur Flächen (sonst HTTP 400).
  • Verfahrens-Layer: Änderungen landen in place im jüngsten Stand; fehlt ein Stand, legt der erste Schreibzugriff ihn an. Das Web-GIS speichert weiterhin als neuer Stand — beide treffen sich am jüngsten.
  • Vorerhebung: nur Status „bearbeitung" ist schreibbar (sonst HTTP 423).
  • Maßnahmenblatt: fid = <Blatt-UUID>:<n>. Neues Feature mit blatt_uuid hängt eine Geometrie an ein Blatt; mit blatt_typ (pflanzung|wasserbau|wegebau|entsiegelung) + blatt_name (+ blatt_mkz) entsteht ein neues Blatt. blatt_*-Attribute ändern die Blatt-Spalten, alles andere die Geometrie-Eigenschaften.
  • Fehler kommen als RFC 7807 (application/problem+json); ohne Anmeldung 401 mit WWW-Authenticate: Basic — QGIS fragt dann selbst nach dem Login.
GET  /ogc                          Landing Page (öffentlich)
GET  /ogc/conformance              Konformitätsklassen (öffentlich)
GET  /ogc/collections[?vkz=]       Sammlungen des Nutzers
GET  /ogc/collections/{cid}        Sammlung: crs, storageCrs, extent
GET  /ogc/collections/{cid}/queryables
GET  /ogc/collections/{cid}/items  ?limit&offset&bbox&bbox-crs&crs   → FeatureCollection
GET  /ogc/collections/{cid}/items/{fid}
POST /ogc/collections/{cid}/items          Feature | FeatureCollection → 201 {ids}
PUT  /ogc/collections/{cid}/items/{fid}    → 204
PATCH /ogc/collections/{cid}/items/{fid}   Eigenschaften mergen, Geometrie optional → 204
DELETE /ogc/collections/{cid}/items/{fid}  → 204
CRS-URIs: http://www.opengis.net/def/crs/OGC/1.3/CRS84 (Vorgabe),
          http://www.opengis.net/def/crs/EPSG/0/25833

Verifiziert mit QGIS 4.2 (headless)

tools/headless_ogc_test.py treibt das installierte QGIS ohne Oberfläche (PyQGIS, QT_QPA_PLATFORM=offscreen) gegen die API: Layer laden, Feature anlegen, Attribut und Geometrie ändern, löschen — für einen Verfahrens-Layer und ein Maßnahmenblatt, jeder Schritt per API gegengeprüft. Stand 07.09.2026: 0 Fehler mit QGIS 4.2.0. Was QGIS dafür vom Server braucht (und die API liefert): service-desc-Link auf ein OpenAPI-Dokument, Part-5-Schema für Felder/Geometrietyp, OPTIONS …/items mit Allow, PATCH als JSON Merge Patch.

Das Beispiel-Plugin

Das Plugin macht den kompletten Arbeitsablauf in der QGIS-Oberfläche erlebbar:

  • Login beim Start: ohne gespeicherten API-Key zeigt das Plugin nach dem QGIS-Start gleich den Anmeldedialog (E-Mail/Passwort). Der Login liefert das userauth-Token; das Plugin speichert nur dieses Token (QSettings vln_karten/api_key), nie das Passwort, und nutzt es in jeder weiteren Sitzung. „Abmelden“ löscht es.
  • Einmaliger Login (E-Mail/Passwort) — der API-Key wird in den QGIS-Einstellungen gespeichert und über QGIS-Neustarts hinweg wiederverwendet; bei 401 öffnet sich der Anmeldedialog erneut. Ein 403 (angemeldet, aber nicht berechtigt — etwa „nur lesen“) zeigt seit 0.7.0 nur eine Meldung und meldet nicht ab.
  • Seitenleiste rechts (andockbar, seit 08.09.2026 anstelle der Werkzeugleiste): Anmeldung, Auswahl aus GET /tgen/auswahl mit Suchfeld (oben die eigenen Landkreise für die Linkliste, dann die Verfahren; als oFB die des Landkreises mit „nur lesen“), Lade- und Speicherknöpfe, Statuszeile. Wieder einblenden über Web → VLN Karten → Seitenleiste anzeigen.
  • Verfahrens-Auswahl gemerkt je QGIS-Projektdatei.
  • Speichern: über die OGC API schreibt QGIS jede Änderung einzeln zurück (Part 4); der Knopf „Änderungen speichern" schließt die offenen Bearbeitungssitzungen aller geladenen VLN-Layer auf einmal. Der frühere GeoJSON-Weg (ganze Layer laden und als Ganzes hochladen) ist am 08.09.2026 entfallen — samt layer_manager.py und den beiden Client-Methoden dafür.
  • Ladezeit: jede Sammlung kostet beim Anlegen rund eine halbe Sekunde — der OAPIF-Provider fragt Sammlung, Schema, Stil, OPTIONS und die erste Seite ab, nacheinander und blockierend. Zwei Gegenmittel: vorwaermen() holt vorab alle diese Antworten gleichzeitig (unter 1,5 s), und die Häkchen in der Seitenleiste laden nur die gewünschten Gruppen. Gemessen am 08.09.2026 (Berbisdorf, 27 Sammlungen): 20,5 s ohne, 14,2 s mit Vorwärmen; nur Verfahren 11,1 s (21 Layer), nur Vorerhebung oder nur Maßnahmenblätter je 1,6 s (3 Layer). Nicht parallel: ein in einem Python-Thread gebauter OAPIF-Layer stürzt beim ersten getFeatures() ab (Segfault, gemessen) — der Provider gehört dem Thread, der ihn erzeugt hat.
Datei Zweck
vln_karten/plugin.py Ablaufsteuerung: Anmeldung, Laden, Speichern, Hochladen, DATASETS-Registry
vln_karten/panel.py Seitenleiste (Anmeldung, Verfahrensfilter, Knöpfe, Statuszeile)
vln_karten/api_client.py HTTP-Client: Login, Paging-Loader, PUT, RFC-7807-Fehler
vln_karten/ogc_layers.py OGC API Features: Auth-Konfiguration (API-Header), Sammlungen → OAPIF-Layer
vln_karten/login_dialog.py Anmeldedialog
vln_karten/metadata.txt QGIS-Plugin-Metadaten

Geodienste aus der Linkliste

Die Linkliste pflegt der VLN-Manager (/linkliste.py in Ministeriums-, oFB- und meinVLN-Portal, Doku docs/linkliste.md im Repo Erik/VLNManager): landesweit und vom Landkreis (oFB). Team und Teilnehmergemeinschaft sehen sie nur; welche Dienste geladen werden, entscheidet man hier mit den Häkchen (Erik, 06.10.2026).

  • Liste holen ruft GET /linkliste?vkz=… — für ein Verfahren oder, seit 0.7.0, für einen ganzen Landkreis (Eintrag „… — Linkliste des Landkreises“ oben in der Auswahl). Die Liste kommt fertig aufgelöst; je Zeile stehen Name, Gruppe › Untergruppe und Herkunft. Wechselt die Auswahl, leert sich die Liste (seit 0.7.1) — „Liste holen“ holt sie für die neue Auswahl.
  • Ausgewählte laden hängt die angehakten Dienste schrittweise unter „Geodienste “ ein: Gruppe › Untergruppe › Layer (linkliste.zielgruppe); ohne Untergruppe direkt unter die Gruppe. Ein hinterlegter Stil kommt über GET /linkliste/{id}/style.qml.
  • Für Karte (seit 0.7.0): über der Liste je Karte ein Häkchen — Wege- und Gewässerplan, Neugestaltungsgrundsätze, Wertermittlung (Katalog vom Server, GET /linkliste/karten). Eine oder mehrere Karten gewählt: angehakt sind die Dienste, die der Landkreis bzw. die landesweite Pflege dieser Karte zugeordnet hat (linkliste.vorhaken); nachjustieren von Hand bleibt möglich.
  • Anbieter: WMS (QgsRasterLayer), WFS, ArcGIS REST (FeatureServer) und GeoJSON/OGR.
  • Nur lesen: eine oFB sieht die Verfahren ihres Landkreises; deren OGC-Sammlungen tragen vln:schreibbar: false und werden schreibgeschützt geladen (layer.setReadOnly(True)).

Installation

Voraussetzung: QGIS 3.22+ oder QGIS 4 (Qt6/PyQt6 — der Code nutzt scoped Enums und exec()), plus ein VLN-Manager-Konto.

Für Anwender: über das VLN-Plugin-Verzeichnis

Erweiterungen → Erweiterungen verwalten → Einstellungen → Hinzufügen, Name „VLN“, Adresse:

https://api.flurneuordnung-sachsen.de/v2/qgis/plugins.xml

Danach unter Alle nach „VLN Karten“ suchen und installieren (experimentelle Erweiterungen zulassen). Neue Fassungen bietet QGIS von sich aus an. Das Paket baut python3 tools/baue_paket.py; ZIP und plugins.xml gehören danach in den Manager nach api/qgis/.

Zum Entwickeln: Ordner verlinken

git clone https://entwicklung.flurneuordnung-sachsen.de/VLN_SN/API_Karte_QGISDemo.git
cd API_Karte_QGISDemo

# macOS, QGIS 4 (bei QGIS 3: "QGIS4" durch "QGIS3" ersetzen):
ln -s "$PWD/vln_karten" \
  ~/Library/Application\ Support/QGIS/QGIS4/profiles/default/python/plugins/vln_karten

# Linux:   ~/.local/share/QGIS/QGIS4/profiles/default/python/plugins/
# Windows: %APPDATA%\QGIS\QGIS4\profiles\default\python\plugins\

Dann QGIS starten und unter Erweiterungen → Erweiterungen verwalten „VLN Karten“ aktivieren (experimentelle Erweiterungen zulassen). Beim Entwickeln hilft das Plugin Plugin Reloader — Codeänderungen wirken dann ohne QGIS-Neustart.

Verkehrszeichen und Widmungen

Die Sammlungen widmung-<vkz>-punkt (Schilder) und -linie (Widmungen) führen den Bestand des Verfahrens; blattzeichen-<vkz> führt die neuen Zeichen am Weg eines Maßnahmenblatts (sie liegen im Blatt, ein neues Zeichen braucht darum blatt_uuid). Beides ist über die OGC API voll bearbeitbar.

Den Stil liefert der Server fertig: Schildgrafik statt Kreis, gedreht nach drehung, Größe nach groesse, bis zu zwei Zusatzzeichen darunter; Widmungslinien nach Straßenklasse eingefärbt, Strichmuster nach Zustand, Änderungen seitlich versetzt. Ab 1:2500 wird aus dem Schild eine Marke, ab 1:10000 ein Punkt — sonst liegt über einem großen Verfahren nur noch ein Haufen.

Die Grafiken kommen von der API (/v2/zeichen/svg/<code>.svg, Katalog unter /v2/zeichen/katalog.json, beides öffentlich). Das Plugin legt sie beim Laden im QGIS-Profil ab (<Profil>/svg/vln/) und schreibt den Stil auf diesen Ordner um; fehlt eine Datei, bleibt die Serveradresse stehen.

Gesetzt wird wie im Web: in der Seitenleiste unter Verkehrszeichen setzen ein Schild wählen (Suche nach Nummer oder Name), dann Schild setzen einschalten — erster Klick Standort, zweiter Klick Blickrichtung. Zusatzzeichen hängt das gewählte Zusatzzeichen an ein vorhandenes Schild (höchstens zwei). Für Zeichen am Weg eines Blattes oben das Blatt auswählen; in der Verfahrenskarte bleibt die Auswahl leer. Zum Drehen vorhandener Schilder taugt auch das QGIS-Bordwerkzeug Punktsymbole drehen, weil der Stil die Drehung datendefiniert führt.

Hinweise für eigene Integrationen

  • QgsBlockingNetworkRequest statt requests/urllib verwenden — damit greifen Proxy- und Zertifikatseinstellungen aus QGIS.
  • Der API-Key wird im Beispiel unverschlüsselt in QSettings abgelegt; für Produktivcode bietet sich der QGIS-Authentifizierungsmanager an (QgsApplication.authManager()).
  • Requests laufen im Beispiel synchron (blockierend); für große Datensätze auf QgsNetworkAccessManager mit Tasks wechseln.
  • Features ohne Geometrie landen beim Laden in einem Tabellen-Layer „ohne Geometrie“; Geometrien werden beim Hochladen als Multi-Typen gesendet (ST_GeomFromGeoJSON akzeptiert beides).
S
Description
No description provided
Readme
428 KiB
Languages
Python 100%