📁
Filter Expressions in FME
  • Introduction
  • Credits
  • Working Environment
  • GetCapabilities
  • 1st Filter
  • The Formula
  • Bulk Processing
  • Comparison Operators
  • Spatial Operators
  • Logical Operators
  • DefaultCRS vs OtherCRS
  • Outlook: WFS 3.0
  • Resources
  • Ideas for improvement
  • Expression Library
Powered by GitBook
On this page
  • Examine a feature
  • Examine the Translation Log
  • Choosing the right version
  • Good to know #3

The Formula

Ingredients for the perfect Filter Expression

Let's have a look at the filter expression again:

<fes:Filter 
   xmlns:fes="http://www.opengis.net/fes/2.0"
   xmlns:cp="http://inspire.ec.europa.eu/schemas/cp/4.0">
   <fes:PropertyIsEqualTo>
      <fes:ValueReference>cp:nationalCadastralReference</fes:ValueReference>
      <fes:Literal>05430202600946______</fes:Literal>
   </fes:PropertyIsEqualTo>
</fes:Filter>

Maybe you're wondering about the prefixes

  • fes:

  • xmlns:

  • cp:

What's this?

Did you ever hear about XML namespaces, aka xmlns?

A XML namespace is comparable to

  • a dictionary or

  • a telephone book

A telephone number is only valid in combination with an area code (which represents a certain city or geographic area).

Let's give an example: the telephone number is 501 9985.

You may dial it on your phone and maybe someone answers (please don't do it in real!).

501 9985 without a prefix is not specific enough! You'll need an area code and maybe a country code in order to reach someone.

If you put the country code "+1" and the area code "604" for greater Vancouver in front of 501 9985 you'll get Safe Softwares phone number: +1 604 501 9985

Let's have a look at another example: take the word "Kindergarten"

Does it occur in your dictionary? In german Duden dictionary it does. What does the word mean in your language?

W3schools says: "XML Namespaces provide a method to avoid element name conflicts." It means they are used to define unique and precise names.

Name conflicts in XML can easily be avoided using a name prefix.

Use the following syntax to declare a namespace: xmlns:prefix="URI", e.g.

  • xmlns:fes="http://www.opengis.net/fes/2.0"

  • xmlns:cp="http://inspire.ec.europa.eu/schemas/cp/4.0"

Please note that a namespaces points to an URI (Uniform Resource Identifier), not an URL (Uniform Resource Locator).

An URI may be a real URL (internet link) you can open using a browser, but it doesn't have to be!

Coming back to filter expressions, we have to define the correct namespace prefixes within our expression in order to get them working. But how to find them out?

I'll show you 2 possible ways to get the right namespaces.

  1. Examine a feature

  2. Examine the Translation Log

Examine a feature

For the first way, we will use another WFS.

This time a service providing traffic meters for counting vehicles in North Rhine-Westphalia. The WFS URL is:

https://www.wfs.nrw.de/wfs/strassen_nrw?SERVICE=WFS&VERSION=2.0.0

Add a WFS reader to your FME Workbench and configure it the following way:

Select Zaehlstellen (counting points) as [Feature Types].

Set [Max Features] to 1 and run the reader (Run Just This). You should see a point feature east of Dortmund.

Switch to Translation Log.

Scroll upwards and look for <WFS> GetFeature URL.

Click on the blue colored URL or copy it to your browser.

https://www.wfs.nrw.de/wfs/strassen_nrw?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=ms%3AZaehlstellen&NAMESPACES=xmlns%28ms%2Chttp%3A%2F%2Fmapserver.gis.umn.edu%2Fmapserver%29&OUTPUTFORMAT=application%2Fgml%2Bxml%3B%20version%3D3.2&COUNT=1

Now, you'll see one feature encoded as GML/XML in your browser:

<wfs:FeatureCollection xmlns:ms="http://mapserver.gis.umn.edu/mapserver" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:wfs="http://www.opengis.net/wfs/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver https://www.wfs.nrw.de/wfs/strassen_nrw?SERVICE=WFS&VERSION=2.0.0&REQUEST=DescribeFeatureType&TYPENAME=ms:Zaehlstellen&OUTPUTFORMAT=application%2Fgml%2Bxml%3B%20version%3D3.2 http://www.opengis.net/wfs/2.0 http://www.wfs.nrw.de/schemas/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://www.wfs.nrw.de/schemas/gml/3.2.1/gml.xsd" timeStamp="2023-08-13T18:16:59" numberMatched="unknown" numberReturned="1" next="https://www.wfs.nrw.de/wfs/strassen_nrw?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=ms%3AZaehlstellen&NAMESPACES=xmlns(ms%2Chttp%3A%2F%2Fmapserver.gis.umn.edu%2Fmapserver)&OUTPUTFORMAT=application%2Fgml%2Bxml%3B%20version%3D3.2&COUNT=1&STARTINDEX=1">
<wfs:boundedBy>
<gml:Envelope srsName="urn:ogc:def:crs:EPSG::25832">
<gml:lowerCorner>397181.079930 5708784.375433</gml:lowerCorner>
<gml:upperCorner>397181.079930 5708784.375433</gml:upperCorner>
</gml:Envelope>
</wfs:boundedBy>
<wfs:member>
<ms:Zaehlstellen gml:id="Zaehlstellen.4411120A4411111A">
<gml:boundedBy>
<gml:Envelope srsName="urn:ogc:def:crs:EPSG::25832">
<gml:lowerCorner>397181.079930 5708784.375433</gml:lowerCorner>
<gml:upperCorner>397181.079930 5708784.375433</gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
<ms:Shape>
<gml:Point gml:id="Zaehlstellen.4411120A4411111A.1" srsName="urn:ogc:def:crs:EPSG::25832">
<gml:pos>397181.079930 5708784.375433</gml:pos>
</gml:Point>
</ms:Shape>
<ms:ABS>4411120A4411111A</ms:ABS>
<ms:STAT>1782.000000000000000</ms:STAT>
<ms:ZSTNR>44112109</ms:ZSTNR>
<ms:ZSTART>manuelle Zählstelle (SVZ)</ms:ZSTART>
<ms:ZSTARTKNZ>03</ms:ZSTARTKNZ>
<ms:ERFASSART>Keine Werte (d.h. weder DZ, noch TM, noch MZ-Ergebnisse vorliegend)</ms:ERFASSART>
<ms:BZUSTAND>aktiv (in Betrieb)</ms:BZUSTAND>
<ms:NETZSTAND>20230630190000</ms:NETZSTAND>
</ms:Zaehlstellen>
</wfs:member>
</wfs:FeatureCollection>

We will concentrate on the counting point number "ZSTNR":

<ms:ZSTNR>44112109</ms:ZSTNR>

As you can see, the attribute comes already together with a namespace prefix: ms:ZSTNR

Perfect!

The only thing we still need is the URI. Finding the URI is also easy! Just look at the xml header:

xmlns:ms="http://mapserver.gis.umn.edu/mapserver"

Putting the things together, we can modify the filter expression from above the following way:

<fes:Filter 
   xmlns:fes="http://www.opengis.net/fes/2.0"
   xmlns:ms="http://mapserver.gis.umn.edu/mapserver">
   <fes:PropertyIsEqualTo>
      <fes:ValueReference>ms:ZSTNR</fes:ValueReference>
      <fes:Literal>52082215</fes:Literal>
   </fes:PropertyIsEqualTo>
</fes:Filter>

Please use counting point 52082215.

Modify your reader as follows by right clicking on it:

Clear [Max Features] and paste the new filter expression in [XML Filter Expression] editor and run the Workbench.

As a result, you'll see a counting point in Bonn, near World Conference Center Bonn (WCCB).

Great! This was easy.

Examine the Translation Log

Coming back to our cadastral parcel service, the things are a little bit more difficult.

Add or modify your cadastral parcel WFS reader the following way:

Parameter
Value

WFS URL

Feature Types

CadastralParcel

Max Features

1

Run the reader and inspect the Translation Log.

Look for <WFS> GetFeature URL, which is:

https://www.wfs.nrw.de:443/geobasis/wfs_nw_inspire-flurstuecke_alkis?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=cp%3ACadastralParcel&NAMESPACES=xmlns%28cp%2Chttp%3A%2F%2Finspire.ec.europa.eu%2Fschemas%2Fcp%2F4.0%29&OUTPUTFORMAT=application%2Fgml%2Bxml%3B%20version%3D3.2&COUNT=1

and open it in a browser.

Save the returned document and open it either in a browser or in a text editor (remember: it is a GML/XML document). It will look like this (some content is turned of "..." for a clearer view):

<wfs:FeatureCollection xmlns:base="http://inspire.ec.europa.eu/schemas/base/3.3" xmlns="http://inspire.ec.europa.eu/schemas/cp/4.0" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:wfs="http://www.opengis.net/wfs/2.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" timeStamp="2023-08-13T19:11:31.688+02:00" numberReturned="1" numberMatched="unknown" xsi:schemaLocation="http://inspire.ec.europa.eu/schemas/cp/4.0 http://www.wfs.nrw.de/aaa-suite/schema/inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd http://www.opengis.net/wfs/2.0 http://www.wfs.nrw.de/aaa-suite/schema/ogc/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://www.wfs.nrw.de/aaa-suite/schema/ogc/gml/3.2.1/gml.xsd">
<wfs:boundedBy>
<gml:Envelope srsName="http://www.opengis.net/def/crs/epsg/0/25832" srsDimension="2">
...
</gml:Envelope>
</wfs:boundedBy>
<wfs:member>
<CadastralParcel gml:id="CadastralParcel_05439400700069______">
<gml:identifier codeSpace="http://inspire.ec.europa.eu/ids">https://registry.gdi-de.org/id/de.nw.inspire.cp.alkis/CadastralParcel_05439400700069______</gml:identifier>
<areaValue uom="m2">35190.00</areaValue>
<beginLifespanVersion>2017-01-16T15:22:59Z</beginLifespanVersion>
<endLifespanVersion nilReason="other:unpopulated" xsi:nil="true"/>
<geometry>
...
</geometry>
<inspireId>
<base:Identifier>
<base:localId>CadastralParcel_05439400700069______</base:localId>
<base:namespace>https://registry.gdi-de.org/id/de.nw.inspire.cp.alkis</base:namespace>
</base:Identifier>
</inspireId>
<label>69</label>
<nationalCadastralReference>05439400700069______</nationalCadastralReference>
<referencePoint>
<gml:Point gml:id="o11001.id.1.ST_PointOnSurface__T_.position__.Geom_0" srsName="http://www.opengis.net/def/crs/epsg/0/25832" srsDimension="2">
<gml:pos>315035.325 5579575.262</gml:pos>
</gml:Point>
</referencePoint>
<validFrom>1974-01-01</validFrom>
<validTo nilReason="other:unpopulated" xsi:nil="true"/>
<zoning xlink:href="https://registry.gdi-de.org/id/de.nw.inspire.cp.alkis/CadastralZoning_054394007"/>
</CadastralParcel>
</wfs:member>
</wfs:FeatureCollection>

We concentrate on the cadastral parcel number attribute:

<nationalCadastralReference>05439400700069______</nationalCadastralReference>

As you can see, it comes without a namespace prefix, while we're expecting cp:nationalCadastralReference.

What a bummer! Well then?

We may inspect the header where we will find

http://www.wfs.nrw.de/aaa-suite/schema/inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd

This URL points to a XML schema (*.xsd). It can also be opened with a browser or text editor.

If you're familiar with XML schemata you may recognize, that the cp:-prefix is passed to nationalCadastralReference from BasicPropertyUnitType which is a higher-order complex type.

But, never mind!

We will ask our best friend: the Translation Log!

First, we will inspect the feature in Visual Preview (or Inspector)

Next open [Columns...]

On the left side scroll down to the end of the list of available columns and activate xml_ns_uri.

For a better view, you may move it up near nationalCadastralReference.

Close the dialog and inspect the new attribute:

http://inspire.ec.europa.eu/schemas/cp/4.0

Keep this in mind and switch to Translation Log.

Scroll up until you see "Using prefix ..." and look for the URI in question.

Using prefix 'cp' for uri 'http://inspire.ec.europa.eu/schemas/cp/4.0'

Surprise: the correspondig prefix is cp!

How cool is this!?

To complete the formula, we have to discuss versions.

Choosing the right version

While treating GetCapabilities I mentioned, that you should use version 2.0.0 if your WFS supports this version.

Why?

Because there are some differences between

  • version 1.0.0, 1.1.0

  • version 2.0

While we used <fes:ValueReference> to query version 2.0 WFS, we have to use <ogc:PropertyName> for version 1.x

Version
Element
Schema

1.0.0

ogc:PropertyName

[FMEdir]\xml\schemas\filter\1.0.0\filter.xsd

1.1.0

ogc:PropertyName

[FMEdir]\xml\schemas\filter\1.1.0\filter.xsd

2.0.0

fes:ValueReference

[FMEdir]\xml\schemas\filter\2.0.0\filter.xsd

You may have a look at the corresponding schema called filter.xsd.

It can be found in FMEs installation directory (FMEdir) on your local hard drive.

Another little but tricky difference concerns the defintion of wildcards when using PropertyIsLike:

Version
Expression
Expression
Expression

1.0.0

wildCard

singleChar

escape

1.1.0

wildCard

singleChar

escapeChar

2.0.0

wildCard

singleChar

escapeChar

We will discuss the usage of PropertyIsLike later on.

To summarize let's have a look at our traffic meter WFS from above:

Parameter
Value

WFS URL

Version

1.0.0 and 2.0.0

Features Types

Zaehlstellen (counting points)

Max Features

leave blank

If you want to query the service in version 1.0.0/1.1.0 the filter expression should look like this:

<ogc:Filter 
   xmlns:ogc="http://www.opengis.net/ogc"
   xmlns:ms="http://mapserver.gis.umn.edu/mapserver">
   <ogc:PropertyIsEqualTo>
      <ogc:PropertyName>ms:ZSTNR</ogc:PropertyName>
      <ogc:Literal>52082215</ogc:Literal>
   </ogc:PropertyIsEqualTo>
</ogc:Filter>

and in version 2.0.0 like this:

<fes:Filter 
   xmlns:fes="http://www.opengis.net/fes/2.0"
   xmlns:ms="http://mapserver.gis.umn.edu/mapserver">
   <fes:PropertyIsEqualTo>
      <fes:ValueReference>ms:ZSTNR</fes:ValueReference>
      <fes:Literal>52082215</fes:Literal>
   </fes:PropertyIsEqualTo>
</fes:Filter>

Caution: You may notice that <fes:ValueReference> works with version 1.0.0/1.1.0 as well!

This is usually the case, if the WFS supports both, 1.x and 2.0.

But if you stumble on a version 1.x only WFS, please keep this in mind!

Ok, now we know how to collect the information we need to write perfect filter expressions.

Let's put the theory into practice!

Good to know #3

Sometimes it is a good idea to check if your XML Filter Expression is well formed, i.e. if the syntax is correct.

Especially if you copy & paste some code from the internet it may happen that quotation marks or something else gets lost.

There are tons of XML validation tools in the internet. My personal favorite is

https://jsonformatter.org/xml-validator

Q: What's going wrong here?

A: The closing quotation mark is missing!

Previous1st FilterNextBulk Processing

Last updated 9 months ago

https://www.wfs.nrw.de/geobasis/wfs_nw_inspire-flurstuecke_alkis?
https://www.wfs.nrw.de/wfs/strassen_nrw?