Skip to content

Commit bd3d75f

Browse files
committed
Indent on JSON export
1 parent 290909f commit bd3d75f

8 files changed

+638
-476
lines changed

python/core/auto_generated/qgsjsonutils.sip.in

+5-2
Original file line numberDiff line numberDiff line change
@@ -219,14 +219,16 @@ take precedence over attributes included via attributes().
219219

220220
QString exportFeature( const QgsFeature &feature,
221221
const QVariantMap &extraProperties = QVariantMap(),
222-
const QVariant &id = QVariant() ) const;
222+
const QVariant &id = QVariant(),
223+
int indent = -1 ) const;
223224
%Docstring
224225
Returns a GeoJSON string representation of a feature.
225226

226227
:param feature: feature to convert
227228
:param extraProperties: map of extra attributes to include in feature's properties
228229
:param id: optional ID to use as GeoJSON feature's ID instead of input feature's ID. If omitted, feature's
229230
ID is used.
231+
:param indent: number of indentation spaces for generated JSON (defaults to none)
230232

231233
:return: GeoJSON string
232234

@@ -237,11 +239,12 @@ Returns a GeoJSON string representation of a feature.
237239

238240

239241

240-
QString exportFeatures( const QgsFeatureList &features ) const;
242+
QString exportFeatures( const QgsFeatureList &features, int indent = -1 ) const;
241243
%Docstring
242244
Returns a GeoJSON string representation of a list of features (feature collection).
243245

244246
:param features: features to convert
247+
:param indent: number of indentation spaces for generated JSON (defaults to none)
245248

246249
:return: GeoJSON string
247250

src/core/qgsjsonutils.cpp

+54-19
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ QgsCoordinateReferenceSystem QgsJsonExporter::sourceCrs() const
6969
}
7070

7171
QString QgsJsonExporter::exportFeature( const QgsFeature &feature, const QVariantMap &extraProperties,
72-
const QVariant &id ) const
72+
const QVariant &id, int indent ) const
7373
{
74-
return QString::fromStdString( exportFeatureToJsonObject( feature, extraProperties, id ).dump() );
74+
return QString::fromStdString( exportFeatureToJsonObject( feature, extraProperties, id ).dump( indent ) );
7575
}
7676

7777
json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, const QVariantMap &extraProperties, const QVariant &id ) const
@@ -82,7 +82,16 @@ json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, cons
8282
};
8383
if ( id.isValid() )
8484
{
85-
featureJson["id"] = id.toString().toStdString();
85+
bool ok = false;
86+
auto intId = id.toLongLong( &ok );
87+
if ( ok )
88+
{
89+
featureJson["id"] = intId;
90+
}
91+
else
92+
{
93+
featureJson["id"] = id.toString().toStdString();
94+
}
8695
}
8796
else
8897
{
@@ -213,15 +222,19 @@ json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, cons
213222
return featureJson;
214223
}
215224

216-
QString QgsJsonExporter::exportFeatures( const QgsFeatureList &features ) const
225+
QString QgsJsonExporter::exportFeatures( const QgsFeatureList &features, int indent ) const
217226
{
218-
QStringList featureJSON;
227+
json data
228+
{
229+
{ "type", "FeatureCollection" },
230+
{ "features", json::array() }
231+
};
219232
const auto constFeatures = features;
220233
for ( const QgsFeature &feature : constFeatures )
221234
{
222-
featureJSON << exportFeature( feature );
235+
data["features"].push_back( exportFeatureToJsonObject( feature ) );
223236
}
224-
return QStringLiteral( "{ \"type\": \"FeatureCollection\",\n \"features\":[\n%1\n]}" ).arg( featureJSON.join( QStringLiteral( ",\n" ) ) );
237+
return QString::fromStdString( data.dump( indent ) );
225238
}
226239

227240
//
@@ -328,19 +341,41 @@ QVariantList QgsJsonUtils::parseArray( const QString &json, QVariant::Type type
328341

329342
json QgsJsonUtils::jsonFromVariant( const QVariant &val )
330343
{
331-
332-
switch ( val.userType() )
344+
if ( val.type() == QVariant::Type::Map )
333345
{
334-
case QMetaType::Int:
335-
case QMetaType::UInt:
336-
case QMetaType::LongLong:
337-
case QMetaType::ULongLong:
338-
return val.toLongLong();
339-
case QMetaType::Double:
340-
case QMetaType::Float:
341-
return val.toDouble();
342-
default:
343-
return val.toString().toStdString();
346+
const auto vMap { val.toMap() };
347+
auto jMap { json::object() };
348+
for ( auto it = vMap.constBegin(); it != vMap.constEnd(); it++ )
349+
{
350+
jMap[ it.key().toStdString() ] = jsonFromVariant( it.value() );
351+
}
352+
return jMap;
353+
}
354+
else if ( val.type() == QVariant::Type::List )
355+
{
356+
const auto vList{ val.toList() };
357+
auto jList { json::array() };
358+
for ( const auto &v : vList )
359+
{
360+
jList.push_back( jsonFromVariant( v ) );
361+
}
362+
return jList;
363+
}
364+
else
365+
{
366+
switch ( val.userType() )
367+
{
368+
case QMetaType::Int:
369+
case QMetaType::UInt:
370+
case QMetaType::LongLong:
371+
case QMetaType::ULongLong:
372+
return val.toLongLong();
373+
case QMetaType::Double:
374+
case QMetaType::Float:
375+
return val.toDouble();
376+
default:
377+
return val.toString().toStdString();
378+
}
344379
}
345380
}
346381

src/core/qgsjsonutils.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,15 @@ class CORE_EXPORT QgsJsonExporter
198198
* \param extraProperties map of extra attributes to include in feature's properties
199199
* \param id optional ID to use as GeoJSON feature's ID instead of input feature's ID. If omitted, feature's
200200
* ID is used.
201+
* \param indent number of indentation spaces for generated JSON (defaults to none)
201202
* \returns GeoJSON string
202203
* \see exportFeatures()
203204
* \see exportFeatureToJsonObject()
204205
*/
205206
QString exportFeature( const QgsFeature &feature,
206207
const QVariantMap &extraProperties = QVariantMap(),
207-
const QVariant &id = QVariant() ) const;
208+
const QVariant &id = QVariant(),
209+
int indent = -1 ) const;
208210

209211
/**
210212
* Returns a QJsonObject representation of a feature.
@@ -223,10 +225,11 @@ class CORE_EXPORT QgsJsonExporter
223225
/**
224226
* Returns a GeoJSON string representation of a list of features (feature collection).
225227
* \param features features to convert
228+
* \param indent number of indentation spaces for generated JSON (defaults to none)
226229
* \returns GeoJSON string
227230
* \see exportFeature()
228231
*/
229-
QString exportFeatures( const QgsFeatureList &features ) const;
232+
QString exportFeatures( const QgsFeatureList &features, int indent = -1 ) const;
230233

231234
private:
232235

tests/src/app/testqgisappclipboard.cpp

+6-19
Original file line numberDiff line numberDiff line change
@@ -157,24 +157,11 @@ void TestQgisAppClipboard::copyToText()
157157
// GeoJSON
158158
settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::GeoJSON );
159159
result = mQgisApp->clipboard()->generateClipboardText();
160-
QString expected = "{ \"type\": \"FeatureCollection\",\n \"features\":[\n"
161-
"{\n \"type\":\"Feature\",\n"
162-
" \"id\":5,\n"
163-
" \"geometry\":\n"
164-
" {\"type\": \"Point\", \"coordinates\": [5, 6]},\n"
165-
" \"properties\":{\n"
166-
" \"int_field\":9,\n"
167-
" \"string_field\":\"val\"\n"
168-
" }\n"
169-
"},\n"
170-
"{\n \"type\":\"Feature\",\n"
171-
" \"id\":6,\n"
172-
" \"geometry\":\n"
173-
" {\"type\": \"Point\", \"coordinates\": [7, 8]},\n"
174-
" \"properties\":{\n"
175-
" \"int_field\":19,\n"
176-
" \"string_field\":\"val2\"\n"
177-
" }\n}\n]}";
160+
QString expected = "{\"features\":[{\"geometry\":{\"coordinates\":[5.0,6.0],\"type\":\"Point\"},\"id\":5,"
161+
"\"properties\":{\"int_field\":9,\"string_field\":\"val\"},\"type\":\"Feature\"},"
162+
"{\"geometry\":{\"coordinates\":[7.0,8.0],\"type\":\"Point\"},\"id\":6,"
163+
"\"properties\":{\"int_field\":19,\"string_field\":\"val2\"},\"type\":\"Feature\"}],"
164+
"\"type\":\"FeatureCollection\"}";
178165
QCOMPARE( result, expected );
179166

180167
// test CRS is transformed correctly for GeoJSON
@@ -191,7 +178,7 @@ void TestQgisAppClipboard::copyToText()
191178

192179
// just test coordinates as integers - that's enough to verify that reprojection has occurred
193180
// and helps avoid rounding issues
194-
QRegExp regex( "\\[([-\\d.]+), ([-\\d.]+)\\]" );
181+
QRegExp regex( "\\[([-\\d.]+),([-\\d.]+)\\]" );
195182
( void )regex.indexIn( result );
196183
QStringList list = regex.capturedTexts();
197184
QCOMPARE( list.count(), 3 );

0 commit comments

Comments
 (0)