Skip to content

Commit

Permalink
[WFS provider] Handle gml:description/identifier/name attributes (fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault authored and nyalldawson committed Sep 26, 2022
1 parent a38a4f4 commit ec96b49
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 52 deletions.
1 change: 1 addition & 0 deletions src/providers/wfs/qgswfsconstants.cpp
Expand Up @@ -41,6 +41,7 @@ const QString QgsWFSConstants::URI_PARAM_HIDEDOWNLOADPROGRESSDIALOG( QStringLite
const QString QgsWFSConstants::URI_PARAM_PAGING_ENABLED( "pagingEnabled" );
const QString QgsWFSConstants::URI_PARAM_PAGE_SIZE( "pageSize" );
const QString QgsWFSConstants::URI_PARAM_WFST_1_1_PREFER_COORDINATES( "preferCoordinatesForWfsT11" );
const QString QgsWFSConstants::URI_PARAM_SKIP_INITIAL_GET_FEATURE( "skipInitialGetFeature" );

const QString QgsWFSConstants::VERSION_AUTO( QStringLiteral( "auto" ) );

1 change: 1 addition & 0 deletions src/providers/wfs/qgswfsconstants.h
Expand Up @@ -49,6 +49,7 @@ struct QgsWFSConstants
static const QString URI_PARAM_PAGING_ENABLED;
static const QString URI_PARAM_PAGE_SIZE;
static const QString URI_PARAM_WFST_1_1_PREFER_COORDINATES;
static const QString URI_PARAM_SKIP_INITIAL_GET_FEATURE;

//
static const QString VERSION_AUTO;
Expand Down
10 changes: 9 additions & 1 deletion src/providers/wfs/qgswfsdatasourceuri.cpp
Expand Up @@ -171,7 +171,8 @@ QSet<QString> QgsWFSDataSourceURI::unknownParamKeys() const
QgsWFSConstants::URI_PARAM_HIDEDOWNLOADPROGRESSDIALOG,
QgsWFSConstants::URI_PARAM_PAGING_ENABLED,
QgsWFSConstants::URI_PARAM_PAGE_SIZE,
QgsWFSConstants::URI_PARAM_WFST_1_1_PREFER_COORDINATES
QgsWFSConstants::URI_PARAM_WFST_1_1_PREFER_COORDINATES,
QgsWFSConstants::URI_PARAM_SKIP_INITIAL_GET_FEATURE
};

QSet<QString> l_unknownParamKeys;
Expand Down Expand Up @@ -416,6 +417,13 @@ bool QgsWFSDataSourceURI::preferCoordinatesForWfst11() const
mURI.param( QgsWFSConstants::URI_PARAM_WFST_1_1_PREFER_COORDINATES ).toUpper() == QLatin1String( "TRUE" );
}

bool QgsWFSDataSourceURI::skipInitialGetFeature() const
{
if ( !mURI.hasParam( QgsWFSConstants::URI_PARAM_SKIP_INITIAL_GET_FEATURE ) )
return false;
return mURI.param( QgsWFSConstants::URI_PARAM_SKIP_INITIAL_GET_FEATURE ).toUpper() == QLatin1String( "TRUE" );
}

QString QgsWFSDataSourceURI::build( const QString &baseUri,
const QString &typeName,
const QString &crsString,
Expand Down
3 changes: 3 additions & 0 deletions src/providers/wfs/qgswfsdatasourceuri.h
Expand Up @@ -137,6 +137,9 @@ class QgsWFSDataSourceURI
//! Return set of unknown parameter keys in the URI.
QSet<QString> unknownParamKeys() const;

//! Whether the initial GetFeature request, used to determine if gml:description/name/identifiers are used, should be skipped
bool skipInitialGetFeature() const;

private:
QgsDataSourceUri mURI;
QgsAuthorizationSettings mAuth;
Expand Down
46 changes: 41 additions & 5 deletions src/providers/wfs/qgswfsprovider.cpp
Expand Up @@ -175,10 +175,31 @@ QgsWFSProvider::QgsWFSProvider( const QString &uri, const ProviderOptions &optio
mShared->setCurrentRect( QgsRectangle() );
};

//Failed to detect feature type from describeFeatureType -> get first feature from layer to detect type
if ( mShared->mWKBType == QgsWkbTypes::Unknown )
{
GetGeometryTypeFromOneFeature( true );
// For WFS >= 1.1, by default, issue a GetFeature on one feature to check
// if gml:description, gml:identifier, gml:name attributes are
// present (unless mShared->mURI.skipInitialGetFeature() returns false)
// Another reason to issue it if we do not known the exact geometry type
// from describeFeatureType()
if ( !mShared->mWFSVersion.startsWith( QLatin1String( "1.0" ) ) &&
!mShared->mURI.skipInitialGetFeature() )
{
// Try to see if gml:description, gml:identifier, gml:name attributes are
// present. So insert them temporarily in mShared->mFields so that the
// GML parser can detect them.
const auto addGMLFields = [ = ]( bool forceAdd )
{
if ( mShared->mFields.indexOf( QStringLiteral( "description" ) ) < 0 && ( forceAdd || mSampleFeatureHasDescription ) )
mShared->mFields.append( QgsField( QStringLiteral( "description" ), QVariant::String, QStringLiteral( "xsd:string" ) ) );
if ( mShared->mFields.indexOf( QStringLiteral( "identifier" ) ) < 0 && ( forceAdd || mSampleFeatureHasIdentifier ) )
mShared->mFields.append( QgsField( QStringLiteral( "identifier" ), QVariant::String, QStringLiteral( "xsd:string" ) ) );
if ( mShared->mFields.indexOf( QStringLiteral( "name" ) ) < 0 && ( forceAdd || mSampleFeatureHasName ) )
mShared->mFields.append( QgsField( QStringLiteral( "name" ), QVariant::String, QStringLiteral( "xsd:string" ) ) );
};

const QgsFields fieldsBackup = mShared->mFields;
addGMLFields( true );

GetGeometryTypeFromOneFeature( mShared->mWKBType == QgsWkbTypes::Unknown );

// If we still didn't get the geometry type, and have a filter, temporarily
// disable the filter.
Expand All @@ -193,6 +214,13 @@ QgsWFSProvider::QgsWFSProvider( const QString &uri, const ProviderOptions &optio
}
else if ( mShared->mWKBType == QgsWkbTypes::Unknown )
GetGeometryTypeFromOneFeature( false );

// Edit the final mFields to add the description, identifier, name fields
// if they were actually found.
mShared->mFields.clear();
addGMLFields( false );
for ( const QgsField &field : fieldsBackup )
mShared->mFields.append( field );
}
}

Expand Down Expand Up @@ -721,7 +749,7 @@ void QgsWFSProvider::pushErrorSlot( const QString &errorMsg )

void QgsWFSProvider::featureReceivedAnalyzeOneFeature( QVector<QgsFeatureUniqueIdPair> list )
{
if ( list.size() != 0 )
if ( list.size() != 0 && mShared->mWKBType == QgsWkbTypes::Unknown )
{
QgsFeature feat = list[0].first;
QgsGeometry geometry = feat.geometry();
Expand Down Expand Up @@ -780,6 +808,14 @@ void QgsWFSProvider::featureReceivedAnalyzeOneFeature( QVector<QgsFeatureUniqueI
}
}
}
if ( list.size() != 0 )
{
QgsFeature feat = list[0].first;
feat.padAttributes( mShared->mFields.count() );
mSampleFeatureHasDescription = !feat.attribute( "description" ).isNull();
mSampleFeatureHasIdentifier = !feat.attribute( "identifier" ).isNull();
mSampleFeatureHasName = !feat.attribute( "name" ).isNull();
}
}

QString QgsWFSProvider::subsetString() const
Expand Down
9 changes: 9 additions & 0 deletions src/providers/wfs/qgswfsprovider.h
Expand Up @@ -139,6 +139,15 @@ class QgsWFSProvider final: public QgsVectorDataProvider
//! Mutable data shared between provider and feature sources
std::shared_ptr<QgsWFSSharedData> mShared;

//! Field set by featureReceivedAnalyzeOneFeature() if a "description" field is set in the sample feature
bool mSampleFeatureHasDescription = false;

//! Field set by featureReceivedAnalyzeOneFeature() if a "identifier" field is set in the sample feature
bool mSampleFeatureHasIdentifier = false;

//! Field set by featureReceivedAnalyzeOneFeature() if a "name" field is set in the sample feature
bool mSampleFeatureHasName = false;

/**
* Invalidates cache of shared object
*/
Expand Down

0 comments on commit ec96b49

Please sign in to comment.