WFS GetFeature POST request with filter fails to evaluate xlink:href attribute
Originally tested against deegree 3.3.13, but can confirm the issue remains in 3.3.14 and 3.4-pre17 releases. 

When using a WFS 2 GetFeature POST request where the ValueReference attempts to evaluate an attribute value _(tested specifically with xlink:href, may apply to other attributes)_, deegree fails to return any results.  deegree therefore fails the Filter Encoding Minimum Standard Filter conformance class.

For example using the following service end point: 

http://194.66.252.155/m4eu/services?

Looking at  ge:MappedFeature (ref: http://194.66.252.155/m4eu/services?service=WFS&request=GetFeature&version=2.0.0&typenames=ge:MappedFeature&count=3&)

If we use a **PropertyIsNull** operator (tests the specified property to see if it exists in the resource being evaluated. ref: OpenGIS Filter Encoding 2.0 Encoding Standard, section 7.7.3.5) as below we get no results, but we can see that ge:mappingFrame/@xlink:href should evaluate.

```
<?xml version="1.0" encoding="UTF-8"?>
<GetFeature version="2.0.0" service="WFS" handle="Filter on attribute test with PropertyIsNull deegree" count="100"
    xmlns="http://www.opengis.net/wfs/2.0" 
    xmlns:ge="http://inspire.ec.europa.eu/schemas/ge-core/3.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:wfs="http://www.opengis.net/wfs/2.0"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xsi:schemaLocation="http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd">
    <Query typeNames="ge:MappedFeature">
        <Filter xmlns="http://www.opengis.net/fes/2.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ge="http://inspire.ec.europa.eu/schemas/ge-core/3.0">
            <PropertyIsNull>
                <ValueReference>ge:mappingFrame/@xlink:href</ValueReference>
            </PropertyIsNull>
        </Filter>
    </Query>
</GetFeature>
```

As a sanity check we can see that a similar filter query using the **PropertyIsNull** operator but without the xlink:href attribute returns results:

```
<?xml version="1.0" encoding="UTF-8"?>
<GetFeature version="2.0.0" service="WFS" handle="Filter on element test with PropertyIsNull deegree" count="100"
    xmlns="http://www.opengis.net/wfs/2.0" 
    xmlns:ge="http://inspire.ec.europa.eu/schemas/ge-core/3.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:wfs="http://www.opengis.net/wfs/2.0"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xsi:schemaLocation="http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd">
    <Query typeNames="ge:MappedFeature">
        <Filter xmlns="http://www.opengis.net/fes/2.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ge="http://inspire.ec.europa.eu/schemas/ge-core/3.0">
            <PropertyIsNull>
                <ValueReference>ge:mappingFrame</ValueReference>
            </PropertyIsNull>
        </Filter>
    </Query>`
</GetFeature>
```

It follows too that using a **PropertyIsEqualTo** operator to evaluate the value of the attribute also fails:

```
<?xml version="1.0" encoding="UTF-8"?>
<GetFeature version="2.0.0" service="WFS" handle="Filter on attribute test with PropertyIsEqualTo deegree" count="100"
    xmlns="http://www.opengis.net/wfs/2.0" 
    xmlns:ge="http://inspire.ec.europa.eu/schemas/ge-core/3.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:wfs="http://www.opengis.net/wfs/2.0"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xsi:schemaLocation="http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd">
    <Query typeNames="ge:MappedFeature">
        <Filter xmlns="http://www.opengis.net/fes/2.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ge="http://inspire.ec.europa.eu/schemas/ge-core/3.0">
            <PropertyIsEqualTo>
                <ValueReference>ge:mappingFrame/@xlink:href</ValueReference>
                <Literal>http://inspire.ec.europa.eu/codeList/MappingFrameTerm/topographicSurface</Literal>
            </PropertyIsEqualTo>
        </Filter>
    </Query>
</GetFeature>
```

Just checking that such a query should be possible, here it is working as expected in a GeoServer service.

end point: http://ogc.bgs.ac.uk/digmap625k_gsml32_insp_gs/wfs?  

Looking at  gsml:MappedFeature (ref: http://ogc.bgs.ac.uk/digmap625k_gsml32_insp_gs/wfs?service=WFS&request=GetFeature&version=2.0.0&typenames=gsml:MappedFeature&count=3&)

The null test returns no results

```
<GetFeature
    version="2.0.2"
    service="WFS"
    handle="Filter on attribute test with PropertyIsNull GeoServer"
    count="10"
    xmlns="http://www.opengis.net/wfs/2.0"
    xmlns:fes="http://www.opengis.net/fes/2.0"
    xmlns:gsml="http://xmlns.geosciml.org/GeoSciML-Core/3.2"
    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">
    <Query typeNames="gsml:MappedFeature">
        <Filter  
            xmlns="http://www.opengis.net/fes/2.0" 
            xmlns:xlink="http://www.w3.org/1999/xlink" 
            xmlns:gsml="http://xmlns.geosciml.org/GeoSciML-Core/3.2" >
            <PropertyIsNull>
                <ValueReference>gsml:samplingFrame/@xlink:href</ValueReference>
            </PropertyIsNull>
        </Filter>
    </Query>
</GetFeature>
```

Whilst the **PropertyIsEqualTo** request for an xlink:href attribute gives us results

```
<GetFeature
    version="2.0.2"
    service="WFS"
    handle="Filter on attribute test with PropertyIsEqualTo GeoServer"
    count="10"
    xmlns="http://www.opengis.net/wfs/2.0"
    xmlns:fes="http://www.opengis.net/fes/2.0"
    xmlns:gsml="http://xmlns.geosciml.org/GeoSciML-Core/3.2"
    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">
    <Query typeNames="gsml:MappedFeature">
        <Filter  
            xmlns="http://www.opengis.net/fes/2.0" 
            xmlns:xlink="http://www.w3.org/1999/xlink" 
            xmlns:gsml="http://xmlns.geosciml.org/GeoSciML-Core/3.2" >
            <PropertyIsEqualTo>
                <ValueReference>gsml:samplingFrame/@xlink:href</ValueReference>
                <Literal>http://inspire.ec.europa.eu/codelist/MappingFrameValue/topOfBedrock</Literal>
            </PropertyIsEqualTo>
        </Filter>
    </Query>
</GetFeature>
```

diff --git a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/config/SQLFeatureStoreConfigWriter.java b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/config/SQLFeatureStoreConfigWriter.java
index 0165d69af6..b3b000de74 100644
--- a/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/config/SQLFeatureStoreConfigWriter.java
+++ b/deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/config/SQLFeatureStoreConfigWriter.java
@@ -91,6 +91,8 @@ public class SQLFeatureStoreConfigWriter {
 
     private final MappedAppSchema schema;
 
+    private final List<QName> propertiesWithPrimitiveHref;
+
     /**
      * Creates a new {@link SQLFeatureStoreConfigWriter} instance.
      * 
@@ -98,7 +100,21 @@ public class SQLFeatureStoreConfigWriter {
      *            the mapped application schema to export, must not be <code>null</code>
      */
     public SQLFeatureStoreConfigWriter( MappedAppSchema schema ) {
+        this( schema, null );
+    }
+
+    /**
+     * Creates a new {@link SQLFeatureStoreConfigWriter} instance.
+     *
+     * @param schema
+     *            the mapped application schema to export, must not be <code>null</code>
+     * @param propertiesWithPrimitiveHref
+     *            list of properties which are written with primitive instead of feature mapping, is applied to all
+     *            properties of type {@link FeatureMapping}, may be <code>null</code>
+     */
+    public SQLFeatureStoreConfigWriter( MappedAppSchema schema, List<QName> propertiesWithPrimitiveHref ) {
         this.schema = schema;
+        this.propertiesWithPrimitiveHref = propertiesWithPrimitiveHref;
     }
 
     /**
@@ -211,13 +227,13 @@ public class SQLFeatureStoreConfigWriter {
         writer.writeEndElement();
 
         for ( Mapping particle : ftMapping.getMappings() ) {
-            writeMapping( writer, particle );
+            writeMapping( writer, particle, false );
         }
 
         writer.writeEndElement();
     }
 
-    private void writeMapping( XMLStreamWriter writer, Mapping particle )
+    private void writeMapping( XMLStreamWriter writer, Mapping particle, boolean isHrefPrimitive )
                             throws XMLStreamException {
 
         if ( particle instanceof PrimitiveMapping ) {
@@ -245,17 +261,24 @@ public class SQLFeatureStoreConfigWriter {
             writer.writeEndElement();
         } else if ( particle instanceof FeatureMapping ) {
             FeatureMapping gm = (FeatureMapping) particle;
-            writer.writeStartElement( CONFIG_NS, "Feature" );
-            writer.writeAttribute( "path", particle.getPath().getAsText() );
-            if ( particle.getJoinedTable() != null && !particle.getJoinedTable().isEmpty() ) {
-                writeJoinedTable( writer, particle.getJoinedTable().get( 0 ) );
-            }
-            if ( gm.getHrefMapping() != null ) {
-                writer.writeStartElement( CONFIG_NS, "Href" );
+            if ( gm.getHrefMapping() != null && isHrefPrimitive ) {
+                writer.writeStartElement( CONFIG_NS, "Primitive" );
+                writer.writeAttribute( "path", "@xlink:href" );
                 writer.writeAttribute( "mapping", gm.getHrefMapping().toString() );
                 writer.writeEndElement();
+            } else {
+                writer.writeStartElement( CONFIG_NS, "Feature" );
+                writer.writeAttribute( "path", particle.getPath().getAsText() );
+                if ( particle.getJoinedTable() != null && !particle.getJoinedTable().isEmpty() ) {
+                    writeJoinedTable( writer, particle.getJoinedTable().get( 0 ) );
+                }
+                if ( gm.getHrefMapping() != null ) {
+                    writer.writeStartElement( CONFIG_NS, "Href" );
+                    writer.writeAttribute( "mapping", gm.getHrefMapping().toString() );
+                    writer.writeEndElement();
+                }
+                writer.writeEndElement();
             }
-            writer.writeEndElement();
         } else if ( particle instanceof CompoundMapping ) {
             writer.writeStartElement( CONFIG_NS, "Complex" );
             writer.writeAttribute( "path", particle.getPath().getAsText() );
@@ -264,7 +287,8 @@ public class SQLFeatureStoreConfigWriter {
             }
             CompoundMapping compound = (CompoundMapping) particle;
             for ( Mapping childMapping : compound.getParticles() ) {
-                writeMapping( writer, childMapping );
+                boolean isChildHrefPrimitive = isHrefPrimitive( compound );
+                writeMapping( writer, childMapping, isChildHrefPrimitive );
             }
             writer.writeEndElement();
         } else {
@@ -296,4 +320,10 @@ public class SQLFeatureStoreConfigWriter {
         }
         return name.getLocalPart();
     }
+
+    private boolean isHrefPrimitive( CompoundMapping compound ) {
+        return propertiesWithPrimitiveHref != null
+               && propertiesWithPrimitiveHref.contains( compound.getPath().getAsQName() );
+    }
+
 }
\ No newline at end of file
diff --git a/deegree-services/deegree-webservices-handbook/src/main/sphinx/featurestores.rst b/deegree-services/deegree-webservices-handbook/src/main/sphinx/featurestores.rst
index f21da4ca5f..349085a9ef 100644
--- a/deegree-services/deegree-webservices-handbook/src/main/sphinx/featurestores.rst
+++ b/deegree-services/deegree-webservices-handbook/src/main/sphinx/featurestores.rst
@@ -571,6 +571,8 @@ In order to successfully create a mapping for a feature type from a GML applicat
 .. hint::
    The deegree project aims for a user-interface to help with all steps of creating mapping configurations. If you are interested in working on this (or funding it), don't hesitate to contact the project bodies.
 
+.. _anchor-mapping-rich-feature-types:
+
 """"""""""""""""""""""""""
 Mapping rich feature types
 """"""""""""""""""""""""""
@@ -687,6 +689,38 @@ Here is an overview on all options for ``<Feature>`` elements:
 | ``<Href>``            | 0..1        | Complex | Defines the column that stores the value for ``xlink:href``                  |
 +-----------------------+-------------+---------+------------------------------------------------------------------------------+
 
+.. _anchor-mapping-strategies-href-attributes:
+
+""""""""""""""""""""""""""""""""""""""""""""
+Mapping strategies for xlink:href attributes
+""""""""""""""""""""""""""""""""""""""""""""
+
+There are two different use cases when xlink:href attributes are used:
+
+* 1. Reference on other feature.
+* 2. xlink:href value is used as static value. For example, if a user wants to filter on INSPIRE codelists, filtering is executed on the value of xlink:href.
+
+Case 1. does not allow filtering on the value of xlink:href itself. Case 2. allows filtering on the static value of the xlink:href attribute but the linked feature is not resolved anymore.
+
+Those two cases can be realized by different mappings in SQL feature store configuration:
+
+* 1. Feature mapping is used:
+
+.. code-block:: xml
+
+    <Feature path=".">
+      <Join table="?" fromColumns="designationtype_designation_fk" toColumns="id"/>
+      <Href mapping="designationtype_designation_href"/>
+    </Feature>
+
+* 2. Primitive mapping is used:
+
+.. code-block:: xml
+
+    <Primitive path="@xlink:href" mapping="designationtype_designation_href"/>
+
+For more details see chapter :ref:`anchor-mapping-rich-feature-types`.
+
 """"""""""""""""""""""""""
 Changing the table context
 """"""""""""""""""""""""""
diff --git a/deegree-services/deegree-webservices-handbook/src/main/sphinx/filterencoding.rst b/deegree-services/deegree-webservices-handbook/src/main/sphinx/filterencoding.rst
index f2e5a21e12..f1e1c456a9 100644
--- a/deegree-services/deegree-webservices-handbook/src/main/sphinx/filterencoding.rst
+++ b/deegree-services/deegree-webservices-handbook/src/main/sphinx/filterencoding.rst
@@ -220,6 +220,24 @@ filter operator handles it. In the concrete case this means a normalization of t
 
 .. tip:: Please note, the use of functions within PropertyIsLike filter operators is only possible with FE 2.0. This is the reason for the FE 2.0 notation.
 
+___________________________________________
+Filter expressions on xlink:href attributes
+___________________________________________
+
+Example for filtering on xlink:href attributes:
+
+.. code-block:: xml
+
+    <fes:Filter xmlns:fes="http://www.opengis.net/fes/2.0" xmlns:xlink="http://www.w3.org/1999/xlink">
+      <fes:PropertyIsEqualTo>
+        <fes:PropertyName>property/@xlink:href</fes:PropertyName>
+        <fes:Literal>100</fes:Literal>
+      </fes:PropertyIsEqualTo>
+    </fes:Filter>
+
+deegree applies the filter to the static value of the attribute. This just works if the feature store is configured a certain way. For example, this can be useful if a user wants to filter on INSPIRE codelists.
+
+Chapter :ref:`anchor-mapping-strategies-href-attributes` describes how the configuration of the feature store is done and provides further details regarding usage.
 
 ^^^^^^^^^^^^^^^^^^^
 Custom FE functions
['deegree-services/deegree-webservices-handbook/src/main/sphinx/filterencoding.rst', 'deegree-datastores/deegree-featurestores/deegree-featurestore-sql/src/main/java/org/deegree/feature/persistence/sql/config/SQLFeatureStoreConfigWriter.java', 'deegree-services/deegree-webservices-handbook/src/main/sphinx/featurestores.rst']