Skip to content

Commit b863ca1

Browse files
committed
Allow access to feature attributes by name
1 parent 70ff8ef commit b863ca1

File tree

14 files changed

+189
-1
lines changed

14 files changed

+189
-1
lines changed

python/core/qgsfeature.sip

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,34 @@ class QgsFeature
3939
}
4040
%End
4141

42+
SIP_PYOBJECT __getitem__(const QString& name);
43+
%MethodCode
44+
int fieldIdx = sipCpp->fieldNameIndex(*a0);
45+
if (fieldIdx == -1)
46+
PyErr_SetString(PyExc_KeyError, a0->toAscii());
47+
else
48+
{
49+
QVariant* v = new QVariant( sipCpp->attributeMap().value(fieldIdx) );
50+
sipRes = sipConvertFromInstance(v, sipClass_QVariant, Py_None);
51+
}
52+
%End
53+
4254
void __setitem__(int key, QVariant value);
4355
%MethodCode
4456
sipCpp->addAttribute(a0, *a1);
4557
%End
4658

59+
void __setitem__(const QString& key, QVariant value);
60+
%MethodCode
61+
int fieldIdx = sipCpp->fieldNameIndex(*a0);
62+
if (fieldIdx == -1)
63+
PyErr_SetString(PyExc_KeyError, a0->toAscii());
64+
else
65+
{
66+
sipCpp->addAttribute(fieldIdx, *a1);
67+
}
68+
%End
69+
4770
void __delitem__(int key);
4871
%MethodCode
4972
if (sipCpp->attributeMap().contains(a0))
@@ -52,6 +75,15 @@ class QgsFeature
5275
PyErr_SetString(PyExc_KeyError, QByteArray::number(a0));
5376
%End
5477

78+
void __delitem__(const QString& name);
79+
%MethodCode
80+
int fieldIdx = sipCpp->fieldNameIndex(*a0);
81+
if (fieldIdx == -1)
82+
PyErr_SetString(PyExc_KeyError, a0->toAscii());
83+
else
84+
sipCpp->deleteAttribute(fieldIdx);
85+
%End
86+
5587
//! Constructor
5688
QgsFeature( qint64 id = 0, QString typeName = "" );
5789

@@ -162,5 +194,46 @@ class QgsFeature
162194
*/
163195
void setGeometryAndOwnership( unsigned char * geom /Transfer/, size_t length );
164196

197+
/** Assign a field map with the feature to allow attribute access by attribute name
198+
* @note added in 2.0
199+
*/
200+
void setFieldMap( const QgsFieldMap* fields );
201+
202+
/** Get associated field map. may be NULL
203+
* @note added in 2.0
204+
*/
205+
const QgsFieldMap* fieldMap() const;
206+
207+
/** Insert a value into attribute. Returns false if attribute name could not be converted to index.
208+
* Field map must be associated to make this work.
209+
* @note added in 2.0
210+
*/
211+
bool addAttribute( const QString& name, QVariant value );
212+
213+
/** Change a value of an attribute. Returns false if attribute name could not be converted to index.
214+
* Field map must be associated to make this work.
215+
* @note added in 2.0
216+
*/
217+
bool changeAttribute( const QString& name, QVariant value );
218+
219+
/** Remove an attribute value. Returns false if attribute name could not be converted to index.
220+
* Field map must be associated to make this work.
221+
* @note added in 2.0
222+
*/
223+
bool deleteAttribute( const QString& name );
224+
225+
/** Lookup attribute value from attribute name. Returns invalid variant if attribute name could not be converted to index.
226+
* Field map must be associated to make this work.
227+
* @note added in 2.0
228+
*/
229+
QVariant attribute( const QString& name ) const;
230+
231+
/** Utility method to get attribute index from name. Returns -1 if field does not exist or field map is not associated.
232+
* Field map must be associated to make this work.
233+
* @note added in 2.0
234+
*/
235+
int fieldNameIndex( const QString& fieldName ) const;
236+
237+
165238
}; // class QgsFeature
166239

src/core/qgsfeature.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ email : sherman at mrcc.com
1414
***************************************************************************/
1515

1616
#include "qgsfeature.h"
17+
#include "qgsfield.h"
1718
#include "qgsgeometry.h"
1819
#include "qgsrectangle.h"
1920

@@ -28,6 +29,7 @@ QgsFeature::QgsFeature( QgsFeatureId id, QString typeName )
2829
, mValid( false )
2930
, mDirty( 0 )
3031
, mTypeName( typeName )
32+
, mFields( 0 )
3133
{
3234
// NOOP
3335
}
@@ -40,6 +42,7 @@ QgsFeature::QgsFeature( QgsFeature const & rhs )
4042
, mValid( rhs.mValid )
4143
, mDirty( rhs.mDirty )
4244
, mTypeName( rhs.mTypeName )
45+
, mFields( rhs.mFields )
4346
{
4447

4548
// copy embedded geometry
@@ -60,6 +63,7 @@ QgsFeature & QgsFeature::operator=( QgsFeature const & rhs )
6063
mAttributes = rhs.mAttributes;
6164
mValid = rhs.mValid;
6265
mTypeName = rhs.mTypeName;
66+
mFields = rhs.mFields;
6367

6468
// make sure to delete the old geometry (if exists)
6569
if ( mGeometry && mOwnsGeometry )
@@ -218,3 +222,53 @@ void QgsFeature::clean()
218222
{
219223
mDirty = false;
220224
}
225+
226+
227+
bool QgsFeature::addAttribute( const QString& name, QVariant value )
228+
{
229+
int fieldIdx = fieldNameIndex( name );
230+
if ( fieldIdx == -1 )
231+
return false;
232+
233+
mAttributes.insert( fieldIdx, value );
234+
return true;
235+
}
236+
237+
bool QgsFeature::changeAttribute( const QString& name, QVariant value )
238+
{
239+
return addAttribute( name, value );
240+
}
241+
242+
bool QgsFeature::deleteAttribute( const QString& name )
243+
{
244+
int fieldIdx = fieldNameIndex( name );
245+
if ( fieldIdx == -1 )
246+
return false;
247+
248+
mAttributes.remove( fieldIdx );
249+
return true;
250+
}
251+
252+
QVariant QgsFeature::attribute( const QString& name ) const
253+
{
254+
int fieldIdx = fieldNameIndex( name );
255+
if ( fieldIdx == -1 )
256+
return QVariant();
257+
258+
return mAttributes.value( fieldIdx );
259+
}
260+
261+
int QgsFeature::fieldNameIndex( const QString& fieldName ) const
262+
{
263+
if ( !mFields )
264+
return -1;
265+
266+
for ( QgsFieldMap::const_iterator it = mFields->constBegin(); it != mFields->constEnd(); ++it )
267+
{
268+
if ( QString::compare( it->name(), fieldName, Qt::CaseInsensitive ) == 0 )
269+
{
270+
return it.key();
271+
}
272+
}
273+
return -1;
274+
}

src/core/qgsfeature.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ typedef int QgsFeatureId;
9494
// key = field index, value = field value
9595
typedef QMap<int, QVariant> QgsAttributeMap;
9696

97+
class QgsField;
98+
typedef QMap<int, QgsField> QgsFieldMap;
9799

98100
/** \ingroup core
99101
* The feature class encapsulates a single feature including its id,
@@ -216,6 +218,46 @@ class CORE_EXPORT QgsFeature
216218
*/
217219
void setGeometryAndOwnership( unsigned char * geom, size_t length );
218220

221+
/** Assign a field map with the feature to allow attribute access by attribute name
222+
* @note added in 2.0
223+
*/
224+
void setFieldMap( const QgsFieldMap* fields ) { mFields = fields; }
225+
226+
/** Get associated field map. may be NULL
227+
* @note added in 2.0
228+
*/
229+
const QgsFieldMap* fieldMap() const { return mFields; }
230+
231+
/** Insert a value into attribute. Returns false if attribute name could not be converted to index.
232+
* Field map must be associated to make this work.
233+
* @note added in 2.0
234+
*/
235+
bool addAttribute( const QString& name, QVariant value );
236+
237+
/** Change a value of an attribute. Returns false if attribute name could not be converted to index.
238+
* Field map must be associated to make this work.
239+
* @note added in 2.0
240+
*/
241+
bool changeAttribute( const QString& name, QVariant value );
242+
243+
/** Remove an attribute value. Returns false if attribute name could not be converted to index.
244+
* Field map must be associated to make this work.
245+
* @note added in 2.0
246+
*/
247+
bool deleteAttribute( const QString& name );
248+
249+
/** Lookup attribute value from attribute name. Returns invalid variant if attribute name could not be converted to index.
250+
* Field map must be associated to make this work.
251+
* @note added in 2.0
252+
*/
253+
QVariant attribute( const QString& name ) const;
254+
255+
/** Utility method to get attribute index from name. Returns -1 if field does not exist or field map is not associated.
256+
* Field map must be associated to make this work.
257+
* @note added in 2.0
258+
*/
259+
int fieldNameIndex( const QString& fieldName ) const;
260+
219261
private:
220262

221263
//! feature id
@@ -246,6 +288,8 @@ class CORE_EXPORT QgsFeature
246288
/// feature type name
247289
QString mTypeName;
248290

291+
//! Optional field map for name-based attribute lookups
292+
const QgsFieldMap* mFields;
249293

250294
}; // class QgsFeature
251295

src/providers/delimitedtext/qgsdelimitedtextprovider.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ bool QgsDelimitedTextProvider::nextFeature( QgsFeature& feature )
545545
// At this point the current feature values are valid
546546

547547
feature.setValid( true );
548-
548+
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
549549
feature.setFeatureId( mFid );
550550

551551
if ( geom )

src/providers/gpx/qgsgpxprovider.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ bool QgsGPXProvider::nextFeature( QgsFeature& feature )
157157
feature.setGeometryAndOwnership(( unsigned char * )geo, sizeof( wkbPoint ) );
158158
}
159159
feature.setValid( true );
160+
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
160161

161162
// add attributes if they are wanted
162163
for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
@@ -248,6 +249,7 @@ bool QgsGPXProvider::nextFeature( QgsFeature& feature )
248249
feature.setFeatureId( rte->id );
249250
result = true;
250251
feature.setValid( true );
252+
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
251253

252254
// add attributes if they are wanted
253255
for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
@@ -364,6 +366,7 @@ bool QgsGPXProvider::nextFeature( QgsFeature& feature )
364366
result = true;
365367

366368
feature.setValid( true );
369+
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
367370

368371
// add attributes if they are wanted
369372
for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )

src/providers/grass/qgsgrassprovider.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ bool QgsGrassProvider::nextFeature( QgsFeature& feature )
343343

344344
feature.setFeatureId( id );
345345
feature.clearAttributeMap();
346+
feature.setFieldMap( &fields() ); // allow name-based attribute lookups
346347

347348
// TODO int may be 64 bits (memcpy)
348349
if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) ) /* points or lines */

src/providers/memory/qgsmemoryprovider.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ bool QgsMemoryProvider::nextFeature( QgsFeature& feature )
287287
feature = mSelectIterator.value();
288288
mSelectIterator++;
289289
feature.setValid( true );
290+
feature.setFieldMap( &mFields ); // allow name-based attribute lookups
290291
}
291292

292293
return hasFeature;
@@ -308,6 +309,7 @@ bool QgsMemoryProvider::featureAtId( QgsFeatureId featureId,
308309

309310
feature = *it;
310311
feature.setValid( true );
312+
feature.setFieldMap( &mFields ); // allow name-based attribute lookups
311313
return true;
312314
}
313315

src/providers/mssql/qgsmssqlprovider.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ bool QgsMssqlProvider::nextFeature( QgsFeature& feature )
537537
}
538538

539539
feature.setValid( true );
540+
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
540541
return true;
541542
}
542543
return false;

src/providers/ogr/qgsogrprovider.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,7 @@ bool QgsOgrProvider::featureAtId( QgsFeatureId featureId,
639639
if ( !fet )
640640
return false;
641641

642+
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
642643
feature.setFeatureId( OGR_F_GetFID( fet ) );
643644
feature.clearAttributeMap();
644645
// skip features without geometry
@@ -714,6 +715,7 @@ bool QgsOgrProvider::nextFeature( QgsFeature& feature )
714715
feature.setFeatureId( OGR_F_GetFID( fet ) );
715716
feature.clearAttributeMap();
716717
feature.setTypeName( featureTypeName );
718+
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
717719

718720
/* fetch geometry */
719721
if ( mFetchGeom || mUseIntersect )

src/providers/osm/osmprovider.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ bool QgsOSMDataProvider::fetchNode( QgsFeature& feature, sqlite3_stmt* stmt, boo
651651

652652
feature.setFeatureId( selId );
653653
feature.setValid( true );
654+
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
654655
return true;
655656
}
656657

@@ -762,6 +763,7 @@ bool QgsOSMDataProvider::fetchWay( QgsFeature& feature, sqlite3_stmt* stmt, bool
762763
}
763764
feature.setFeatureId( selId );
764765
feature.setValid( true );
766+
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
765767
return true;
766768
}
767769

src/providers/postgres/qgspostgresprovider.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ bool QgsPostgresProvider::nextFeature( QgsFeature& feature )
672672
mFetched++;
673673

674674
feature.setValid( true );
675+
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
675676
return true;
676677
}
677678

@@ -877,6 +878,7 @@ bool QgsPostgresProvider::featureAtId( QgsFeatureId featureId, QgsFeature& featu
877878
mConnectionRO->closeCursor( cursorName );
878879

879880
feature.setValid( gotit );
881+
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
880882

881883
#if 0
882884
if ( gotit )

src/providers/spatialite/qgsspatialiteprovider.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,7 @@ bool QgsSpatiaLiteProvider::featureAtId( QgsFeatureId featureId, QgsFeature & fe
705705

706706
sqlite3_finalize( stmt );
707707

708+
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
708709
feature.setValid( true );
709710
return true;
710711
}
@@ -731,6 +732,7 @@ bool QgsSpatiaLiteProvider::nextFeature( QgsFeature & feature )
731732
return false;
732733
}
733734

735+
feature.setFieldMap( &attributeFields ); // allow name-based attribute lookups
734736
feature.setValid( true );
735737
return true;
736738
}

src/providers/sqlanywhere/qgssqlanywhereprovider.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ QgsSqlAnywhereProvider::nextFeature( QgsFeature & feature, SqlAnyStatement *stmt
315315

316316
if ( ok )
317317
{
318+
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
318319
// iterate mAttributesToFetch
319320
feature.clearAttributeMap();
320321
for ( QgsAttributeList::const_iterator it = mAttributesToFetch.constBegin()

src/providers/wfs/qgswfsprovider.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ void QgsWFSProvider::copyFeature( QgsFeature* f, QgsFeature& feature, bool fetch
172172
//id and valid
173173
feature.setValid( true );
174174
feature.setFeatureId( f->id() );
175+
feature.setFieldMap( &mFields ); // allow name-based attribute lookups
175176
}
176177

177178
bool QgsWFSProvider::featureAtId( QgsFeatureId featureId,

0 commit comments

Comments
 (0)