Het bevragen van een WFS in de browser – voorbeelden aan de hand van de BAG-service

Het leek me interessant en nuttig om wat meer te leren over het bevragen van een Web Feature Service (WFS) in de browser in het algemeen, en de WFS van de Basisregistratie Adressen en Gebouwen (BAG) in het bijzonder. Daarom ben ik maar eens in de materie gedoken ūüėČ Wat ik heb opgestoken, lees je in dit blog. De volgende bronnen waren daarbij erg behulpzaam:

WFS is een interface voor het opvragen van geografische vector data en bijbehorende administratieve data over het internet (zie Wikipedia). Je kunt een WFS bevragen met een HTTP GET of HTTP POST request. Een HTTP GET request (kortweg: GET) is een verzoek aan een WFS om gegevens te retourneren versleuteld in een URL. Een GET voor de WFS van de BAG ziet er zo uit:

http://geodata.nationaalgeoregister.nl/bag/wfs?param1=waarde1&param2=waarde2&...

De drie meest gebruikte GET requests voor het bevragen van een WFS zijn:

  • GetCapabilities
  • DescribeFeatureType
  • GetFeature

Tenzij je een ander formaat specificeert, geeft de WFS antwoord in de vorm van een XML-document.
In onderstaande tekst wordt het gebruik van deze drie requests ge√Įllustreerd aan de hand van de WFS voor de BAG.

Met een GetCapabilities request krijg je snel inzicht in wat de WFS voor mogelijkheden biedt:

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&request=GetCapabilities

Welke lagen bevat de service? In welk coördinatenstelsel worden de features standaard geretourneerd? Wat voor uitvoerformaten ondersteunt de service? Vragen die beantwoord worden in het GetCapabilities document dat de service retourneert.

Als je detailinformatie over een laag (‘feature type’) in de WFS wilt, bijvoorbeeld de namen en gegevenstypen van de attributen, gebruik dan DescribeFeatureType. Door een waarde op te geven voor de parameter typeName geef je aan van welke laag je meer informatie wilt opvragen.

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=DescribeFeatureType&typeName=bag:verblijfsobject

Voor de duidelijkheid is in bovenstaand request version=2.0.0 opgenomen, maar strikt genomen is dit niet nodig. Als je de parameter version weg laat, geeft de service standaard de hoogste ondersteunde versie terug. In het geval van de BAG is dat 2.0.0.

Met een getFeature request kun je de geografische objecten (‘features’) en hun bijbehorende administratieve gegevens opvragen. Met de parameter count kun je het maximum aantal features aangeven dat in het antwoord geretourneerd wordt. Voor de BAG-service geldt dat count standaard de waarde 15.000 heeft.

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&count=25

Met de parameter sortBy kun je de features in het antwoord van de service sorteren op attribuutwaarden. Met de toevoeging +A of +D kun je aangeven of de waarden in respectievelijk oplopende of aflopende volgorde gesorteerd moeten worden. Let op: bij een WFS die met ArcGIS Server gepubliceerd wordt, werkt de parameter sortBy alléén als de gegevens zijn opgeslagen in een ArcSDE geodatabase.

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&count=25&sortBy=bag:identificatie+D

Als je slechts ge√Įnteresseerd bent in √©√©n of enkele attributen, kun je het aantal attributen in het antwoord beperken met behulp van de parameter propertyName.

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&count=25&propertyName=bag:postcode,bag:woonplaats

De gegevens van een specifieke feature kun je opvragen met de featureId parameter. De waarde die je in het geval van de BAG-service moet opgeven is het gml:id en níet de bag:identificatie!

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&count=25&featureId=verblijfsobject.118285

Door met de parameter bbox een ‘bounding box’ op te geven, vraag je alleen de features op die binnen het opgegeven gebied liggen. Als de gegevens in EPSG:28992 (Amersfoort / RD New) geretourneerd worden, zoals bij de BAG standaard het geval is, geldt bbox=xmin,ymin,xmax,ymax. In het voorbeeld worden alle verblijfsobjecten in een deel van de gemeente De Marne opgevraagd.

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&bbox=213089,593892,217076,597981

Het is ook mogelijk om een selectie te maken met behulp van de filter parameter. Het filter om alleen de verblijfsobjecten uit de BAG opgevraagd met postcode 9712 JN is: filter=<Filter><PropertyIsEqualTo><PropertyName>bag:postcode</PropertyName><Literal>9712JN</Literal></PropertyIsEqualTo></Filter>

Als je een filter opneemt in een URL, moet je niet vergeten bijzonder tekens zoals spaties, haakjes en aanhalingstekens te vervangen met behulp van URL encoding. Het maakt het request er jammer genoeg niet overzichtelijker op.

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&filter=%3CFilter%3E%3CPropertyIsEqualTo%3E%3CPropertyName%3Ebag:postcode%3C/PropertyName%3E%3CLiteral%3E9712JN%3C/Literal%3E%3C/PropertyIsEqualTo%3E%3C/Filter%3E

Een ander voorbeeld van het filteren van features op basis van attribuutwaarden is onderstaand verzoek om alleen de verblijfsobjecten in Groningen met huisnummer 4 te retourneren. Het filter is in dit geval: Filter=<Filter><And><PropertyIsEqualTo><PropertyName>bag:woonplaats</PropertyName><Literal>Groningen</Literal></PropertyIsEqualTo><PropertyIsEqualTo><PropertyName>bag:huisnummer</PropertyName><Literal>4</Literal></PropertyIsEqualTo></And></Filter>

Met URL encoding wordt de URL dan:

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&filter=%3CFilter%3E%3CAnd%3E%3CPropertyIsEqualTo%3E%3CPropertyName%3Ebag:woonplaats%3C/PropertyName%3E%3CLiteral%3EGroningen%3C/Literal%3E%3C/PropertyIsEqualTo%3E%3CPropertyIsEqualTo%3E%3CPropertyName%3Ebag:huisnummer%3C/PropertyName%3E%3CLiteral%3E4%3C/Literal%3E%3C/PropertyIsEqualTo%3E%3C/And%3E%3C/Filter%3E

Jammer genoeg kun je de parameters bbox en filter niet combineren. Als je het probeert, krijg je een foutmelding: Filter and bbox both specified but are mutually exclusive.

Het is niet eenvoudig om een filter te specificeren conform de offici√ęle specificatie van het OGC. GeoServer maakt het iets makkelijker met¬†CQL filters. CQL staat voor Common Query Language. Het is beter leesbaar dan ‘gewone’ filters, al moet je bij CQL filters¬†ook URL encoding toepassen. CQL filters zijn echter geen onderdeel van de formele WFS-specificatie! De volgende voorbeelden met CQL filters werken, omdat de BAG-service ‘draait’ op GeoServer. Bij een service die wordt ontsloten met ArcGIS Server of Deegree kun je geen gebruik maken van CQL filters.

Het request in het vorige voorbeeld zou je ook kunnen doen met een CQL filter: cql_filter=(huisnummer=4 and woonplaats='Groningen')
Als je een CQL filter opneemt in een URL, moet je niet vergeten bijzonder tekens zoals spaties, haakjes en aanhalingstekens te vervangen met behulp van URL encoding. Het verzoek om alle verblijfsobjecten in Groningen met huisnummer 4 wordt dan:

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&cql_filter=%28bag:woonplaats=%27Groningen%27%20and%20bag:huisnummer=4%29

Met een CQL filter kunt je ook op geometrie filteren. Met dit CQL filter worden alle verblijfsobjecten in een straal van 100 meter rondom het provinciehuis in Groningen opgevraagd: cql_filter=dwithin(bag:geometrie, point(234055 582111), 100, meters)

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&cql_filter=dwithin%28bag:geometrie,point%28234055%20582111%29,100,meters%29

Het is mogelijk om tegelijkertijd te filteren op geometrie Рbijvoorbeeld door een bounding box op te geven Рen op attribuutwaarden. Het CQL filter voor het opvragen van alle verblijfsobjecten met een logiesfunctie in een door coördinaten begrensd deel van de gemeente De Marne is: cql_filter=((bbox(bag:geometrie, 213089, 593892, 217076, 597981) and (bag:gebruiksdoel='logiesfunctie'))

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&cql_filter=%28bbox%28bag:geometrie,213089,593892,217076,597981%29and%28bag:gebruiksdoel=%27logiesfunctie%27%29%29

De BAG-service retourneert maximaal 15.000 features per request. Maar soms wil je meer features opvragen, dan kun je gebruik maken van ‘response paging’. Vraag eerst het totaal aantal features op dat voldoet aan je zoekopdracht door gebruik te maken van resultType=hits. Vervolgens kun je door slim gebruik te maken van de parameters startindex, count en sortBy in ‘etappes’ alle features opvragen.
In onderstaand voorbeeld wordt het aantal verblijfsobjecten in de woonplaats Groningen opgevraagd. Het aantal wordt geretourneerd in het XML-attribuut numberMatched.

http://geodata.nationaalgeoregister.nl/bag/wfs?service=WFS&version=2.0.0&request=GetFeature&typename=bag:verblijfsobject&cql_filter=%28bag:woonplaats=%27Groningen%27%29&resulttype=hits

De eerste 5.000 verblijfsobjecten in Groningen krijg je retour met het volgende request:

http://geodata.nationaalgeoregister.nl/bag/wfs?service=WFS&version=2.0.0&request=GetFeature&typename=bag:verblijfsobject&cql_filter=%28bag:woonplaats=%27Groningen%27%29&count=5000&startindex=0&sortBy=bag:identificatie+A

De volgende 5.000 verblijfsobjecten krijg je door startIndex=5000 op te geven.

http://geodata.nationaalgeoregister.nl/bag/wfs?service=WFS&version=2.0.0&request=GetFeature&typename=bag:verblijfsobject&cql_filter=%28bag:woonplaats=%27Groningen%27%29&count=5000&startindex=5000&sortBy=bag:identificatie+A

Standaard geeft een WFS het antwoord terug in XML-formaat, maar je kunt ook een andere formaat opgeven met behulp van de outputFormat parameter. In dit voorbeeld worden bijvoorbeeld alle verblijfsobjecten met postcode 9712 JN opgevraagd in CSV-formaat.

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&cql_filter=%28bag:postcode=%279712JN%27%29&outputFormat=csv

KML kan ook:

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&cql_filter=%28bag:postcode=%279712JN%27%29&srsName=EPSG:4326&outputFormat=kml

Als je de gegevens wilt opslaan in GeoJSON formaat, vergeet dan niet EPSG:4326 (WGS84) als coördinatenstelsel op te geven met behulp van de srsName parameter. De meeste ontwikkelaars en data analisten verwachten namelijk dat coördinaten in een GeoJSON-bestand in WGS84 zijn.

http://geodata.nationaalgeoregister.nl/bag/wfs?service=wfs&version=2.0.0&request=GetFeature&typeName=bag:verblijfsobject&cql_filter=%28bag:postcode=%279712JN%27%29&outputFormat=json&srsName=epsg:4326

Let op: de outputFormat parameter is weliswaar onderdeel van de formele WFS-specificatie van het OGC, maar welke uitvoerformaten beschikbaar zijn, hangt af van de map server die gebruikt wordt. Zo ondersteunt Deegree op dit moment bijvoorbeeld nog geen KML en GeoJSON. De uitvoerformaten waaruit je kunt kiezen voor een bepaalde WFS, kun je opvragen met een GetCapabilities request.

Tot zover. Mocht je nog verbeteringen of aanvullingen hebben, dan hoor ik het graag!