Skip to content

Commit

Permalink
Merge pull request #6279 from mhugent/featureinfo_gml_id
Browse files Browse the repository at this point in the history
Server: if there is a primary key, use the pk value(s) as gml id inst…
  • Loading branch information
mhugent committed Feb 21, 2018
2 parents 9aa6a4d + 40b67e2 commit c8ed4c1
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 30 deletions.
9 changes: 6 additions & 3 deletions python/server/qgswfserver.sip
Expand Up @@ -104,7 +104,8 @@ class QgsWFSServer: public QgsOWSServer
protected:

void startGetFeature( QgsRequestHandler& request, const QString& format, int prec, QgsCoordinateReferenceSystem& crs, QgsRectangle* rect );
void setGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes );
void setGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes,
const QgsAttributeList& pkAttributes = QgsAttributeList());
void endGetFeature( QgsRequestHandler& request, const QString& format );

//method for transaction
Expand All @@ -114,10 +115,12 @@ class QgsWFSServer: public QgsOWSServer
QString createFeatureGeoJSON( QgsFeature* feat, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes ) /*const*/;

//methods to write GML2
QDomElement createFeatureGML2( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes ) /*const*/;
QDomElement createFeatureGML2( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes,
const QgsAttributeList& pkAttributes = QgsAttributeList()) /*const*/;

//methods to write GML3
QDomElement createFeatureGML3( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, QgsAttributeList attrIndexes, QSet<QString> excludedAttributes ) /*const*/;
QDomElement createFeatureGML3( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, QgsAttributeList attrIndexes, QSet<QString> excludedAttributes,
const QgsAttributeList& pkAttributes = QgsAttributeList() ) /*const*/;

void addTransactionResult( QDomDocument& responseDoc, QDomElement& responseElem, const QString& status, const QString& locator, const QString& message );
};
Expand Down
25 changes: 25 additions & 0 deletions src/server/qgsowsserver.cpp
Expand Up @@ -64,3 +64,28 @@ void QgsOWSServer::restoreLayerFilters( const QHash<QgsMapLayer*, QString>& filt
}
}
}

QString QgsOWSServer::featureGmlId( const QgsFeature* f, const QgsAttributeList& pkAttributes )
{
if ( !f )
{
return QString();
}

if ( pkAttributes.isEmpty() )
{
return QString::number( f->id() );
}

QString pkId;
QgsAttributeList::const_iterator it = pkAttributes.constBegin();
for ( ; it != pkAttributes.constEnd(); ++it )
{
if ( it != pkAttributes.constBegin() )
{
pkId.append( pkSeparator() );
}
pkId.append( f->attribute( *it ).toString() );
}
return pkId;
}
10 changes: 10 additions & 0 deletions src/server/qgsowsserver.h
Expand Up @@ -23,6 +23,7 @@
#include "qgsaccesscontrol.h"
#endif

#include "qgsfield.h"
#include <QHash>

class QgsMapLayer;
Expand Down Expand Up @@ -54,6 +55,8 @@ class QgsOWSServer
*/
static void restoreLayerFilters( const QHash < QgsMapLayer*, QString >& filterMap );

static QString pkSeparator() { return "@@"; }

private:
QgsOWSServer() {}

Expand All @@ -73,6 +76,13 @@ class QgsOWSServer
void applyAccessControlLayerFilters( QgsMapLayer* layer, QHash<QgsMapLayer*, QString>& originalLayerFilters ) const;
#endif

/** Creates gml id for feature. Returns primary key value or feature id in case there is no PK
* @param f feature
* @param pkAttributes list of attribute indices used as primary key
* @return pk as string or feature id
*/
static QString featureGmlId( const QgsFeature* f, const QgsAttributeList& pkAttributes );

};

/** RAII class to restore layer filters on destruction
Expand Down
80 changes: 59 additions & 21 deletions src/server/qgswfsserver.cpp
Expand Up @@ -603,7 +603,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
if ( featureCounter == 0 )
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );

setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );

fid = "";
++featCounter;
Expand Down Expand Up @@ -642,7 +642,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format

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

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

if ( featureCounter >= startIndex )
{
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );
++featCounter;
}
++featureCounter;
Expand Down Expand Up @@ -977,7 +977,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
if ( featureCounter == 0 )
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );

setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );
++featCounter;
++featureCounter;
}
Expand Down Expand Up @@ -1026,7 +1026,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format

if ( featureCounter >= startIndex )
{
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );
++featCounter;
}
++featureCounter;
Expand Down Expand Up @@ -1063,7 +1063,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
if ( featureCounter == 0 )
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );

setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );

fid = "";
++featCounter;
Expand Down Expand Up @@ -1102,7 +1102,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format

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

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

if ( featureCounter >= startIndex )
{
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );
++featCounter;
}
++featureCounter;
Expand Down Expand Up @@ -1363,7 +1363,8 @@ void QgsWFSServer::startGetFeature( QgsRequestHandler& request, const QString& f
fcString = "";
}

void QgsWFSServer::setGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes ) /*const*/
void QgsWFSServer::setGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes,
const QgsAttributeList& pkAttributes ) /*const*/
{
if ( !feat->isValid() )
return;
Expand All @@ -1376,7 +1377,7 @@ void QgsWFSServer::setGetFeature( QgsRequestHandler& request, const QString& for
fcString += " ";
else
fcString += " ,";
fcString += createFeatureGeoJSON( feat, prec, crs, attrIndexes, excludedAttributes );
fcString += createFeatureGeoJSON( feat, prec, crs, attrIndexes, excludedAttributes, pkAttributes );
fcString += "\n";

result = fcString.toUtf8();
Expand All @@ -1389,12 +1390,12 @@ void QgsWFSServer::setGetFeature( QgsRequestHandler& request, const QString& for
QDomElement featureElement;
if ( format == "GML3" )
{
featureElement = createFeatureGML3( feat, gmlDoc, prec, crs, attrIndexes, excludedAttributes );
featureElement = createFeatureGML3( feat, gmlDoc, prec, crs, attrIndexes, excludedAttributes, pkAttributes );
gmlDoc.appendChild( featureElement );
}
else
{
featureElement = createFeatureGML2( feat, gmlDoc, prec, crs, attrIndexes, excludedAttributes );
featureElement = createFeatureGML2( feat, gmlDoc, prec, crs, attrIndexes, excludedAttributes, pkAttributes );
gmlDoc.appendChild( featureElement );
}

Expand Down Expand Up @@ -1871,7 +1872,39 @@ QgsFeatureIds QgsWFSServer::getFeatureIdsFromFilter( const QDomElement& filterEl
fid = fidElem.attribute( "fid" );
if ( fid.contains( "." ) )
fid = fid.section( ".", 1, 1 );
fids.insert( fid.toLongLong( &conversionSuccess ) );
QgsAttributeList pkAttributes = provider->pkAttributeIndexes();
if ( pkAttributes.isEmpty() )
{
fids.insert( fid.toLongLong( &conversionSuccess ) );
}
else
{
//assume ID is the primary key, as it is more stable than the feature ID
QgsFeature feature;
const QgsFields& fields = provider->fields();

QString expressionString;
QStringList pkValues = fid.split( pkSeparator() );
int pkExprSize = qMin( pkAttributes.size(), pkValues.size() );
for ( int i = 0; i < pkExprSize; ++i )
{
if ( i > 0 )
{
expressionString.append( " AND " );
}
QString fieldName = fields[ pkAttributes.at( i )].name();
expressionString.append( fieldName + " = " + pkValues.at( i ) );
}
QgsExpression pkExpression( expressionString );

QgsExpressionContext exprContext = QgsExpressionContextUtils::createFeatureBasedContext( feature, fields );
QgsFeatureRequest fReq( pkExpression, exprContext );
QgsFeatureIterator fIt = provider->getFeatures( fReq );
if ( fIt.nextFeature( feature ) )
{
fids.insert( feature.id() );
}
}
}
}
else
Expand Down Expand Up @@ -1907,9 +1940,10 @@ QgsFeatureIds QgsWFSServer::getFeatureIdsFromFilter( const QDomElement& filterEl
return fids;
}

QString QgsWFSServer::createFeatureGeoJSON( QgsFeature* feat, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes ) /*const*/
QString QgsWFSServer::createFeatureGeoJSON( QgsFeature* feat, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes,
const QgsAttributeList& pkAttributes ) /*const*/
{
QString id = QString( "%1.%2" ).arg( mTypeName, FID_TO_STRING( feat->id() ) );
QString id = QString( "%1.%2" ).arg( mTypeName, featureGmlId( feat, pkAttributes ) );

QgsJSONExporter exporter;
exporter.setSourceCrs( crs );
Expand Down Expand Up @@ -1963,14 +1997,16 @@ QString QgsWFSServer::createFeatureGeoJSON( QgsFeature* feat, int prec, QgsCoord
return exporter.exportFeature( f, QVariantMap(), id );
}

QDomElement QgsWFSServer::createFeatureGML2( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes ) /*const*/
QDomElement QgsWFSServer::createFeatureGML2( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes,
const QgsAttributeList& pkAttributes ) /*const*/
{
//gml:FeatureMember
QDomElement featureElement = doc.createElement( "gml:featureMember"/*wfs:FeatureMember*/ );

//qgs:%TYPENAME%
QDomElement typeNameElement = doc.createElement( "qgs:" + mTypeName /*qgs:%TYPENAME%*/ );
typeNameElement.setAttribute( "fid", mTypeName + "." + QString::number( feat->id() ) );
QString gmlId = featureGmlId( feat, pkAttributes );
typeNameElement.setAttribute( "fid", mTypeName + "." + gmlId );
featureElement.appendChild( typeNameElement );

const QgsGeometry* geom = feat->constGeometry();
Expand Down Expand Up @@ -2045,14 +2081,16 @@ QDomElement QgsWFSServer::createFeatureGML2( QgsFeature* feat, QDomDocument& doc
return featureElement;
}

QDomElement QgsWFSServer::createFeatureGML3( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes ) /*const*/
QDomElement QgsWFSServer::createFeatureGML3( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes,
const QgsAttributeList& pkAttributes ) /*const*/
{
//gml:FeatureMember
QDomElement featureElement = doc.createElement( "gml:featureMember"/*wfs:FeatureMember*/ );

//qgs:%TYPENAME%
QDomElement typeNameElement = doc.createElement( "qgs:" + mTypeName /*qgs:%TYPENAME%*/ );
typeNameElement.setAttribute( "gml:id", mTypeName + "." + QString::number( feat->id() ) );
QString gmlId = featureGmlId( feat, pkAttributes );
typeNameElement.setAttribute( "gml:id", mTypeName + "." + gmlId );
featureElement.appendChild( typeNameElement );

const QgsGeometry* geom = feat->constGeometry();
Expand Down
12 changes: 8 additions & 4 deletions src/server/qgswfsserver.h
Expand Up @@ -112,20 +112,24 @@ class QgsWFSServer: public QgsOWSServer
protected:

void startGetFeature( QgsRequestHandler& request, const QString& format, int prec, QgsCoordinateReferenceSystem& crs, QgsRectangle* rect );
void setGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes );
void setGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes,
const QgsAttributeList& pkAttributes = QgsAttributeList() );
void endGetFeature( QgsRequestHandler& request, const QString& format );

//method for transaction
QgsFeatureIds getFeatureIdsFromFilter( const QDomElement& filter, QgsVectorLayer* layer );

//methods to write GeoJSON
QString createFeatureGeoJSON( QgsFeature* feat, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes ) /*const*/;
QString createFeatureGeoJSON( QgsFeature* feat, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes,
const QgsAttributeList& pkAttributes = QgsAttributeList() ) /*const*/;

//methods to write GML2
QDomElement createFeatureGML2( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes ) /*const*/;
QDomElement createFeatureGML2( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes,
const QgsAttributeList& pkAttributes = QgsAttributeList() ) /*const*/;

//methods to write GML3
QDomElement createFeatureGML3( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes ) /*const*/;
QDomElement createFeatureGML3( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes,
const QgsAttributeList& pkAttributes = QgsAttributeList() ) /*const*/;

void addTransactionResult( QDomDocument& responseDoc, QDomElement& responseElem, const QString& status, const QString& locator, const QString& message );
};
Expand Down
5 changes: 3 additions & 2 deletions src/server/qgswmsserver.cpp
Expand Up @@ -2426,7 +2426,7 @@ int QgsWMSServer::featureInfoFromVectorLayer( QgsVectorLayer* layer,
else
{
QDomElement featureElement = infoDocument.createElement( "Feature" );
featureElement.setAttribute( "id", FID_TO_STRING( feature.id() ) );
featureElement.setAttribute( "id", featureGmlId( &feature, layer->dataProvider()->pkAttributeIndexes() ) );
layerElement.appendChild( featureElement );

//read all attribute values from the feature
Expand Down Expand Up @@ -3312,7 +3312,8 @@ QDomElement QgsWMSServer::createFeatureGML(
{
//qgs:%TYPENAME%
QDomElement typeNameElement = doc.createElement( "qgs:" + typeName /*qgs:%TYPENAME%*/ );
typeNameElement.setAttribute( "fid", typeName + "." + QString::number( feat->id() ) );
QString gmlId = featureGmlId( feat, layer->dataProvider()->pkAttributeIndexes() );
typeNameElement.setAttribute( "fid", typeName + "." + gmlId );

const QgsCoordinateTransform* transform = nullptr;
if ( layer && layer->crs() != crs )
Expand Down

0 comments on commit c8ed4c1

Please sign in to comment.