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