Neu in docs/wissen: wfs_dienste.md (ALKIS-WFS-Endpunkte der saechsischen Dienste, erprobte Anfragen je Objektart, die vom WAF blockierten Normfaelle) und alkis_objektarten.md (die von sn_verfahrensgebiet genutzten AAA-Objektarten mit Attributen, Filterkonventionen und den FlurbG-Werten von artderfestlegung). Neu in docs/konzept: 09_alkis7_umstellung.md - Vergleich ALKIS 6 (GID 6.0) gegen ALKIS 7 (GID 7.1) und die konkrete Anpassungsliste fuer sn_verfahrensgebiet (fest verdrahteter NAS-Namespace, abgeflachte WFS-Feldnamen, Codelisten, Tests). Als offene Baustelle 14 in STATUS.md verlinkt. Quellmaterial (OK-AAA 7.1.2, ALKIS-FSK 2.1.0, EA-Modellexporte, ~180 MB) liegt lokal unter referenz/ und wird per .gitignore nicht versioniert; Herkunft ist in alkis_objektarten.md dokumentiert. Querverweise aus externe_dienste.md, fallstricke.md, docs/README.md ergaenzt; Glossar um NAS, ZUSO/REO, OK-AAA erweitert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NqvdHqySjQMVowB3G3Vf3U
138 lines
6.9 KiB
Markdown
138 lines
6.9 KiB
Markdown
# WFS-Dienste (ALKIS Sachsen)
|
||
|
||
Lebendes Dokument. Was die Plugins an WFS-Diensten ansprechen, wie sich diese Dienste **tatsächlich**
|
||
verhalten (nicht wie die Norm es vorsieht) und welche Anfragen erprobt funktionieren.
|
||
|
||
Betrifft ausschließlich **`sn_verfahrensgebiet`** (`functions/*_alkis*.py`). `sn_plan41` nutzt kein ALKIS/WFS,
|
||
sondern die VLN-Karten-API. Objektarten und Attribute im Detail: [`alkis_objektarten.md`](alkis_objektarten.md).
|
||
Quelle der Erkenntnisse: Sondierungsskripte in `referenz/wfs/` (nicht versioniert) und der Code selbst.
|
||
|
||
## Die drei Endpunkte
|
||
|
||
| Kürzel im Code | URL | WFS-Version | Geometrie | Verwendung |
|
||
|---|---|---|---|---|
|
||
| „vereinfacht" (`ALKIS_VEREINF_URL`) | `https://geodienste.sachsen.de/aaa/public_alkis/vereinf/wfs` | 2.0.0 | ja | `ave:KatasterBezirk` → Gemarkungen mit Fläche |
|
||
| „SF" (`ALKIS_SF_URL`) | `https://geodienste.sachsen.de/aaa/public_alkis/sf/wfs` | 2.0.0 | teils | `adv:AX_Flurstueck`, `adv:AX_BauRaumOderBodenordnungsrecht`, `adv:AX_PunktortTA`, `adv:AX_Grenzpunkt` |
|
||
| „NAS" (nur erwähnt) | – | – | – | `adv:AX_Gemarkung` hätte **keine** Geometrie, deshalb wird stattdessen `ave:KatasterBezirk` genommen |
|
||
|
||
CRS durchgängig **EPSG:25833** (ETRS89 / UTM 33N). In KVP-Parametern als `urn:ogc:def:crs:EPSG::25833`,
|
||
in der QGIS-WFS-URI als `srsname='EPSG:25833'`.
|
||
|
||
## Was der Dienst blockiert – die harten Grenzen
|
||
|
||
Ein Web Application Firewall vor `geodienste.sachsen.de` schränkt den Dienst gegenüber der WFS-2.0-Norm ein:
|
||
|
||
| Was | Verhalten | Beleg |
|
||
|---|---|---|
|
||
| **POST** (`GetFeature` als XML-Body) | blockiert | `referenz/wfs/_test_wfs_post.py` |
|
||
| **`FILTER`-XML mit GML-`Envelope`/`BBOX`** in der GET-URL | blockiert | `referenz/wfs/_test_wfs_bbox.py`, `grenzpunkt_alkis.py` Kopf |
|
||
| **KVP-Parameter `BBOX=minx,miny,maxx,maxy,crs`** | **funktioniert** – so wird PunktortTA räumlich gefiltert | `_punktort_ta_bbox_param()` |
|
||
| **`FILTER` mit `fes:ResourceId rid="…"`** in der GET-URL | funktioniert (`ImplementsResourceId=TRUE`) | `_test_wfs_get.py`, Grenzpunkt-Batches |
|
||
| **URL-Länge** | ~8192 Bytes; darüber 414/Abbruch | Batchgröße 100 IDs (~54 Byte/ID URL-kodiert) |
|
||
| **`COUNT`** | Serverlimit, im Code auf 20 000 gesetzt (`_MAX_FEATURES`) | `grenzpunkt_alkis.py` |
|
||
| **Serverseitiger Filter auf `gehoertZu`/`istTeilVon`** | nicht möglich (`ErrorInPropertyName`) | `grenzpunkt_alkis.py` Kopf |
|
||
| **`AX_Grenzpunkt` per BBOX** | nicht möglich – Objektart ohne eigene Geometrie | siehe unten |
|
||
|
||
Folgerung: **Nicht „vereinfachen", ohne gegen den Dienst zu testen.** Die scheinbar umständlichen
|
||
Mehrschritt-Strategien (BBOX → PunktortTA → GML-IDs → Grenzpunkt-Batches → Client-Join; Flurstücke
|
||
gemarkungsweise einzeln) sind die Antwort auf genau diese Grenzen.
|
||
|
||
## Anfragen je Objektart (erprobt)
|
||
|
||
### `ave:KatasterBezirk` (vereinfachter Dienst) → Gemarkungen
|
||
|
||
QGIS-WFS-Layer, **ohne** serverseitigen Filter (Dienst kann es nicht), danach Client-seitige Verschneidung
|
||
per `QgsGeometry.intersects` mit der Verfahrensgebiets-Geometrie:
|
||
|
||
```
|
||
url='https://geodienste.sachsen.de/aaa/public_alkis/vereinf/wfs'
|
||
typename='ave:KatasterBezirk' srsname='EPSG:25833'
|
||
```
|
||
|
||
Attribute: `schluessel` (voller Katasterbezirksschlüssel, **letzte 4 Stellen = Gemarkungsnummer**),
|
||
`ave_name` (Bezeichnung). Sachsen hat ≈ 2 000 Katasterbezirke – der Komplettabruf ist vertretbar.
|
||
|
||
### `adv:AX_BauRaumOderBodenordnungsrecht` (SF) → Verfahrensgebiet
|
||
|
||
Serverseitiger Attributfilter über die QGIS-WFS-URI (`sql=`):
|
||
|
||
```
|
||
url='…/sf/wfs' typename='adv:AX_BauRaumOderBodenordnungsrecht' srsname='EPSG:25833'
|
||
sql=SELECT * FROM AX_BauRaumOderBodenordnungsrecht WHERE bezeichnung LIKE '<vkz5>%'
|
||
```
|
||
|
||
`<vkz5>` = die **ersten 5 Stellen** der Verfahrenskennziffer (`get_variable("verfahrensnummer")[:5]`);
|
||
die Daten im Dienst führen teils abweichende Suffixe. Geladene Attribute:
|
||
`artderfestlegung`, `ausfuehrendestelle_ax_dienststelle_schluessel_stelle`, `adv_name`, `bezeichnung`,
|
||
`datumanordnung`, `datumbesitzeinweisung`, `datumrechtskraft`, `datumabgabe`.
|
||
Gruppierung im Plugin nach `(adv_name, bezeichnung)`.
|
||
|
||
### `adv:AX_Flurstueck` (SF)
|
||
|
||
**Eine WFS-Anfrage pro Gemarkung** (Sammelabfrage mit mehreren Nummern läuft ins Feature-Limit),
|
||
Ergebnisse in einen Memory-Layer zusammengeführt:
|
||
|
||
```
|
||
url='…/sf/wfs' typename='adv:AX_Flurstueck' srsname='EPSG:25833'
|
||
sql=SELECT * FROM AX_Flurstueck
|
||
WHERE gemarkung_ax_gemarkung_schluessel_gemarkungsnummer = '<gemarkungsnummer4>'
|
||
```
|
||
|
||
### `adv:AX_PunktortTA` (SF) → Trägerpunkt für Grenzpunkte
|
||
|
||
Roh-GET mit KVP-`BBOX`, GML-Antwort wird selbst geparst (`xml.etree`):
|
||
|
||
```
|
||
SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature
|
||
&TYPENAMES=adv:AX_PunktortTA
|
||
&SRSNAME=urn:ogc:def:crs:EPSG::25833
|
||
&COUNT=20000
|
||
&BBOX=<minx>,<miny>,<maxx>,<maxy>,urn:ogc:def:crs:EPSG::25833
|
||
```
|
||
|
||
Geometrieattribut `position`. Referenz auf den Grenzpunkt: Feldname je NAS-Version unterschiedlich –
|
||
Kandidaten in dieser Reihenfolge geprüft: `istTeilVon` (NAS 6.x), `gehoertZu`, `gehoertZuAX_Grenzpunkt`.
|
||
Wert kommt als `xlink:href` (`urn:adv:oid:DE…`) oder flach. Optional wird
|
||
`adv:qualitaetsangaben/adv:genauigkeitsstufe` in das Feld
|
||
`qualitaetsangaben_ax_dqpunktort_genauigkeitsstufe` gezogen.
|
||
|
||
### `adv:AX_Grenzpunkt` (SF)
|
||
|
||
Kein BBOX (ZUSO ohne eigene Geometrie). Abruf über die aus PunktortTA gewonnenen GML-IDs,
|
||
**Batches à 100**, GET mit `ResourceId`-Filter:
|
||
|
||
```
|
||
SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature
|
||
&TYPENAMES=adv:AX_Grenzpunkt&COUNT=20000
|
||
&FILTER=<fes:Filter xmlns:fes="http://www.opengis.net/fes/2.0">
|
||
<fes:ResourceId rid="DE…"/> … (bis zu 100)
|
||
</fes:Filter>
|
||
```
|
||
|
||
Danach Client-seitiger Join `PunktortTA.<referenzfeld>` ↔ `AX_Grenzpunkt.gml_id`; Grenzpunkt-Attribute
|
||
im Ergebnis mit Präfix `gp_`.
|
||
|
||
## Fehlerantworten, die im Betrieb auftauchen
|
||
|
||
| Antwort | Bedeutung | Reaktion im Code |
|
||
|---|---|---|
|
||
| HTTP 403 / HTML-Seite statt XML | WAF hat POST oder GML-XML-Filter geblockt | auf GET + KVP/ResourceId ausweichen |
|
||
| `ExceptionReport` mit `ErrorInPropertyName` | Attribut ist nicht serverseitig filterbar | Attribut client-seitig filtern |
|
||
| gültiger Layer, `featureCount() == 0` | Dienst liefert ohne (unterstützten) Filter nichts | Diagnosemeldung, leere Liste, manueller Fallback |
|
||
| HTTP 414 | URL zu lang | Batchgröße senken |
|
||
|
||
## Offene Punkte
|
||
|
||
- Die vier Skripte in `referenz/wfs/` sind Wegwerf-Sondierungen. Wenn Bedarf besteht, sie regelmäßig
|
||
laufen zu lassen (Dienst-Regression erkennen), gehören sie als `scripts/wfs_probe.py` ins Projektwissen –
|
||
mit Netzkennzeichnung, kein Unittest.
|
||
- `ave:KatasterBezirk` vs. Schreibweise `Katasterbezirk`/`KatasterBezirk`: im Code uneinheitlich
|
||
dokumentiert, maßgeblich ist der Wert in `gemarkung_alkis.py` (`ave:KatasterBezirk`).
|
||
|
||
## Siehe auch
|
||
|
||
- [`alkis_objektarten.md`](alkis_objektarten.md) – Objektarten und Attribute
|
||
- [`externe_dienste.md`](externe_dienste.md) – alle externen Dienste im Überblick
|
||
- [`fallstricke.md`](fallstricke.md) – Abschnitt „Daten und Dienste"
|
||
- `referenz/alkis/` (lokal, nicht versioniert) – OK-AAA 7.1.2, ALKIS-FSK 2.1.0
|