QGIS API Documentation  3.17.0-Master (a035f434f4)
qgsjsonutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsjsonutils.h
3  -------------
4  Date : May 206
5  Copyright : (C) 2016 Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsjsonutils.h"
17 #include "qgsfeatureiterator.h"
18 #include "qgsogrutils.h"
19 #include "qgsgeometry.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsrelation.h"
22 #include "qgsrelationmanager.h"
23 #include "qgsproject.h"
24 #include "qgsexception.h"
25 #include "qgslogger.h"
27 #include "qgsfieldformatter.h"
28 #include "qgsapplication.h"
29 #include "qgsfeatureid.h"
30 
31 #include <QJsonDocument>
32 #include <QJsonArray>
33 #include <nlohmann/json.hpp>
34 
36  : mPrecision( precision )
37  , mLayer( vectorLayer )
38 {
39  if ( vectorLayer )
40  {
41  mCrs = vectorLayer->crs();
42  mTransform.setSourceCrs( mCrs );
43  }
44  mTransform.setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
45 }
46 
48 {
49  mLayer = vectorLayer;
50  if ( vectorLayer )
51  {
52  mCrs = vectorLayer->crs();
53  mTransform.setSourceCrs( mCrs );
54  }
55 }
56 
58 {
59  return mLayer.data();
60 }
61 
63 {
64  mCrs = crs;
65  mTransform.setSourceCrs( mCrs );
66 }
67 
69 {
70  return mCrs;
71 }
72 
73 QString QgsJsonExporter::exportFeature( const QgsFeature &feature, const QVariantMap &extraProperties,
74  const QVariant &id, int indent ) const
75 {
76  return QString::fromStdString( exportFeatureToJsonObject( feature, extraProperties, id ).dump( indent ) );
77 }
78 
79 json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, const QVariantMap &extraProperties, const QVariant &id ) const
80 {
81  json featureJson
82  {
83  { "type", "Feature" },
84  };
85  if ( id.isValid() )
86  {
87  bool ok = false;
88  auto intId = id.toLongLong( &ok );
89  if ( ok )
90  {
91  featureJson["id"] = intId;
92  }
93  else
94  {
95  featureJson["id"] = id.toString().toStdString();
96  }
97  }
98  else if ( FID_IS_NULL( feature.id() ) )
99  {
100  featureJson["id"] = nullptr;
101  }
102  else
103  {
104  featureJson["id"] = feature.id();
105  }
106 
107  QgsGeometry geom = feature.geometry();
108  if ( !geom.isNull() && mIncludeGeometry )
109  {
110  if ( mCrs.isValid() )
111  {
112  try
113  {
114  QgsGeometry transformed = geom;
115  if ( mTransformGeometries && transformed.transform( mTransform ) == 0 )
116  geom = transformed;
117  }
118  catch ( QgsCsException &cse )
119  {
120  Q_UNUSED( cse )
121  }
122  }
123  QgsRectangle box = geom.boundingBox();
124 
126  {
127  featureJson[ "bbox" ] =
128  {
129  qgsRound( box.xMinimum(), mPrecision ),
130  qgsRound( box.yMinimum(), mPrecision ),
131  qgsRound( box.xMaximum(), mPrecision ),
132  qgsRound( box.yMaximum(), mPrecision )
133  };
134  }
135  featureJson[ "geometry" ] = geom.asJsonObject( mPrecision );
136  }
137  else
138  {
139  featureJson[ "geometry" ] = nullptr;
140  }
141 
142  // build up properties element
143  int attributeCounter { 0 };
144  json properties;
145  if ( mIncludeAttributes || !extraProperties.isEmpty() )
146  {
147  //read all attribute values from the feature
148  if ( mIncludeAttributes )
149  {
150  QgsFields fields = mLayer ? mLayer->fields() : feature.fields();
151  // List of formatters through we want to pass the values
152  QStringList formattersAllowList;
153  formattersAllowList << QStringLiteral( "KeyValue" )
154  << QStringLiteral( "List" )
155  << QStringLiteral( "ValueRelation" )
156  << QStringLiteral( "ValueMap" );
157 
158  for ( int i = 0; i < fields.count(); ++i )
159  {
160  if ( ( !mAttributeIndexes.isEmpty() && !mAttributeIndexes.contains( i ) ) || mExcludedAttributeIndexes.contains( i ) )
161  continue;
162 
163  QVariant val = feature.attributes().at( i );
164 
165  if ( mLayer )
166  {
167  const QgsEditorWidgetSetup setup = fields.at( i ).editorWidgetSetup();
168  const QgsFieldFormatter *fieldFormatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() );
169  if ( formattersAllowList.contains( fieldFormatter->id() ) )
170  val = fieldFormatter->representValue( mLayer.data(), i, setup.config(), QVariant(), val );
171  }
172 
173  QString name = fields.at( i ).name();
174  if ( mAttributeDisplayName )
175  {
176  name = mLayer->attributeDisplayName( i );
177  }
178  properties[ name.toStdString() ] = QgsJsonUtils::jsonFromVariant( val );
179  attributeCounter++;
180  }
181  }
182 
183  if ( !extraProperties.isEmpty() )
184  {
185  QVariantMap::const_iterator it = extraProperties.constBegin();
186  for ( ; it != extraProperties.constEnd(); ++it )
187  {
188  properties[ it.key().toStdString() ] = QgsJsonUtils::jsonFromVariant( it.value() );
189  attributeCounter++;
190  }
191  }
192 
193  // related attributes
194  if ( mLayer && mIncludeRelatedAttributes )
195  {
196  QList< QgsRelation > relations = QgsProject::instance()->relationManager()->referencedRelations( mLayer.data() );
197  for ( const auto &relation : qgis::as_const( relations ) )
198  {
199  QgsFeatureRequest req = relation.getRelatedFeaturesRequest( feature );
201  QgsVectorLayer *childLayer = relation.referencingLayer();
202  json relatedFeatureAttributes;
203  if ( childLayer )
204  {
205  QgsFeatureIterator it = childLayer->getFeatures( req );
206  QVector<QVariant> attributeWidgetCaches;
207  int fieldIndex = 0;
208  const QgsFields fields { childLayer->fields() };
209  for ( const QgsField &field : fields )
210  {
213  attributeWidgetCaches.append( fieldFormatter->createCache( childLayer, fieldIndex, setup.config() ) );
214  fieldIndex++;
215  }
216  QgsFeature relatedFet;
217  while ( it.nextFeature( relatedFet ) )
218  {
219  relatedFeatureAttributes += QgsJsonUtils::exportAttributesToJsonObject( relatedFet, childLayer, attributeWidgetCaches );
220  }
221  }
222  properties[ relation.name().toStdString() ] = relatedFeatureAttributes;
223  attributeCounter++;
224  }
225  }
226  }
227  featureJson[ "properties" ] = properties;
228  return featureJson;
229 }
230 
231 QString QgsJsonExporter::exportFeatures( const QgsFeatureList &features, int indent ) const
232 {
233  return QString::fromStdString( exportFeaturesToJsonObject( features ).dump( indent ) );
234 }
235 
237 {
238  json data
239  {
240  { "type", "FeatureCollection" },
241  { "features", json::array() }
242  };
243  for ( const QgsFeature &feature : qgis::as_const( features ) )
244  {
245  data["features"].push_back( exportFeatureToJsonObject( feature ) );
246  }
247  return data;
248 }
249 
250 //
251 // QgsJsonUtils
252 //
253 
254 QgsFeatureList QgsJsonUtils::stringToFeatureList( const QString &string, const QgsFields &fields, QTextCodec *encoding )
255 {
256  if ( !encoding )
257  encoding = QTextCodec::codecForName( "UTF-8" );
258 
259  return QgsOgrUtils::stringToFeatureList( string, fields, encoding );
260 }
261 
262 QgsFields QgsJsonUtils::stringToFields( const QString &string, QTextCodec *encoding )
263 {
264  if ( !encoding )
265  encoding = QTextCodec::codecForName( "UTF-8" );
266 
267  return QgsOgrUtils::stringToFields( string, encoding );
268 }
269 
270 QString QgsJsonUtils::encodeValue( const QVariant &value )
271 {
272  if ( value.isNull() )
273  return QStringLiteral( "null" );
274 
275  switch ( value.type() )
276  {
277  case QVariant::Int:
278  case QVariant::UInt:
279  case QVariant::LongLong:
280  case QVariant::ULongLong:
281  case QVariant::Double:
282  return value.toString();
283 
284  case QVariant::Bool:
285  return value.toBool() ? "true" : "false";
286 
287  case QVariant::StringList:
288  case QVariant::List:
289  case QVariant::Map:
290  return QString::fromUtf8( QJsonDocument::fromVariant( value ).toJson( QJsonDocument::Compact ) );
291 
292  default:
293  case QVariant::String:
294  QString v = value.toString()
295  .replace( '\\', QLatin1String( "\\\\" ) )
296  .replace( '"', QLatin1String( "\\\"" ) )
297  .replace( '\r', QLatin1String( "\\r" ) )
298  .replace( '\b', QLatin1String( "\\b" ) )
299  .replace( '\t', QLatin1String( "\\t" ) )
300  .replace( '/', QLatin1String( "\\/" ) )
301  .replace( '\n', QLatin1String( "\\n" ) );
302 
303  return v.prepend( '"' ).append( '"' );
304  }
305 }
306 
307 QString QgsJsonUtils::exportAttributes( const QgsFeature &feature, QgsVectorLayer *layer, const QVector<QVariant> &attributeWidgetCaches )
308 {
309  QgsFields fields = feature.fields();
310  QString attrs;
311  for ( int i = 0; i < fields.count(); ++i )
312  {
313  if ( i > 0 )
314  attrs += QLatin1String( ",\n" );
315 
316  QVariant val = feature.attributes().at( i );
317 
318  if ( layer )
319  {
320  QgsEditorWidgetSetup setup = layer->fields().at( i ).editorWidgetSetup();
323  val = fieldFormatter->representValue( layer, i, setup.config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
324  }
325 
326  attrs += encodeValue( fields.at( i ).name() ) + ':' + encodeValue( val );
327  }
328  return attrs.prepend( '{' ).append( '}' );
329 }
330 
331 QVariantList QgsJsonUtils::parseArray( const QString &json, QVariant::Type type )
332 {
333  QString errorMessage;
334  QVariantList result;
335  try
336  {
337  const auto jObj( json::parse( json.toStdString() ) );
338  if ( ! jObj.is_array() )
339  {
340  throw json::parse_error::create( 0, 0, QStringLiteral( "JSON value must be an array" ).toStdString() );
341  }
342  for ( const auto &item : jObj )
343  {
344  // Create a QVariant from the array item
345  QVariant v;
346  if ( item.is_number_integer() )
347  {
348  v = item.get<int>();
349  }
350  else if ( item.is_number_unsigned() )
351  {
352  v = item.get<unsigned>();
353  }
354  else if ( item.is_number_float() )
355  {
356  // Note: it's a double and not a float on purpose
357  v = item.get<double>();
358  }
359  else if ( item.is_string() )
360  {
361  v = QString::fromStdString( item.get<std::string>() );
362  }
363  else if ( item.is_boolean() )
364  {
365  v = item.get<bool>();
366  }
367  else if ( item.is_null() )
368  {
369  // Fallback to int
370  v = QVariant( type == QVariant::Type::Invalid ? QVariant::Type::Int : type );
371  }
372 
373  // If a destination type was specified (it's not invalid), try to convert
374  if ( type != QVariant::Invalid )
375  {
376  if ( ! v.convert( static_cast<int>( type ) ) )
377  {
378  QgsLogger::warning( QStringLiteral( "Cannot convert json array element to specified type, ignoring: %1" ).arg( v.toString() ) );
379  }
380  else
381  {
382  result.push_back( v );
383  }
384  }
385  else
386  {
387  result.push_back( v );
388  }
389  }
390  }
391  catch ( json::parse_error &ex )
392  {
393  errorMessage = ex.what();
394  QgsLogger::warning( QStringLiteral( "Cannot parse json (%1): %2" ).arg( ex.what(), json ) );
395  }
396 
397  return result;
398 }
399 
400 json QgsJsonUtils::jsonFromVariant( const QVariant &val )
401 {
402  if ( val.isNull() || ! val.isValid() )
403  {
404  return nullptr;
405  }
406  json j;
407  if ( val.type() == QVariant::Type::Map )
408  {
409  const QVariantMap &vMap = val.toMap();
410  json jMap = json::object();
411  for ( auto it = vMap.constBegin(); it != vMap.constEnd(); it++ )
412  {
413  jMap[ it.key().toStdString() ] = jsonFromVariant( it.value() );
414  }
415  j = jMap;
416  }
417  else if ( val.type() == QVariant::Type::List || val.type() == QVariant::Type::StringList )
418  {
419  const QVariantList &vList = val.toList();
420  json jList = json::array();
421  for ( const auto &v : vList )
422  {
423  jList.push_back( jsonFromVariant( v ) );
424  }
425  j = jList;
426  }
427  else
428  {
429  switch ( val.userType() )
430  {
431  case QMetaType::Int:
432  case QMetaType::UInt:
433  case QMetaType::LongLong:
434  case QMetaType::ULongLong:
435  j = val.toLongLong();
436  break;
437  case QMetaType::Double:
438  case QMetaType::Float:
439  j = val.toDouble();
440  break;
441  case QMetaType::Bool:
442  j = val.toBool();
443  break;
444  case QMetaType::QByteArray:
445  j = val.toByteArray().toBase64().toStdString();
446  break;
447  default:
448  j = val.toString().toStdString();
449  break;
450  }
451  }
452  return j;
453 }
454 
455 QVariant QgsJsonUtils::parseJson( const std::string &jsonString )
456 {
457  // tracks whether entire json string is a primitive
458  bool isPrimitive = true;
459 
460  std::function<QVariant( json )> _parser { [ & ]( json jObj ) -> QVariant {
461  QVariant result;
462  if ( jObj.is_array() )
463  {
464  isPrimitive = false;
465  QVariantList results;
466  for ( const auto &item : jObj )
467  {
468  results.push_back( _parser( item ) );
469  }
470  result = results;
471  }
472  else if ( jObj.is_object() )
473  {
474  isPrimitive = false;
475  QVariantMap results;
476  for ( const auto &item : jObj.items() )
477  {
478  const auto key { QString::fromStdString( item.key() ) };
479  const auto value { _parser( item.value() ) };
480  results[ key ] = value;
481  }
482  result = results;
483  }
484  else
485  {
486  if ( jObj.is_number_integer() )
487  {
488  result = jObj.get<int>();
489  }
490  else if ( jObj.is_number_unsigned() )
491  {
492  result = jObj.get<unsigned>();
493  }
494  else if ( jObj.is_boolean() )
495  {
496  result = jObj.get<bool>();
497  }
498  else if ( jObj.is_number_float() )
499  {
500  // Note: it's a double and not a float on purpose
501  result = jObj.get<double>();
502  }
503  else if ( jObj.is_string() )
504  {
505  if ( isPrimitive && jObj.get<std::string>().length() == 0 )
506  {
507  result = QString::fromStdString( jObj.get<std::string>() ).append( "\"" ).insert( 0, "\"" );
508  }
509  else
510  {
511  result = QString::fromStdString( jObj.get<std::string>() );
512  }
513  }
514  else if ( jObj.is_null() )
515  {
516  // Do nothing (leave invalid)
517  }
518  }
519  return result;
520  }
521  };
522 
523  try
524  {
525  const json j = json::parse( jsonString );
526  return _parser( j );
527  }
528  catch ( json::parse_error &ex )
529  {
530  QgsLogger::warning( QStringLiteral( "Cannot parse json (%1): %2" ).arg( QString::fromStdString( ex.what() ),
531  QString::fromStdString( jsonString ) ) );
532  }
533  return QVariant();
534 }
535 
536 QVariant QgsJsonUtils::parseJson( const QString &jsonString )
537 {
538  return parseJson( jsonString.toStdString() );
539 }
540 
541 json QgsJsonUtils::exportAttributesToJsonObject( const QgsFeature &feature, QgsVectorLayer *layer, const QVector<QVariant> &attributeWidgetCaches )
542 {
543  QgsFields fields = feature.fields();
544  json attrs;
545  for ( int i = 0; i < fields.count(); ++i )
546  {
547  QVariant val = feature.attributes().at( i );
548 
549  if ( layer )
550  {
551  QgsEditorWidgetSetup setup = layer->fields().at( i ).editorWidgetSetup();
554  val = fieldFormatter->representValue( layer, i, setup.config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
555  }
556  attrs[fields.at( i ).name().toStdString()] = jsonFromVariant( val );
557  }
558  return attrs;
559 }
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QgsFeatureId id
Definition: qgsfeature.h:64
Wrapper for iterator of features from vector data provider or vector layer.
int precision
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg, bool allowFragments)
QVariantMap config() const
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
static json jsonFromVariant(const QVariant &v)
Converts a QVariant v to a json object.
json exportFeatureToJsonObject(const QgsFeature &feature, const QVariantMap &extraProperties=QVariantMap(), const QVariant &id=QVariant()) const
Returns a QJsonObject representation of a feature.
QString name
Definition: qgsfield.h:59
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source CRS for feature geometries.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
virtual QVariant createCache(QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config) const
Create a cache for a given field.
void setVectorLayer(QgsVectorLayer *vectorLayer)
Sets the associated vector layer (required for related attribute export).
#define FID_IS_NULL(fid)
Definition: qgsfeatureid.h:30
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:583
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:122
void setSourceCrs(const QgsCoordinateReferenceSystem &crs)
Sets the source CRS for feature geometries.
QString exportFeature(const QgsFeature &feature, const QVariantMap &extraProperties=QVariantMap(), const QVariant &id=QVariant(), int indent=-1) const
Returns a GeoJSON string representation of a feature.
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:702
Container of fields for a vector layer.
Definition: qgsfields.h:44
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:123
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition: qgsfield.cpp:559
virtual QString id() const =0
Returns a unique id for this field formatter.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
const QgsCoordinateReferenceSystem & crs
QgsFields fields
Definition: qgsfeature.h:66
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsVectorLayer * vectorLayer() const
Returns the associated vector layer, if set.
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
QString exportFeatures(const QgsFeatureList &features, int indent=-1) const
Returns a GeoJSON string representation of a list of features (feature collection).
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
static QgsFields stringToFields(const QString &string, QTextCodec *encoding=nullptr)
Attempts to retrieve the fields from a GeoJSON string representing a collection of features...
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields, QTextCodec *encoding)
Attempts to parse a string representing a collection of features using OGR.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
Sets the destination coordinate reference system.
static QString encodeValue(const QVariant &value)
Encodes a value to a JSON string representation, adding appropriate quotations and escaping where req...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
static QgsFields stringToFields(const QString &string, QTextCodec *encoding)
Attempts to retrieve the fields from a string representing a collection of features using OGR...
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:49
QgsRelationManager relationManager
Definition: qgsproject.h:105
static json exportAttributesToJsonObject(const QgsFeature &feature, QgsVectorLayer *layer=nullptr, const QVector< QVariant > &attributeWidgetCaches=QVector< QVariant >())
Exports all attributes from a QgsFeature as a json object.
QgsFieldFormatter * fieldFormatter(const QString &id) const
Gets a field formatter by its id.
static QString exportAttributes(const QgsFeature &feature, QgsVectorLayer *layer=nullptr, const QVector< QVariant > &attributeWidgetCaches=QVector< QVariant >())
Exports all attributes from a QgsFeature as a JSON map type.
A field formatter helps to handle and display values for a field.
QgsJsonExporter(QgsVectorLayer *vectorLayer=nullptr, int precision=6)
Constructor for QgsJsonExporter.
json exportFeaturesToJsonObject(const QgsFeatureList &features) const
Returns a JSON object representation of a list of features (feature collection).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
virtual QString representValue(QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value) const
Create a pretty String representation of the value.
virtual json asJsonObject(int precision=17) const
Exports the geometry to a json object.
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places...
Definition: qgis.h:364
Holder for the widget type and its configuration for a field.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:469
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
This class represents a coordinate reference system (CRS).
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields=QgsFields(), QTextCodec *encoding=nullptr)
Attempts to parse a GeoJSON string to a collection of features.
static QVariantList parseArray(const QString &json, QVariant::Type type=QVariant::Invalid)
Parse a simple array (depth=1)
QgsFieldFormatter * fallbackFieldFormatter() const
Returns a basic fallback field formatter which can be used to represent any field in an unspectacular...
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned...
QgsGeometry geometry
Definition: qgsfeature.h:67
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
bool nextFeature(QgsFeature &f)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Represents a vector layer which manages a vector based data sets.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs)
Sets the source coordinate reference system.
const QgsField & field
Definition: qgsfield.h:471
QgsAttributes attributes
Definition: qgsfeature.h:65
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:90
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.