From a6bd16583fdb6aa3a5ec7c78bc2cdb4305f11b02 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 25 Jan 2024 17:29:44 +0100 Subject: [PATCH] QgsVectorLayerUtils::guessFriendlyIdentifierField(): improve heuristics to work better with WFS layers analyzed with the GMLAS driver --- src/core/vector/qgsvectorlayerutils.cpp | 30 +++++++++++++++++++- tests/src/python/test_qgsvectorlayerutils.py | 13 +++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/core/vector/qgsvectorlayerutils.cpp b/src/core/vector/qgsvectorlayerutils.cpp index fc5468155a64..42d423d0c523 100644 --- a/src/core/vector/qgsvectorlayerutils.cpp +++ b/src/core/vector/qgsvectorlayerutils.cpp @@ -1239,9 +1239,37 @@ QString QgsVectorLayerUtils::guessFriendlyIdentifierField( const QgsFields &fiel break; } - const QString candidateName = bestCandidateName.isEmpty() ? bestCandidateNameWithAntiCandidate : bestCandidateName; + QString candidateName = bestCandidateName.isEmpty() ? bestCandidateNameWithAntiCandidate : bestCandidateName; if ( !candidateName.isEmpty() ) { + // Special case for layers got from WFS using the OGR GMLAS field parsing logic. + // Such layers contain a "id" field (the gml:id attribute of the object), + // as well as a gml_name (a ) element. However this gml:name is often + // absent, partly because it is a property of the base class in GML schemas, and + // that a lot of readers are not able to deduce its potential presence. + // So try to look at another field whose name would end with _name + // And fallback to using the "id" field that should always be filled. + if ( candidateName == QLatin1String( "gml_name" ) && + fields.indexOf( QStringLiteral( "id" ) ) >= 0 ) + { + candidateName.clear(); + // Try to find a field ending with "_name", which is not "gml_name" + for ( const QgsField &field : fields ) + { + const QString fldName = field.name(); + if ( fldName != QLatin1String( "gml_name" ) && fldName.endsWith( QLatin1String( "_name" ) ) ) + { + candidateName = fldName; + break; + } + } + if ( candidateName.isEmpty() ) + { + // Fallback to "id" + candidateName = QStringLiteral( "id" ); + } + } + if ( foundFriendly ) *foundFriendly = true; return candidateName; diff --git a/tests/src/python/test_qgsvectorlayerutils.py b/tests/src/python/test_qgsvectorlayerutils.py index f1d01e98490b..b467c828dbd2 100644 --- a/tests/src/python/test_qgsvectorlayerutils.py +++ b/tests/src/python/test_qgsvectorlayerutils.py @@ -880,6 +880,19 @@ def testGuessFriendlyIdentifierField(self): fields.append(QgsField('org', QVariant.String)) self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'station') + # Particular case for WFS layers analyzed with the GMLAS driver. + # We prioritize a field ending with _name, but which is not gml_name + fields = QgsFields() + fields.append(QgsField('id', QVariant.String)) + fields.append(QgsField('gml_name', QVariant.String)) + fields.append(QgsField('other_name', QVariant.String)) + self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'other_name') + + fields = QgsFields() + fields.append(QgsField('id', QVariant.String)) + fields.append(QgsField('gml_name', QVariant.String)) + self.assertEqual(QgsVectorLayerUtils.guessFriendlyIdentifierField(fields), 'id') + if __name__ == '__main__': unittest.main()