WFS User Manual

This is a brief explanation of using a WFS server.

Commonly, a WFS server can is accessed by GIS-software, such as QGis. The URL that’s configured inside urls.py can be used directly as WFS endpoint. For example, add https://api.data.amsterdam.nl/v1/wfs/gebieden/ to QGis.

Everything, for querying and viewing can be done in QGis.

Tip

The parameters ?SERVICE=WFS&VERSION=2.0.0&REQUEST=.. are appended to the URL by QGis. It’s not required to add these yourself.

The WFS server can also be accessed directly from a HTTP client (e.g. curl) or web browser. In such case, use the basic URL above, and include the query parameters:

?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=featurename

The available feature types can be found in the GetCapabilities request:

?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetCapabilities

The remaining part of this page assumes this manual access.

Export Formats

The following export formats are available:

  • GeoJSON
  • CSV

These can be queried by manually crafting a GetFeature request. The parameters TYPENAMES=feature-name and OUTPUTFORMAT=format should be included.

For example:

Tip

In the example links above, a COUNT= parameter is included to activate pagination. When this parameter is omitted, all objects will be returned in a single request. For most datasets, the server is capable of efficiently delivering all results in a single response.

Geometry Projections

The exportlink can be extended with the SRSNAME parameter to define the geometry projection of all geo data. For example, SRSNAME=urn:ogc:def:crs:EPSG::3857 activates the web-mercator projection which is used by Google Maps. A common default is urn:ogc:def:crs:EPSG::4326, which is the worldwide WGS 84 longitude-latitude.

Simple Filters

The WFS protocol offers a powerful syntax to filter data. Use the request REQUEST=GetFeature with a FILTER argument. The filter value is expressed as XML.

For example, to query all neighbourhoods (typename buurten) of the central district (stadsdeel) in Amsterdam:

<Filter>
    <PropertyIsEqualTo>
        <ValueReference>ligt_in_stadsdeel/naam</ValueReference>
        <Literal>Centrum</Literal>
    </PropertyIsEqualTo>
</Filter>

This can be included in the request, for example:

The FILTER parameter replaces the separate BBOX and RESOURCEID parameters. If you use these parameters as well, they should be included in the filter:

<Filter>
    <And>
        <BBOX>
            <gml:Envelope srsName="EPSG:4326">
                <gml:lowerCorner>4.58565 52.03560</gml:lowerCorner>
                <gml:upperCorner>5.31360 52.48769</gml:upperCorner>
            </gml:Envelope>
        </BBOX>
        <PropertyIsEqualTo>
            <ValueReference>status</ValueReference>
            <Literal>1</Literal>
        </PropertyIsEqualTo>
    </And>
</Filter>

The RESOURCEID parameter has a <ResourceId> equivalent which can appear several times in the filter:

<Filter>
    <ResourceId rid="TYPENAME.123" />
    <ResourceId rid="TYPENAME.4325" />
    <ResourceId rid="OTHERTYPE.567" />
</Filter>

Complex Filters

The WFS Filter Encoding Standaard (FES) supports many operators. These tags are all supported:

Element SQL equivalent Description
<PropertyIsEqualTo> a == b Values must be equal.
<PropertyIsNotEqualTo> a != b Values must not be equal.
<PropertyIsLessThan> a < b Value 1 must be less than value 2.
<PropertyIsGreaterThan> a > b Value 1 must be greater than value 2.
<PropertyIsLessThanOrEqualTo> a <= b Value 1 must be less than or equal to value 2.
<PropertyIsGreaterThanOrEqualTo> a >= b Value 1 must be greater than or equal to value 2.
<PropertyIsBetween> a BETWEEN x AND y Compares between <LowerBoundary> and <UpperBoundary>, which both contain an expression.
<PropertyIsLike> a LIKE b Performs a wildcard comparison.
<PropertyIsNil> a IS NULL Value must be NULL (xsi:nil="true" in XML).
<PropertyIsNull> n.a. Property may not exist (currently implemented as <PropertyIsNil>).
<BBOX> ST_Intersects(a, b) Geometry must be in value 2. The field name may be omitted to use the default.
<Contains> ST_Contains(a, b) Geometry 1 completely contains geometry 2.
<Crosses> ST_Crosses(a, b) The geometries have some common interior points.
<Disjoint> ST_Disjoint(a, b) The geometries are not connected in any way.
<Equals> ST_Equals(a, b) The geometries are identical.
<Intersects> ST_Intersects(a, b) The geometries share some space.
<Touches> ST_Touches(a, b) The edges of the geometries touch each other.
<Overlaps> ST_Overlaps(a, b) The geometries overlap.
<Within> ST_Within(a, b) Geometry 1 is completely contained within geometry 2.
<DWithin> ST_DWithin(a, b, d) The geometries are within a given distance of each other.
<Beyond> NOT ST_DWithin(a, b, d) The geometries are not within a given distance.
<And> a AND b The nested elements must all be true.
<Or> a OR b Only one of the nested elements has to be true.
<Not> NOT a Negation of the nested element.
<ResourceId> table.id == value / table.id IN (v1, v2, ...) Searches only one element for “type name.identifier”. Combines multiple elements into an IN query.

Tip

For the <BBOX> operator the geometry field may be omitted. The standard geometry field is then used (usually the first field).

Note

Although a number of geometry operators seem to be identical for surfaces (such as <Intersects>, <Crosses> and <Overlaps>), their mutual differences are particularly visible when comparing points with surfaces.

Various expressions may be used as values:

Expression SQL equivalent Description
<ValueReference> field-name References a field.
<Literal> value Literal value, can also be a GML-object.
<Function> function-name(..) Executes a function, such as abs, sin, strLength.
<Add> a + b Addition (WFS 1 expression).
<Sub> a - b Subtraction (WFS 1 expression).
<Mul> a * b Multiplication (WFS 1 expression).
<Div> a / b Division (WFS 1 expression).

This allows to create complex filters, such as:

<Filter>
    <And>
        <PropertyIsEqualTo>
            <ValueReference>status</ValueReference>
            <Literal>1</Literal>
        </PropertyIsEqualTo>
        <Or>
            <PropertyIsEqualTo>
                <ValueReference>container_type</ValueReference>
                <Literal>Other</Literal>
            </PropertyIsEqualTo>
            <PropertyIsEqualTo>
                <ValueReference>container_type</ValueReference>
                <Literal>Textile</Literal>
            </PropertyIsEqualTo>
            <PropertyIsEqualTo>
                <ValueReference>container_type</ValueReference>
                <Literal>Glass</Literal>
            </PropertyIsEqualTo>
            <PropertyIsEqualTo>
                <ValueReference>container_type</ValueReference>
                <Literal>Papier</Literal>
            </PropertyIsEqualTo>
            <PropertyIsEqualTo>
                <ValueReference>container_type</ValueReference>
                <Literal>Organic</Literal>
            </PropertyIsEqualTo>
            <PropertyIsEqualTo>
                <ValueReference>container_type</ValueReference>
                <Literal>Plastic</Literal>
            </PropertyIsEqualTo>
        </Or>
    </And>
</Filter>

Functions

Functions are executed by using the tag <Function name="..">..</Function>. This can be used anywhere as an expression instead of a <ValueReference> or <Literal>.

Inside the function, the parameters are also given as expressions: a <ValueReference>, <Literal> or new <Function>. As a simple example:

<fes:Function name="sin">
    <fes:ValueReference>fieldname</fes:ValueReference>
</fes:Function>

The following functions are available in the server:

Functie SQL equivalent Description
strConcat(string) CONCAT() Concatenates strings
strToLowerCase(string) LOWER() Convert text to lowercase.
strToUpperCase(string) UPPER() Convert text to uppercase.
strTrim(string) TRIM() Remove white space at the beginning and end.
strLength(string) LENGTH() / CHAR_LENGTH() Determines text length.
length(string) LENGTH() / CHAR_LENGTH() Alias of strLength().
abs(number) ABS() Invert negative numbers.
ceil(number) CEIL() Rounding up.
floor(number) FLOOR() Rounding down.
round(value) ROUND() Regular rounding.
min(value1, value2) LEAST() Uses the smallest number.
max(value1, value2) GREATEST() Uses the largest number.
pow(base, exponent) POWER() Exponentiation
exp(value) EXP() Exponent of 𝑒 (2,71828…; natural logarithm).
log(value) LOG() Logarithm; inverse of an exponent.
sqrt(value) SQRT() Square root, inverse of exponentiation.
acos(value) ACOS() Arccosine; inverse of cosine.
asin(value) ASIN() Arcsine; inverse van sine.
atan(value) ATAN() Arctangent; inverse of tangent.
atan2(x, y) ATAN2() Arctangent, for usage outside the range of a circle.
cos(radians) COS() Cosine
sin(radians) SIN() Sine
tan(radians) TAN() Tangent
pi() PI The value of π (3,141592653…)
toDegrees(radians) DEGREES() Conversion of radians to degrees.
toRadians(degree) RADIANS() Conversion degrees to radians.
Area(geometry) ST_AREA() Convert geometry to area.
Centroid(features) ST_Centroid() Return geometric center as “gravity point”.
Difference(geometry1, geometry2) ST_Difference() Parts of geometry 1 that do not overlap with geometry 2.
distance(geometry1, geometry2) ST_Distance() Minimum distance between 2 geometries.
Envelope(geometry) ST_Envelope() Convert geometry to bounding box.
Intersection(geometry1, geometry2) ST_Intersection() Parts of geometry 1 that overlap with geometry 2.
Union(geometry1, geometry2) ST_Union() Merge Geometry 1 and 2.

Filter Compatibility

Strictly speaking, XML namespaces are required in the filter. Since many clients omit them, the server also supports requests without namespaces. For the sake of completeness, a request with namespaces included looks like this:

<fes:Filter xmlns:fes="http://www.opengis.net/fes/2.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.opengis.net/fes/2.0
        http://schemas.opengis.net/filter/2.0/filterAll.xsd">
    <fes:PropertyIsEqualTo>
        <fes:ValueReference>stadsdeel/naam</fes:ValueReference>
        <fes:Literal>Centrum</fes:Literal>
    </fes:PropertyIsEqualTo>
</fes:Filter>

When a geometry filter is included, this also requires the GML namespace:

<fes:Filter
    xmlns:fes="http://www.opengis.net/fes/2.0"
    xmlns:gml="http://www.opengis.net/gml/3.2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.opengis.net/fes/2.0
    http://schemas.opengis.net/filter/2.0/filterAll.xsd
    http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd">
    <fes:BBOX>
        <gml:Polygon gml:id="P1" srsName="http://www.opengis.net/def/crs/epsg/0/4326">
            <gml:exterior>
                <gml:LinearRing>
                    <gml:posList>10 10 20 20 30 30 40 40 10 10</gml:posList>
                </gml:LinearRing>
            </gml:exterior>
        </gml:Polygon>
    </fes:BBOX>
</fes:Filter>

According to the XML rules, the “fes” namespace alias can be renamed here or omitted if only xmlns="..."` is used instead of xmlns:fes="...".

Several existing clients still use other WFS 1 elements, such as <PropertyName> instead of of <ValueReference>. For compatibility this tag is also supported.

The WFS 1 expressions <Add>, <Sub>, <Mul> and <Div> are also implemented to support arithmetic operations from QGis (addition, subtraction, multiplication and division).