WFS - Web Feature Service¶

Eksempel på bruk av en offentlig tilgjengelig WFS-tjeneste:

  • Vannkraft WFS

Denne presentasjonen kan lastes ned som Jupter Notebook-fil (høyreklikk, lagre som ..):

  • vannkraft.ipynb
NTNU 24.02.2025 - Sverre Stikbakke
In [1]:
import requests            # for å sende http-kall
import xml.dom.minidom     # for å håndtere xml-filer
import geopandas as gpd    # for å vise GML-filer som kart

Funksjon som sender kall til WFS-tjenesten¶

  • url: url til WFS-tjeneste
  • request: XML tekst-streng, kodet som byte-string med encode-funksjon
  • outfile: filnavn på XML/GML-fil
In [2]:
def wfs_request(url, request, outfile):
    response = requests.post(url, request)
    doc = xml.dom.minidom.parseString(response.content.decode())
    xml_response = doc.toprettyxml()
    with open(outfile, 'w', encoding = 'utf-8') as f:
        f.write(xml_response)

Url til tjenesten¶

In [3]:
url = 'https://wfs.geonorge.no/skwms1/wfs.vannkraft'

GetCapabilities-kall¶

Utformingen av dette kallet er helt uavhengig av innholdet i tjenesten. Det brukes derfor samme kall til alle tjenester. Vi er spesielt interessert i resultatet under FeatureTypeList.

In [4]:
getcapabilities = """<?xml version="1.0" encoding="UTF-8"?>
<GetCapabilities
  service = "WFS"
  version = "2.0.0"
  xmlns = "http://www.opengis.net/wfs/2.0"
  xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation = "http://www.opengis.net/wfs http://schemas.opengis.net/wfs/2.0/wfs.xsd"/>
""".encode()

DescribeFeatureType¶

Dette kallet tilpasses den aktuelle tjenesten basert på resultatet av GetCapabilities-kallet.

  • XML namespace, her: xmlns:app="http://skjema.geonorge.no/SOSI/produktspesifikasjon/Vannkraft/1.3"
  • TypeName, her: app:InnsjøRegulert

Resultatet av kallet beskriver hvilke egenskaper (attributter) den aktuelle objekttypen (TypeName) har.

In [5]:
describefeaturetype = """<?xml version="1.0" encoding="UTF-8"?>
<DescribeFeatureType
  service = "WFS"
  version = "2.0.0"
  xmlns = "http://www.opengis.net/wfs/2.0"
  xmlns:app ="http://skjema.geonorge.no/SOSI/produktspesifikasjon/Vannkraft/1.3"
  xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation = "http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd">
  <TypeName>app:InnsjøRegulert</TypeName>
</DescribeFeatureType>
""".encode()

GetFeature - uten Filter Encoding¶

Dette kallet henter objekter fra tjenesten. Namespace og Typename må spesifiseres. Her er det ikke noen spesifisering av hvordan objekter skal velges ut. Resultatet blir derfor tilfeldig, men det kan være en første test på å få ut et objekt fra tjenesten. Kallet spør i utgangspunktet etter alle objekter av den aktuelle objekttypen. Det er derfor viktig å begrense antallet objekter med count. Legg merke til:

  • wfs:Query
  • typeNames
  • srsName
In [6]:
getfeature = """<?xml version="1.0" encoding="UTF-8"?>
<GetFeature
  service = "WFS"
  version = "2.0.0"
  count = "1"
  xmlns = "http://www.opengis.net/wfs/2.0"
  xmlns:app="http://skjema.geonorge.no/SOSI/produktspesifikasjon/Vannkraft/1.3">
  <Query typeNames = "app:InnsjøRegulert" srsName="urn:ogc:def:crs:EPSG::25832">
  </Query>
</GetFeature>
""".encode()

GetFeature - med Filter Encoding¶

Dette kallet er utvidet med et fes:Filter-element. Filteret er av type BBOX som er oppgitt som en gml:Envelope. fes:ValueReference henviser til område som er navnet på geometri-egenskapen i objekttypen. Denne opplysningen kunne vi finne basert på resultatet av DescribeFeatureType-kallet, under InnsjøRegulert. Legg merke til at kallet også er utvidet med to nye namespaces:

  • xmlns:fes, for Filter Encoding
  • xmlns:gml, for GML
In [7]:
getfeatureBBOX = """<?xml version="1.0" encoding="UTF-8"?>
<GetFeature
  version = "2.0.0"
  xmlns = "http://www.opengis.net/wfs/2.0"
  xmlns:fes = "http://www.opengis.net/fes/2.0"
  xmlns:gml="http://www.opengis.net/gml/3.2"
  xmlns:app="http://skjema.geonorge.no/SOSI/produktspesifikasjon/Vannkraft/1.3">
  <Query typeNames = "app:InnsjøRegulert"  srsName="urn:ogc:def:crs:EPSG::25832">
    <fes:Filter>
      <fes:BBOX>
        <fes:ValueReference>område</fes:ValueReference>
        <gml:Envelope srsName="urn:ogc:def:crs:EPSG::25832">
          <gml:lowerCorner>586500 6735500</gml:lowerCorner>
          <gml:upperCorner>596500 6745500</gml:upperCorner>
        </gml:Envelope>
      </fes:BBOX>
    </fes:Filter>
  </Query>
</GetFeature>
""".encode()

Utføring av kallene¶

In [8]:
wfs_request(url, getcapabilities, 'getcapabilities.xml')
In [9]:
wfs_request(url, describefeaturetype, 'describefeaturetype.xml')
In [10]:
# wfs_request(url, getfeature, 'features.gml')
In [11]:
wfs_request(url, getfeatureBBOX, 'features.gml')

Presentasjon av resultat-fil¶

In [12]:
# skjuler warnings i cellen nedenfor
import warnings
warnings.filterwarnings('ignore')
In [13]:
features = gpd.read_file('features.gml', download_schema="no")
In [14]:
features.info()
<class 'geopandas.geodataframe.GeoDataFrame'>
RangeIndex: 3 entries, 0 to 2
Data columns (total 25 columns):
 #   Column                     Non-Null Count  Dtype   
---  ------                     --------------  -----   
 0   gml_id                     3 non-null      object  
 1   lokalId                    3 non-null      object  
 2   navnerom                   3 non-null      object  
 3   versjonId                  3 non-null      float64 
 4   datauttaksdato             3 non-null      object  
 5   oppdateringsdato           3 non-null      object  
 6   status                     3 non-null      object  
 7   konsesjonStatus            3 non-null      int32   
 8   konsesjonStatusDato        3 non-null      object  
 9   idriftsattAar              1 non-null      float64 
 10  vannkraftverkNr            3 non-null      int32   
 11  vannkraftverkNavn          3 non-null      object  
 12  elvenavnHierarki           3 non-null      object  
 13  magasinNr                  3 non-null      int32   
 14  magasinNavn                3 non-null      object  
 15  magasinAreal               3 non-null      float64 
 16  volumOppdemt               1 non-null      float64 
 17  magasinKategori            3 non-null      int32   
 18  lavesteRegulerteVannstand  1 non-null      float64 
 19  høyesteRegulerteVannstand  1 non-null      float64 
 20  magasinFormål              3 non-null      object  
 21  kdbNr                      3 non-null      int32   
 22  spID                       1 non-null      object  
 23  delfeltNr                  3 non-null      int32   
 24  geometry                   3 non-null      geometry
dtypes: float64(6), geometry(1), int32(6), object(12)
memory usage: 660.0+ bytes
In [15]:
features.bounds
Out[15]:
minx miny maxx maxy
0 574719.999 6677539.569 630586.005 6779617.995
1 588864.740 6737213.615 589118.598 6737678.122
2 588399.029 6736330.577 588522.028 6736366.842
In [16]:
features
Out[16]:
gml_id lokalId navnerom versjonId datauttaksdato oppdateringsdato status konsesjonStatus konsesjonStatusDato idriftsattAar ... magasinAreal volumOppdemt magasinKategori lavesteRegulerteVannstand høyesteRegulerteVannstand magasinFormål kdbNr spID delfeltNr geometry
0 app.innsjoregulert.791 0441afa2-cd1f-4cb0-acae-c053371734e6 http://skjema.geonorge.no/SOSI/produktspesifik... 1.3 2025-02-24T04:37:21 2611-02-05T03:36:40 D 5 2591-06-08T14:23:20 1912.0 ... 375.82 1312.0 1 119.33 122.94 Kraftproduksjon 794 00422 1905 POLYGON ((574882.001 6779599.002, 574797 67796...
1 app.innsjoregulert.2153 ba48a9a5-bd4a-497e-a852-33282c8e6911 http://skjema.geonorge.no/SOSI/produktspesifik... 1.3 2025-02-24T04:37:51 2611-02-05T03:36:40 D 5 2598-09-26T05:16:40 NaN ... 0.04 NaN 2 NaN NaN Kraftproduksjon 707 None 1167 POLYGON ((588998.713 6737616.81, 588998.037 67...
2 app.innsjoregulert.2156 904f4589-dc86-4387-b524-8efe647e44f1 http://skjema.geonorge.no/SOSI/produktspesifik... 1.3 2025-02-24T04:37:51 2611-02-05T03:36:40 D 5 2599-09-04T01:20:00 NaN ... 0.00 NaN 2 NaN NaN Kraftproduksjon 625 None 3041 POLYGON ((588512.665 6736366.352, 588507.281 6...

3 rows × 25 columns

In [17]:
features.plot(figsize=(10,10))
Out[17]:
<Axes: >
No description has been provided for this image