Skip to content

Commit c8ed4c1

Browse files
authored
Merge pull request #6279 from mhugent/featureinfo_gml_id
Server: if there is a primary key, use the pk value(s) as gml id inst…
2 parents 9aa6a4d + 40b67e2 commit c8ed4c1

File tree

6 files changed

+111
-30
lines changed

6 files changed

+111
-30
lines changed

python/server/qgswfserver.sip

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ class QgsWFSServer: public QgsOWSServer
104104
protected:
105105

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

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

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

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

122125
void addTransactionResult( QDomDocument& responseDoc, QDomElement& responseElem, const QString& status, const QString& locator, const QString& message );
123126
};

src/server/qgsowsserver.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,28 @@ void QgsOWSServer::restoreLayerFilters( const QHash<QgsMapLayer*, QString>& filt
6464
}
6565
}
6666
}
67+
68+
QString QgsOWSServer::featureGmlId( const QgsFeature* f, const QgsAttributeList& pkAttributes )
69+
{
70+
if ( !f )
71+
{
72+
return QString();
73+
}
74+
75+
if ( pkAttributes.isEmpty() )
76+
{
77+
return QString::number( f->id() );
78+
}
79+
80+
QString pkId;
81+
QgsAttributeList::const_iterator it = pkAttributes.constBegin();
82+
for ( ; it != pkAttributes.constEnd(); ++it )
83+
{
84+
if ( it != pkAttributes.constBegin() )
85+
{
86+
pkId.append( pkSeparator() );
87+
}
88+
pkId.append( f->attribute( *it ).toString() );
89+
}
90+
return pkId;
91+
}

src/server/qgsowsserver.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "qgsaccesscontrol.h"
2424
#endif
2525

26+
#include "qgsfield.h"
2627
#include <QHash>
2728

2829
class QgsMapLayer;
@@ -54,6 +55,8 @@ class QgsOWSServer
5455
*/
5556
static void restoreLayerFilters( const QHash < QgsMapLayer*, QString >& filterMap );
5657

58+
static QString pkSeparator() { return "@@"; }
59+
5760
private:
5861
QgsOWSServer() {}
5962

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

79+
/** Creates gml id for feature. Returns primary key value or feature id in case there is no PK
80+
* @param f feature
81+
* @param pkAttributes list of attribute indices used as primary key
82+
* @return pk as string or feature id
83+
*/
84+
static QString featureGmlId( const QgsFeature* f, const QgsAttributeList& pkAttributes );
85+
7686
};
7787

7888
/** RAII class to restore layer filters on destruction

src/server/qgswfsserver.cpp

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
603603
if ( featureCounter == 0 )
604604
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );
605605

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

608608
fid = "";
609609
++featCounter;
@@ -642,7 +642,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
642642

643643
if ( featureCounter >= startIndex )
644644
{
645-
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
645+
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );
646646
++featCounter;
647647
}
648648
++featureCounter;
@@ -696,7 +696,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
696696

697697
if ( featureCounter >= startIndex )
698698
{
699-
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
699+
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );
700700
++featCounter;
701701
}
702702
++featureCounter;
@@ -714,7 +714,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
714714

715715
if ( featureCounter >= startIndex )
716716
{
717-
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
717+
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );
718718
++featCounter;
719719
}
720720
++featureCounter;
@@ -977,7 +977,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
977977
if ( featureCounter == 0 )
978978
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );
979979

980-
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
980+
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );
981981
++featCounter;
982982
++featureCounter;
983983
}
@@ -1026,7 +1026,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
10261026

10271027
if ( featureCounter >= startIndex )
10281028
{
1029-
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
1029+
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );
10301030
++featCounter;
10311031
}
10321032
++featureCounter;
@@ -1063,7 +1063,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
10631063
if ( featureCounter == 0 )
10641064
startGetFeature( request, format, layerPrec, layerCrs, &searchRect );
10651065

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

10681068
fid = "";
10691069
++featCounter;
@@ -1102,7 +1102,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
11021102

11031103
if ( featureCounter >= startIndex )
11041104
{
1105-
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
1105+
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );
11061106
++featCounter;
11071107
}
11081108
++featureCounter;
@@ -1151,7 +1151,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
11511151

11521152
if ( featureCounter >= startIndex )
11531153
{
1154-
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
1154+
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );
11551155
++featCounter;
11561156
}
11571157
++featureCounter;
@@ -1190,7 +1190,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format
11901190

11911191
if ( featureCounter >= startIndex )
11921192
{
1193-
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes );
1193+
setGetFeature( request, format, &feature, featCounter, layerPrec, layerCrs, attrIndexes, layerExcludedAttributes, provider->pkAttributeIndexes() );
11941194
++featCounter;
11951195
}
11961196
++featureCounter;
@@ -1363,7 +1363,8 @@ void QgsWFSServer::startGetFeature( QgsRequestHandler& request, const QString& f
13631363
fcString = "";
13641364
}
13651365

1366-
void QgsWFSServer::setGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes ) /*const*/
1366+
void QgsWFSServer::setGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes,
1367+
const QgsAttributeList& pkAttributes ) /*const*/
13671368
{
13681369
if ( !feat->isValid() )
13691370
return;
@@ -1376,7 +1377,7 @@ void QgsWFSServer::setGetFeature( QgsRequestHandler& request, const QString& for
13761377
fcString += " ";
13771378
else
13781379
fcString += " ,";
1379-
fcString += createFeatureGeoJSON( feat, prec, crs, attrIndexes, excludedAttributes );
1380+
fcString += createFeatureGeoJSON( feat, prec, crs, attrIndexes, excludedAttributes, pkAttributes );
13801381
fcString += "\n";
13811382

13821383
result = fcString.toUtf8();
@@ -1389,12 +1390,12 @@ void QgsWFSServer::setGetFeature( QgsRequestHandler& request, const QString& for
13891390
QDomElement featureElement;
13901391
if ( format == "GML3" )
13911392
{
1392-
featureElement = createFeatureGML3( feat, gmlDoc, prec, crs, attrIndexes, excludedAttributes );
1393+
featureElement = createFeatureGML3( feat, gmlDoc, prec, crs, attrIndexes, excludedAttributes, pkAttributes );
13931394
gmlDoc.appendChild( featureElement );
13941395
}
13951396
else
13961397
{
1397-
featureElement = createFeatureGML2( feat, gmlDoc, prec, crs, attrIndexes, excludedAttributes );
1398+
featureElement = createFeatureGML2( feat, gmlDoc, prec, crs, attrIndexes, excludedAttributes, pkAttributes );
13981399
gmlDoc.appendChild( featureElement );
13991400
}
14001401

@@ -1871,7 +1872,39 @@ QgsFeatureIds QgsWFSServer::getFeatureIdsFromFilter( const QDomElement& filterEl
18711872
fid = fidElem.attribute( "fid" );
18721873
if ( fid.contains( "." ) )
18731874
fid = fid.section( ".", 1, 1 );
1874-
fids.insert( fid.toLongLong( &conversionSuccess ) );
1875+
QgsAttributeList pkAttributes = provider->pkAttributeIndexes();
1876+
if ( pkAttributes.isEmpty() )
1877+
{
1878+
fids.insert( fid.toLongLong( &conversionSuccess ) );
1879+
}
1880+
else
1881+
{
1882+
//assume ID is the primary key, as it is more stable than the feature ID
1883+
QgsFeature feature;
1884+
const QgsFields& fields = provider->fields();
1885+
1886+
QString expressionString;
1887+
QStringList pkValues = fid.split( pkSeparator() );
1888+
int pkExprSize = qMin( pkAttributes.size(), pkValues.size() );
1889+
for ( int i = 0; i < pkExprSize; ++i )
1890+
{
1891+
if ( i > 0 )
1892+
{
1893+
expressionString.append( " AND " );
1894+
}
1895+
QString fieldName = fields[ pkAttributes.at( i )].name();
1896+
expressionString.append( fieldName + " = " + pkValues.at( i ) );
1897+
}
1898+
QgsExpression pkExpression( expressionString );
1899+
1900+
QgsExpressionContext exprContext = QgsExpressionContextUtils::createFeatureBasedContext( feature, fields );
1901+
QgsFeatureRequest fReq( pkExpression, exprContext );
1902+
QgsFeatureIterator fIt = provider->getFeatures( fReq );
1903+
if ( fIt.nextFeature( feature ) )
1904+
{
1905+
fids.insert( feature.id() );
1906+
}
1907+
}
18751908
}
18761909
}
18771910
else
@@ -1907,9 +1940,10 @@ QgsFeatureIds QgsWFSServer::getFeatureIdsFromFilter( const QDomElement& filterEl
19071940
return fids;
19081941
}
19091942

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

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

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

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

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

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

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

20582096
const QgsGeometry* geom = feat->constGeometry();

src/server/qgswfsserver.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,20 +112,24 @@ class QgsWFSServer: public QgsOWSServer
112112
protected:
113113

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

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

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

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

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

130134
void addTransactionResult( QDomDocument& responseDoc, QDomElement& responseElem, const QString& status, const QString& locator, const QString& message );
131135
};

src/server/qgswmsserver.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2426,7 +2426,7 @@ int QgsWMSServer::featureInfoFromVectorLayer( QgsVectorLayer* layer,
24262426
else
24272427
{
24282428
QDomElement featureElement = infoDocument.createElement( "Feature" );
2429-
featureElement.setAttribute( "id", FID_TO_STRING( feature.id() ) );
2429+
featureElement.setAttribute( "id", featureGmlId( &feature, layer->dataProvider()->pkAttributeIndexes() ) );
24302430
layerElement.appendChild( featureElement );
24312431

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

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

0 commit comments

Comments
 (0)