Skip to content
Permalink
Browse files

[FEATURE][QGIS Server] STARTINDEX param in WFS GetFeature Request

STARTINDEX is standard in WFS 2.0, but it's an extension for WFS 1.0 implemented in QGIS Server.

STARTINDEX can be used to skip some features in the result set and in combination with MAXFEATURES provides for the ability to use WFS GetFeature to page through results. Note that STARTINDEX=0 means start with the first feature, skipping none.
  • Loading branch information
rldhont committed Dec 14, 2015
1 parent cf60ddb commit 30b3b6856a2204dcc7cea0f769cde6ac8278e823
Showing with 67 additions and 30 deletions.
  1. +67 −30 src/server/qgswfsserver.cpp
@@ -411,6 +411,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format

long maxFeat = 0;
long maxFeatures = -1;
long startIndex = 0;
long featureCounter = 0;
int layerPrec = 8;

@@ -426,6 +427,8 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format

if ( docElem.hasAttribute( "maxFeatures" ) )
maxFeatures = docElem.attribute( "maxFeatures" ).toLong();
if ( docElem.hasAttribute( "startIndex" ) )
startIndex = docElem.attribute( "startIndex" ).toLong();

QDomNodeList queryNodes = docElem.elementsByTagName( "Query" );
QDomElement queryElem;
@@ -624,13 +627,16 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
req.setSubsetOfAttributes( attrIndexes );

QgsFeatureIterator fit = layer->getFeatures( req );
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat ) )
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat + startIndex ) )
{
if ( featureCounter == 0 )
if ( featureCounter == startIndex )
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );

setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
++featCounter;
if ( featureCounter >= startIndex )
{
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
++featCounter;
}
++featureCounter;
}
}
@@ -643,7 +649,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
{
throw QgsMapServiceException( "RequestNotWellFormed", filter->parserErrorString() );
}
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat ) )
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat + startIndex ) )
{
expressionContext.setFeature( feature );

@@ -654,26 +660,32 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
}
if ( res.toInt() != 0 )
{
if ( featureCounter == 0 )
if ( featureCounter == startIndex )
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );

setGetFeature( request, format, &feature, featureCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
if ( featureCounter >= startIndex )
{
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
++featCounter;
}
++featureCounter;
++featCounter;
}
}
}
}
}
else
{
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat ) )
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat + startIndex ) )
{
if ( featureCounter == 0 )
if ( featureCounter == startIndex )
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );

setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
++featCounter;
if ( featureCounter >= startIndex )
{
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
++featCounter;
}
++featureCounter;
}
}
@@ -692,7 +704,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
QgsMessageLog::logMessage( mErrors.join( "\n" ) );

QgsMapLayerRegistry::instance()->removeAllMapLayers();
if ( featureCounter == 0 )
if ( featureCounter <= startIndex )
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );
endGetFeature( request, format );
return 0;
@@ -806,6 +818,15 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
maxFeat = mfString.toLong( &mfOk, 10 );
}

//read STARTINDEX
QMap<QString, QString>::const_iterator siIt = mParameters.find( "STARTINDEX" );
if ( siIt != mParameters.end() )
{
QString siString = siIt.value();
bool siOk;
startIndex = siString.toLong( &siOk, 10 );
}

//read PROPERTYNAME
mWithGeom = true;
mPropertyName = "*";
@@ -959,7 +980,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
{
throw QgsMapServiceException( "RequestNotWellFormed", QString( "Expression filter error message: %1." ).arg( filter->parserErrorString() ) );
}
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat ) )
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat + startIndex ) )
{
expressionContext.setFeature( feature );
QVariant res = filter->evaluate( &expressionContext );
@@ -969,11 +990,14 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
}
if ( res.toInt() != 0 )
{
if ( featureCounter == 0 )
if ( featureCounter == startIndex )
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );

setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
++featCounter;
if ( featureCounter >= startIndex )
{
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
++featCounter;
}
++featureCounter;
}
}
@@ -1040,13 +1064,16 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
req.setSubsetOfAttributes( attrIndexes );

QgsFeatureIterator fit = layer->getFeatures( req );
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat ) )
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat + startIndex ) )
{
if ( featureCounter == 0 )
if ( featureCounter == startIndex )
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );

setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
++featCounter;
if ( featureCounter >= startIndex )
{
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
++featCounter;
}
++featureCounter;
}
}
@@ -1078,7 +1105,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
}
req.setSubsetOfAttributes( attrIndexes );
QgsFeatureIterator fit = layer->getFeatures( req );
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat ) )
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat + startIndex ) )
{
expressionContext.setFeature( feature );
QVariant res = filter->evaluate( &expressionContext );
@@ -1088,12 +1115,15 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
}
if ( res.toInt() != 0 )
{
if ( featureCounter == 0 )
if ( featureCounter == startIndex )
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );

setGetFeature( request, format, &feature, featureCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
if ( featureCounter >= startIndex )
{
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
++featCounter;
}
++featureCounter;
++featCounter;
}
}
}
@@ -1121,14 +1151,17 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
}
req.setSubsetOfAttributes( attrIndexes );
QgsFeatureIterator fit = layer->getFeatures( req );
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat ) )
while ( fit.nextFeature( feature ) && ( maxFeatures == -1 || featureCounter < maxFeat + startIndex ) )
{
mErrors << QString( "The feature %2 of layer for the TypeName '%1'" ).arg( tnStr ).arg( featureCounter );
if ( featureCounter == 0 )
if ( featureCounter == startIndex )
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );

setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
++featCounter;
if ( featureCounter >= startIndex )
{
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
++featCounter;
}
++featureCounter;
}
}
@@ -1142,7 +1175,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
}

QgsMapLayerRegistry::instance()->removeAllMapLayers();
if ( featureCounter == 0 )
if ( featureCounter <= startIndex )
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );
endGetFeature( request, format );

@@ -1217,6 +1250,10 @@ void QgsWFSServer::startGetFeature( QgsRequestHandler& request, const QString& f
{
mapUrl.removeQueryItem( queryIt->first );
}
else if ( queryIt->first.compare( "STARTINDEX", Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );
}
else if ( queryIt->first.compare( "PROPERTYNAME", Qt::CaseInsensitive ) == 0 )
{
mapUrl.removeQueryItem( queryIt->first );

3 comments on commit 30b3b68

@nyalldawson

This comment has been minimized.

Copy link
Contributor

@nyalldawson nyalldawson replied Dec 15, 2015

Any chance of unit tests for this stuff?

@rldhont

This comment has been minimized.

Copy link
Contributor Author

@rldhont rldhont replied Dec 15, 2015

This PR #2583 will help me to create one.

@rldhont

This comment has been minimized.

Copy link
Contributor Author

@rldhont rldhont replied Dec 15, 2015

done in this commit 9e8e868

Please sign in to comment.
You can’t perform that action at this time.