Skip to content

Commit 268c20f

Browse files
authoredSep 14, 2018
Merge pull request #7887 from pblottiere/server_filter_2
[server] Add suport for OGC FE version 2 in GetMap requests
2 parents 8c31299 + d30f93f commit 268c20f

File tree

7 files changed

+112
-25
lines changed

7 files changed

+112
-25
lines changed
 

‎src/core/qgsogcutils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3172,14 +3172,14 @@ QgsExpressionNodeBinaryOperator *QgsOgcUtilsExpressionFromFilter::nodeBinaryOper
31723172

31733173
QDomElement operandElem = element.firstChildElement();
31743174
std::unique_ptr<QgsExpressionNode> expr( nodeFromOgcFilter( operandElem ) );
3175-
std::unique_ptr<QgsExpressionNode> leftOp( expr->clone() );
31763175

31773176
if ( !expr )
31783177
{
31793178
mErrorMessage = QObject::tr( "invalid left operand for '%1' binary operator" ).arg( element.tagName() );
31803179
return nullptr;
31813180
}
31823181

3182+
std::unique_ptr<QgsExpressionNode> leftOp( expr->clone() );
31833183
for ( operandElem = operandElem.nextSiblingElement(); !operandElem.isNull(); operandElem = operandElem.nextSiblingElement() )
31843184
{
31853185
std::unique_ptr<QgsExpressionNode> opRight( nodeFromOgcFilter( operandElem ) );

‎src/server/services/wms/qgswmsparameters.cpp

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,16 +1248,32 @@ namespace QgsWms
12481248
return style << styles;
12491249
}
12501250

1251-
QMultiMap<QString, QString> QgsWmsParameters::getLayerFilters( const QStringList &layers ) const
1251+
QMultiMap<QString, QgsWmsParametersFilter> QgsWmsParameters::layerFilters( const QStringList &layers ) const
12521252
{
1253+
const QString nsWfs2 = QStringLiteral( "http://www.opengis.net/fes/2.0" );
1254+
const QString prefixWfs2 = QStringLiteral( "<fes:" );
1255+
12531256
const QStringList rawFilters = filters();
1254-
QMultiMap<QString, QString> layerFilters;
1257+
QMultiMap<QString, QgsWmsParametersFilter> filters;
12551258
for ( int i = 0; i < rawFilters.size(); i++ )
12561259
{
12571260
const QString f = rawFilters[i];
1258-
if ( f.startsWith( QLatin1String( "<" ) ) && f.endsWith( QLatin1String( "Filter>" ) ) && i < layers.size() )
1261+
if ( f.startsWith( QLatin1String( "<" ) ) \
1262+
&& f.endsWith( QLatin1String( "Filter>" ) ) \
1263+
&& i < layers.size() )
12591264
{
1260-
layerFilters.insert( layers[i], f );
1265+
QgsWmsParametersFilter filter;
1266+
filter.mFilter = f;
1267+
filter.mType = QgsWmsParametersFilter::OGC_FE;
1268+
filter.mVersion = QgsOgcUtils::FILTER_OGC_1_0;
1269+
1270+
if ( filter.mFilter.contains( nsWfs2 ) \
1271+
|| filter.mFilter.contains( prefixWfs2 ) )
1272+
{
1273+
filter.mVersion = QgsOgcUtils::FILTER_FES_2_0;
1274+
}
1275+
1276+
filters.insert( layers[i], filter );
12611277
}
12621278
else if ( !f.isEmpty() )
12631279
{
@@ -1266,7 +1282,10 @@ namespace QgsWms
12661282
const QStringList splits = f.split( ':' );
12671283
if ( splits.size() == 2 )
12681284
{
1269-
layerFilters.insert( splits[0], splits[1] );
1285+
QgsWmsParametersFilter filter;
1286+
filter.mFilter = splits[1];
1287+
filter.mType = QgsWmsParametersFilter::SQL;
1288+
filters.insert( splits[0], filter );
12701289
}
12711290
else
12721291
{
@@ -1275,7 +1294,7 @@ namespace QgsWms
12751294
}
12761295
}
12771296
}
1278-
return layerFilters;
1297+
return filters;
12791298
}
12801299

12811300
QList<QgsWmsParametersLayer> QgsWmsParameters::layersParameters() const
@@ -1284,7 +1303,7 @@ namespace QgsWms
12841303
const QStringList styles = allStyles();
12851304
const QStringList selection = selections();
12861305
const QList<int> opacities = opacitiesAsInt();
1287-
const QMultiMap<QString, QString> layerFilters = getLayerFilters( layers );
1306+
const QMultiMap<QString, QgsWmsParametersFilter> filters = layerFilters( layers );
12881307

12891308
// selection format: "LayerName:id0,id1;LayerName2:id0,id1;..."
12901309
// several filters can be defined for one layer
@@ -1316,11 +1335,10 @@ namespace QgsWms
13161335
if ( i < opacities.count() )
13171336
param.mOpacity = opacities[i];
13181337

1319-
if ( layerFilters.contains( layer ) )
1338+
if ( filters.contains( layer ) )
13201339
{
1321-
QMultiMap<QString, QString>::const_iterator it;
1322-
it = layerFilters.find( layer );
1323-
while ( it != layerFilters.end() && it.key() == layer )
1340+
auto it = filters.find( layer );
1341+
while ( it != filters.end() && it.key() == layer )
13241342
{
13251343
param.mFilter.append( it.value() );
13261344
++it;

‎src/server/services/wms/qgswmsparameters.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,31 @@
2828
#include "qgsserverrequest.h"
2929
#include "qgslegendsettings.h"
3030
#include "qgsprojectversion.h"
31+
#include "qgsogcutils.h"
3132
#include "qgsserverparameters.h"
3233

3334
namespace QgsWms
3435
{
36+
struct QgsWmsParametersFilter
37+
{
38+
//! Filter type
39+
enum Type
40+
{
41+
UNKNOWN,
42+
SQL,
43+
OGC_FE
44+
};
45+
46+
QString mFilter;
47+
QgsWmsParametersFilter::Type mType = QgsWmsParametersFilter::UNKNOWN;
48+
QgsOgcUtils::FilterVersion mVersion = QgsOgcUtils::FILTER_OGC_1_0; // only if FE
49+
};
50+
3551
struct QgsWmsParametersLayer
3652
{
3753
QString mNickname; // name, id or short name
3854
int mOpacity = -1;
39-
QStringList mFilter; // list of filter
55+
QList<QgsWmsParametersFilter> mFilter; // list of filter
4056
QStringList mSelection; // list of string fid
4157
QString mStyle;
4258
};
@@ -1125,7 +1141,7 @@ namespace QgsWms
11251141
void raiseError( const QString &msg ) const;
11261142
void log( const QString &msg ) const;
11271143

1128-
QMultiMap<QString, QString> getLayerFilters( const QStringList &layers ) const;
1144+
QMultiMap<QString, QgsWmsParametersFilter> layerFilters( const QStringList &layers ) const;
11291145

11301146
QMap<QgsWmsParameter::Name, QgsWmsParameter> mWmsParameters;
11311147
QMap<QString, QMap<QString, QString> > mExternalWMSParameters;

‎src/server/services/wms/qgswmsrenderer.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2795,35 +2795,35 @@ namespace QgsWms
27952795
}
27962796
}
27972797

2798-
void QgsRenderer::setLayerFilter( QgsMapLayer *layer, const QStringList &filters )
2798+
void QgsRenderer::setLayerFilter( QgsMapLayer *layer, const QList<QgsWmsParametersFilter> &filters )
27992799
{
28002800
if ( layer->type() == QgsMapLayer::VectorLayer )
28012801
{
28022802
QgsVectorLayer *filteredLayer = qobject_cast<QgsVectorLayer *>( layer );
2803-
for ( const QString &filter : filters )
2803+
for ( const QgsWmsParametersFilter &filter : filters )
28042804
{
2805-
if ( filter.startsWith( QLatin1String( "<" ) ) && filter.endsWith( QLatin1String( "Filter>" ) ) )
2805+
if ( filter.mType == QgsWmsParametersFilter::OGC_FE )
28062806
{
28072807
// OGC filter
28082808
QDomDocument filterXml;
28092809
QString errorMsg;
2810-
if ( !filterXml.setContent( filter, true, &errorMsg ) )
2810+
if ( !filterXml.setContent( filter.mFilter, true, &errorMsg ) )
28112811
{
28122812
throw QgsBadRequestException( QStringLiteral( "Filter string rejected" ),
2813-
QStringLiteral( "error message: %1. The XML string was: %2" ).arg( errorMsg, filter ) );
2813+
QStringLiteral( "error message: %1. The XML string was: %2" ).arg( errorMsg, filter.mFilter ) );
28142814
}
28152815
QDomElement filterElem = filterXml.firstChildElement();
2816-
std::unique_ptr<QgsExpression> expression( QgsOgcUtils::expressionFromOgcFilter( filterElem, filteredLayer ) );
2816+
std::unique_ptr<QgsExpression> expression( QgsOgcUtils::expressionFromOgcFilter( filterElem, filter.mVersion, filteredLayer ) );
28172817

28182818
if ( expression )
28192819
{
28202820
mFeatureFilter.setFilter( filteredLayer, *expression );
28212821
}
28222822
}
2823-
else
2823+
else if ( filter.mType == QgsWmsParametersFilter::SQL )
28242824
{
28252825
// QGIS (SQL) filter
2826-
if ( !testFilterStringSafety( filter ) )
2826+
if ( !testFilterStringSafety( filter.mFilter ) )
28272827
{
28282828
throw QgsBadRequestException( QStringLiteral( "Filter string rejected" ),
28292829
QStringLiteral( "The filter string %1"
@@ -2833,10 +2833,10 @@ namespace QgsWms
28332833
" Allowed Keywords and special characters are "
28342834
" AND,OR,IN,<,>=,>,>=,!=,',',(,),DMETAPHONE,SOUNDEX."
28352835
" Not allowed are semicolons in the filter expression." ).arg(
2836-
filter ) );
2836+
filter.mFilter ) );
28372837
}
28382838

2839-
QString newSubsetString = filter;
2839+
QString newSubsetString = filter.mFilter;
28402840
if ( !filteredLayer->subsetString().isEmpty() )
28412841
{
28422842
newSubsetString.prepend( ") AND (" );

‎src/server/services/wms/qgswmsrenderer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ namespace QgsWms
162162
void setLayerOpacity( QgsMapLayer *layer, int opacity ) const;
163163

164164
// Set layer filter
165-
void setLayerFilter( QgsMapLayer *layer, const QStringList &filter );
165+
void setLayerFilter( QgsMapLayer *layer, const QList<QgsWmsParametersFilter> &filters );
166166

167167
// Set layer python filter
168168
void setLayerAccessControlFilter( QgsMapLayer *layer ) const;

‎tests/src/python/test_qgsserver_wms_getmap.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,59 @@ def test_wms_getmap_filter_ogc_with_empty(self):
866866
r, h = self._result(self._execute_request(qs))
867867
self._img_diff_error(r, h, "WMS_GetMap_Filter_OGC3")
868868

869+
def test_wms_getmap_filter_ogc_v2(self):
870+
# with namespace
871+
filter = ('<fes:Filter xmlns:fes=\"http://www.opengis.net/fes/2.0\">'
872+
'<fes:PropertyIsEqualTo>'
873+
'<fes:ValueReference>name</fes:ValueReference>'
874+
'<fes:Literal>eurasia</fes:Literal>'
875+
'</fes:PropertyIsEqualTo>'
876+
'</fes:Filter>')
877+
878+
qs = "?" + "&".join(["%s=%s" % i for i in list({
879+
"MAP": urllib.parse.quote(self.projectPath),
880+
"SERVICE": "WMS",
881+
"VERSION": "1.1.1",
882+
"REQUEST": "GetMap",
883+
"LAYERS": "Country,Hello",
884+
"STYLES": "",
885+
"FORMAT": "image/png",
886+
"BBOX": "-16817707,-4710778,5696513,14587125",
887+
"HEIGHT": "500",
888+
"WIDTH": "500",
889+
"CRS": "EPSG:3857",
890+
"FILTER": filter
891+
}.items())])
892+
893+
r, h = self._result(self._execute_request(qs))
894+
self._img_diff_error(r, h, "WMS_GetMap_Filter_OGC_V2")
895+
896+
# without namespace (only with prefix)
897+
filter = ('<fes:Filter>'
898+
'<fes:PropertyIsEqualTo>'
899+
'<fes:ValueReference>name</fes:ValueReference>'
900+
'<fes:Literal>eurasia</fes:Literal>'
901+
'</fes:PropertyIsEqualTo>'
902+
'</fes:Filter>')
903+
904+
qs = "?" + "&".join(["%s=%s" % i for i in list({
905+
"MAP": urllib.parse.quote(self.projectPath),
906+
"SERVICE": "WMS",
907+
"VERSION": "1.1.1",
908+
"REQUEST": "GetMap",
909+
"LAYERS": "Country,Hello",
910+
"STYLES": "",
911+
"FORMAT": "image/png",
912+
"BBOX": "-16817707,-4710778,5696513,14587125",
913+
"HEIGHT": "500",
914+
"WIDTH": "500",
915+
"CRS": "EPSG:3857",
916+
"FILTER": filter
917+
}.items())])
918+
919+
r, h = self._result(self._execute_request(qs))
920+
self._img_diff_error(r, h, "WMS_GetMap_Filter_OGC_V2")
921+
869922
def test_wms_getmap_selection(self):
870923
qs = "?" + "&".join(["%s=%s" % i for i in list({
871924
"MAP": urllib.parse.quote(self.projectPath),

0 commit comments

Comments
 (0)
Please sign in to comment.