Skip to content

Commit

Permalink
Indent on JSON export
Browse files Browse the repository at this point in the history
  • Loading branch information
elpaso committed May 3, 2019
1 parent 290909f commit bd3d75f
Show file tree
Hide file tree
Showing 8 changed files with 638 additions and 476 deletions.
7 changes: 5 additions & 2 deletions python/core/auto_generated/qgsjsonutils.sip.in
Expand Up @@ -219,14 +219,16 @@ take precedence over attributes included via attributes().

QString exportFeature( const QgsFeature &feature,
const QVariantMap &extraProperties = QVariantMap(),
const QVariant &id = QVariant() ) const;
const QVariant &id = QVariant(),
int indent = -1 ) const;
%Docstring
Returns a GeoJSON string representation of a feature.

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

:return: GeoJSON string

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



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

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

:return: GeoJSON string

Expand Down
73 changes: 54 additions & 19 deletions src/core/qgsjsonutils.cpp
Expand Up @@ -69,9 +69,9 @@ QgsCoordinateReferenceSystem QgsJsonExporter::sourceCrs() const
}

QString QgsJsonExporter::exportFeature( const QgsFeature &feature, const QVariantMap &extraProperties,
const QVariant &id ) const
const QVariant &id, int indent ) const
{
return QString::fromStdString( exportFeatureToJsonObject( feature, extraProperties, id ).dump() );
return QString::fromStdString( exportFeatureToJsonObject( feature, extraProperties, id ).dump( indent ) );
}

json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, const QVariantMap &extraProperties, const QVariant &id ) const
Expand All @@ -82,7 +82,16 @@ json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, cons
};
if ( id.isValid() )
{
featureJson["id"] = id.toString().toStdString();
bool ok = false;
auto intId = id.toLongLong( &ok );
if ( ok )
{
featureJson["id"] = intId;
}
else
{
featureJson["id"] = id.toString().toStdString();
}
}
else
{
Expand Down Expand Up @@ -213,15 +222,19 @@ json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, cons
return featureJson;
}

QString QgsJsonExporter::exportFeatures( const QgsFeatureList &features ) const
QString QgsJsonExporter::exportFeatures( const QgsFeatureList &features, int indent ) const
{
QStringList featureJSON;
json data
{
{ "type", "FeatureCollection" },
{ "features", json::array() }
};
const auto constFeatures = features;
for ( const QgsFeature &feature : constFeatures )
{
featureJSON << exportFeature( feature );
data["features"].push_back( exportFeatureToJsonObject( feature ) );
}
return QStringLiteral( "{ \"type\": \"FeatureCollection\",\n \"features\":[\n%1\n]}" ).arg( featureJSON.join( QStringLiteral( ",\n" ) ) );
return QString::fromStdString( data.dump( indent ) );
}

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

json QgsJsonUtils::jsonFromVariant( const QVariant &val )
{

switch ( val.userType() )
if ( val.type() == QVariant::Type::Map )
{
case QMetaType::Int:
case QMetaType::UInt:
case QMetaType::LongLong:
case QMetaType::ULongLong:
return val.toLongLong();
case QMetaType::Double:
case QMetaType::Float:
return val.toDouble();
default:
return val.toString().toStdString();
const auto vMap { val.toMap() };
auto jMap { json::object() };
for ( auto it = vMap.constBegin(); it != vMap.constEnd(); it++ )
{
jMap[ it.key().toStdString() ] = jsonFromVariant( it.value() );
}
return jMap;
}
else if ( val.type() == QVariant::Type::List )
{
const auto vList{ val.toList() };
auto jList { json::array() };
for ( const auto &v : vList )
{
jList.push_back( jsonFromVariant( v ) );
}
return jList;
}
else
{
switch ( val.userType() )
{
case QMetaType::Int:
case QMetaType::UInt:
case QMetaType::LongLong:
case QMetaType::ULongLong:
return val.toLongLong();
case QMetaType::Double:
case QMetaType::Float:
return val.toDouble();
default:
return val.toString().toStdString();
}
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/core/qgsjsonutils.h
Expand Up @@ -198,13 +198,15 @@ class CORE_EXPORT QgsJsonExporter
* \param extraProperties map of extra attributes to include in feature's properties
* \param id optional ID to use as GeoJSON feature's ID instead of input feature's ID. If omitted, feature's
* ID is used.
* \param indent number of indentation spaces for generated JSON (defaults to none)
* \returns GeoJSON string
* \see exportFeatures()
* \see exportFeatureToJsonObject()
*/
QString exportFeature( const QgsFeature &feature,
const QVariantMap &extraProperties = QVariantMap(),
const QVariant &id = QVariant() ) const;
const QVariant &id = QVariant(),
int indent = -1 ) const;

/**
* Returns a QJsonObject representation of a feature.
Expand All @@ -223,10 +225,11 @@ class CORE_EXPORT QgsJsonExporter
/**
* Returns a GeoJSON string representation of a list of features (feature collection).
* \param features features to convert
* \param indent number of indentation spaces for generated JSON (defaults to none)
* \returns GeoJSON string
* \see exportFeature()
*/
QString exportFeatures( const QgsFeatureList &features ) const;
QString exportFeatures( const QgsFeatureList &features, int indent = -1 ) const;

private:

Expand Down
25 changes: 6 additions & 19 deletions tests/src/app/testqgisappclipboard.cpp
Expand Up @@ -157,24 +157,11 @@ void TestQgisAppClipboard::copyToText()
// GeoJSON
settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::GeoJSON );
result = mQgisApp->clipboard()->generateClipboardText();
QString expected = "{ \"type\": \"FeatureCollection\",\n \"features\":[\n"
"{\n \"type\":\"Feature\",\n"
" \"id\":5,\n"
" \"geometry\":\n"
" {\"type\": \"Point\", \"coordinates\": [5, 6]},\n"
" \"properties\":{\n"
" \"int_field\":9,\n"
" \"string_field\":\"val\"\n"
" }\n"
"},\n"
"{\n \"type\":\"Feature\",\n"
" \"id\":6,\n"
" \"geometry\":\n"
" {\"type\": \"Point\", \"coordinates\": [7, 8]},\n"
" \"properties\":{\n"
" \"int_field\":19,\n"
" \"string_field\":\"val2\"\n"
" }\n}\n]}";
QString expected = "{\"features\":[{\"geometry\":{\"coordinates\":[5.0,6.0],\"type\":\"Point\"},\"id\":5,"
"\"properties\":{\"int_field\":9,\"string_field\":\"val\"},\"type\":\"Feature\"},"
"{\"geometry\":{\"coordinates\":[7.0,8.0],\"type\":\"Point\"},\"id\":6,"
"\"properties\":{\"int_field\":19,\"string_field\":\"val2\"},\"type\":\"Feature\"}],"
"\"type\":\"FeatureCollection\"}";
QCOMPARE( result, expected );

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

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

0 comments on commit bd3d75f

Please sign in to comment.