QGIS API Documentation  3.2.0-Bonn (bc43194)
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 
29 #include <QJsonDocument>
30 #include <QJsonArray>
31 
32 QgsJsonExporter::QgsJsonExporter( QgsVectorLayer *vectorLayer, int precision )
33  : mPrecision( precision )
34  , mLayer( vectorLayer )
35 {
36  if ( vectorLayer )
37  {
38  mCrs = vectorLayer->crs();
39  mTransform.setSourceCrs( mCrs );
40  }
42 }
43 
45 {
46  mLayer = vectorLayer;
47  if ( vectorLayer )
48  {
49  mCrs = vectorLayer->crs();
50  mTransform.setSourceCrs( mCrs );
51  }
52 }
53 
55 {
56  return mLayer.data();
57 }
58 
60 {
61  mCrs = crs;
62  mTransform.setSourceCrs( mCrs );
63 }
64 
66 {
67  return mCrs;
68 }
69 
70 QString QgsJsonExporter::exportFeature( const QgsFeature &feature, const QVariantMap &extraProperties,
71  const QVariant &id ) const
72 {
73  QString s = QStringLiteral( "{\n \"type\":\"Feature\",\n" );
74 
75  // ID
76  s += QStringLiteral( " \"id\":%1,\n" ).arg( !id.isValid() ? QString::number( feature.id() ) : QgsJsonUtils::encodeValue( id ) );
77 
78  QgsGeometry geom = feature.geometry();
79  if ( !geom.isNull() && mIncludeGeometry )
80  {
81  if ( mCrs.isValid() )
82  {
83  try
84  {
85  QgsGeometry transformed = geom;
86  if ( transformed.transform( mTransform ) == 0 )
87  geom = transformed;
88  }
89  catch ( QgsCsException &cse )
90  {
91  Q_UNUSED( cse );
92  }
93  }
94  QgsRectangle box = geom.boundingBox();
95 
97  {
98  s += QStringLiteral( " \"bbox\":[%1, %2, %3, %4],\n" ).arg( qgsDoubleToString( box.xMinimum(), mPrecision ),
99  qgsDoubleToString( box.yMinimum(), mPrecision ),
100  qgsDoubleToString( box.xMaximum(), mPrecision ),
101  qgsDoubleToString( box.yMaximum(), mPrecision ) );
102  }
103  s += QLatin1String( " \"geometry\":\n " );
104  s += geom.asJson( mPrecision );
105  s += QLatin1String( ",\n" );
106  }
107  else
108  {
109  s += QLatin1String( " \"geometry\":null,\n" );
110  }
111 
112  // build up properties element
113  QString properties;
114  int attributeCounter = 0;
115  if ( mIncludeAttributes || !extraProperties.isEmpty() )
116  {
117  //read all attribute values from the feature
118 
119  if ( mIncludeAttributes )
120  {
121  QgsFields fields = mLayer ? mLayer->fields() : feature.fields();
122 
123  for ( int i = 0; i < fields.count(); ++i )
124  {
125  if ( ( !mAttributeIndexes.isEmpty() && !mAttributeIndexes.contains( i ) ) || mExcludedAttributeIndexes.contains( i ) )
126  continue;
127 
128  if ( attributeCounter > 0 )
129  properties += QLatin1String( ",\n" );
130  QVariant val = feature.attributes().at( i );
131 
132  if ( mLayer )
133  {
134  QgsEditorWidgetSetup setup = fields.at( i ).editorWidgetSetup();
137  val = fieldFormatter->representValue( mLayer.data(), i, setup.config(), QVariant(), val );
138  }
139 
140  properties += QStringLiteral( " \"%1\":%2" ).arg( fields.at( i ).name(), QgsJsonUtils::encodeValue( val ) );
141 
142  ++attributeCounter;
143  }
144  }
145 
146  if ( !extraProperties.isEmpty() )
147  {
148  QVariantMap::const_iterator it = extraProperties.constBegin();
149  for ( ; it != extraProperties.constEnd(); ++it )
150  {
151  if ( attributeCounter > 0 )
152  properties += QLatin1String( ",\n" );
153 
154  properties += QStringLiteral( " \"%1\":%2" ).arg( it.key(), QgsJsonUtils::encodeValue( it.value() ) );
155 
156  ++attributeCounter;
157  }
158  }
159 
160  // related attributes
161  if ( mLayer && mIncludeRelatedAttributes )
162  {
163  QList< QgsRelation > relations = QgsProject::instance()->relationManager()->referencedRelations( mLayer.data() );
164  Q_FOREACH ( const QgsRelation &relation, relations )
165  {
166  if ( attributeCounter > 0 )
167  properties += QLatin1String( ",\n" );
168 
169  QgsFeatureRequest req = relation.getRelatedFeaturesRequest( feature );
171  QgsVectorLayer *childLayer = relation.referencingLayer();
172  QString relatedFeatureAttributes;
173  if ( childLayer )
174  {
175  QgsFeatureIterator it = childLayer->getFeatures( req );
176  QVector<QVariant> attributeWidgetCaches;
177  int fieldIndex = 0;
178  for ( const auto &field : childLayer->fields() )
179  {
180  QgsEditorWidgetSetup setup = field.editorWidgetSetup();
182  attributeWidgetCaches.append( fieldFormatter->createCache( childLayer, fieldIndex, setup.config() ) );
183  fieldIndex++;
184  }
185 
186  QgsFeature relatedFet;
187  int relationFeatures = 0;
188  while ( it.nextFeature( relatedFet ) )
189  {
190  if ( relationFeatures > 0 )
191  relatedFeatureAttributes += QLatin1String( ",\n" );
192 
193  relatedFeatureAttributes += QgsJsonUtils::exportAttributes( relatedFet, childLayer, attributeWidgetCaches );
194  relationFeatures++;
195  }
196  }
197  relatedFeatureAttributes.prepend( '[' ).append( ']' );
198 
199  properties += QStringLiteral( " \"%1\":%2" ).arg( relation.name(), relatedFeatureAttributes );
200  attributeCounter++;
201  }
202  }
203  }
204 
205  bool hasProperties = attributeCounter > 0;
206 
207  s += QLatin1String( " \"properties\":" );
208  if ( hasProperties )
209  {
210  //read all attribute values from the feature
211  s += "{\n" + properties + "\n }\n";
212  }
213  else
214  {
215  s += QLatin1String( "null\n" );
216  }
217 
218  s += '}';
219 
220  return s;
221 }
222 
223 QString QgsJsonExporter::exportFeatures( const QgsFeatureList &features ) const
224 {
225  QStringList featureJSON;
226  Q_FOREACH ( const QgsFeature &feature, features )
227  {
228  featureJSON << exportFeature( feature );
229  }
230 
231  return QStringLiteral( "{ \"type\": \"FeatureCollection\",\n \"features\":[\n%1\n]}" ).arg( featureJSON.join( QStringLiteral( ",\n" ) ) );
232 }
233 
234 
235 
236 //
237 // QgsJsonUtils
238 //
239 
240 QgsFeatureList QgsJsonUtils::stringToFeatureList( const QString &string, const QgsFields &fields, QTextCodec *encoding )
241 {
242  return QgsOgrUtils::stringToFeatureList( string, fields, encoding );
243 }
244 
245 QgsFields QgsJsonUtils::stringToFields( const QString &string, QTextCodec *encoding )
246 {
247  return QgsOgrUtils::stringToFields( string, encoding );
248 }
249 
250 QString QgsJsonUtils::encodeValue( const QVariant &value )
251 {
252  if ( value.isNull() )
253  return QStringLiteral( "null" );
254 
255  switch ( value.type() )
256  {
257  case QVariant::Int:
258  case QVariant::UInt:
259  case QVariant::LongLong:
260  case QVariant::ULongLong:
261  case QVariant::Double:
262  return value.toString();
263 
264  case QVariant::Bool:
265  return value.toBool() ? "true" : "false";
266 
267  case QVariant::StringList:
268  case QVariant::List:
269  case QVariant::Map:
270  return QString::fromUtf8( QJsonDocument::fromVariant( value ).toJson( QJsonDocument::Compact ) );
271 
272  default:
273  case QVariant::String:
274  QString v = value.toString()
275  .replace( '\\', QLatin1String( "\\\\" ) )
276  .replace( '"', QLatin1String( "\\\"" ) )
277  .replace( '\r', QLatin1String( "\\r" ) )
278  .replace( '\b', QLatin1String( "\\b" ) )
279  .replace( '\t', QLatin1String( "\\t" ) )
280  .replace( '/', QLatin1String( "\\/" ) )
281  .replace( '\n', QLatin1String( "\\n" ) );
282 
283  return v.prepend( '"' ).append( '"' );
284  }
285 }
286 
287 QString QgsJsonUtils::exportAttributes( const QgsFeature &feature, QgsVectorLayer *layer, const QVector<QVariant> &attributeWidgetCaches )
288 {
289  QgsFields fields = feature.fields();
290  QString attrs;
291  for ( int i = 0; i < fields.count(); ++i )
292  {
293  if ( i > 0 )
294  attrs += QLatin1String( ",\n" );
295 
296  QVariant val = feature.attributes().at( i );
297 
298  if ( layer )
299  {
300  QgsEditorWidgetSetup setup = layer->fields().at( i ).editorWidgetSetup();
303  val = fieldFormatter->representValue( layer, i, setup.config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
304  }
305 
306  attrs += encodeValue( fields.at( i ).name() ) + ':' + encodeValue( val );
307  }
308  return attrs.prepend( '{' ).append( '}' );
309 }
310 
311 QVariantList QgsJsonUtils::parseArray( const QString &json, QVariant::Type type )
312 {
313  QJsonParseError error;
314  const QJsonDocument jsonDoc = QJsonDocument::fromJson( json.toUtf8(), &error );
315  QVariantList result;
316  if ( error.error != QJsonParseError::NoError )
317  {
318  QgsLogger::warning( QStringLiteral( "Cannot parse json (%1): %2" ).arg( error.errorString(), json ) );
319  return result;
320  }
321  if ( !jsonDoc.isArray() )
322  {
323  QgsLogger::warning( QStringLiteral( "Cannot parse json (%1) as array: %2" ).arg( error.errorString(), json ) );
324  return result;
325  }
326  Q_FOREACH ( const QJsonValue &cur, jsonDoc.array() )
327  {
328  QVariant curVariant = cur.toVariant();
329  if ( curVariant.convert( type ) )
330  result.append( curVariant );
331  else
332  QgsLogger::warning( QStringLiteral( "Cannot convert json array element: %1" ).arg( cur.toString() ) );
333  }
334  return result;
335 }
QString name
Definition: qgsrelation.h:45
QgsFeatureId id
Definition: qgsfeature.h:71
Wrapper for iterator of features from vector data provider or vector layer.
A rectangle specified with double values.
Definition: qgsrectangle.h:40
QVariantMap config() const
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
QString name
Definition: qgsfield.h:57
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source CRS for feature geometries.
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
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).
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:549
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:121
void setSourceCrs(const QgsCoordinateReferenceSystem &crs)
Sets the source CRS for feature geometries.
QString asJson(int precision=17) const
Exports the geometry to a GeoJSON string.
QgsVectorLayer referencingLayer
Definition: qgsrelation.h:43
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:104
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition: qgsfield.cpp:395
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
QgsFields fields
Definition: qgsfeature.h:73
int count() const
Returns number of items.
Definition: qgsfields.cpp:115
QgsVectorLayer * vectorLayer() const
Returns the associated vector layer, if set.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:145
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields, QTextCodec *encoding)
Attempts to parse a string representing a collection of features using OGR.
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
Sets the destination coordinate reference system.
QgsFields fields() const override
Returns the list of fields of this layer.
static QString encodeValue(const QVariant &value)
Encodes a value to a JSON string representation, adding appropriate quotations and escaping where req...
static QgsFields stringToFields(const QString &string, QTextCodec *encoding)
Attempts to retrieve the fields from a GeoJSON string representing a collection of features...
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:237
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
QList< QgsRelation > referencedRelations(QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
static QgsFields stringToFields(const QString &string, QTextCodec *encoding)
Attempts to retrieve the fields from a string representing a collection of features using OGR...
QgsFeatureRequest getRelatedFeaturesRequest(const QgsFeature &feature) const
Creates a request to return all the features on the referencing (child) layer which have a foreign ke...
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
QgsRelationManager relationManager
Definition: qgsproject.h:95
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields, QTextCodec *encoding)
Attempts to parse a GeoJSON string to a collection of features.
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.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Query the layer for features specified in request.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:176
QgsJsonExporter(QgsVectorLayer *vectorLayer=nullptr, int precision=6)
Constructor for QgsJsonExporter.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
QString exportFeatures(const QgsFeatureList &features) const
Returns a GeoJSON string representation of a list of features (feature collection).
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.
Holder for the widget type and its configuration for a field.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:391
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
This class represents a coordinate reference system (CRS).
static QVariantList parseArray(const QString &json, QVariant::Type type)
Parse a simple array (depth=1).
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166
QgsFieldFormatter * fallbackFieldFormatter() const
Returns a basic fallback field formatter which can be used to represent any field in an unspectacular...
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QString exportFeature(const QgsFeature &feature, const QVariantMap &extraProperties=QVariantMap(), const QVariant &id=QVariant()) const
Returns a GeoJSON string representation of a feature.
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.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:427
void setSourceCrs(const QgsCoordinateReferenceSystem &crs)
Sets the source coordinate reference system.
QgsAttributes attributes
Definition: qgsfeature.h:72
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.