Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Allow injecting extra properties into feature's GeoJSON export
Sponsored by Kanton of Zug, Switzerland
  • Loading branch information
nyalldawson committed May 9, 2016
1 parent c3f6c39 commit 9041c95
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 15 deletions.
2 changes: 2 additions & 0 deletions python/core/qgsjsonutils.sip
Expand Up @@ -66,11 +66,13 @@ class QgsJSONExporter

/** 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.
* @returns GeoJSON string
*/
QString exportFeature( const QgsFeature& feature,
const QVariantMap& extraProperties = QVariantMap(),
const QVariant& id = QVariant() ) const;

};
Expand Down
46 changes: 32 additions & 14 deletions src/core/qgsjsonutils.cpp
Expand Up @@ -26,14 +26,15 @@ QgsJSONExporter::QgsJSONExporter( int precision, bool includeGeometry, bool incl

}

QString QgsJSONExporter::exportFeature( const QgsFeature& feature, const QVariant& id ) const
QString QgsJSONExporter::exportFeature( const QgsFeature& feature, const QVariantMap& extraProperties,
const QVariant& id ) const
{
QString s = "{\n \"type\":\"Feature\",\n";

// ID
s += QString( " \"id\":%1" ).arg( !id.isValid() ? QString::number( feature.id() ) : QgsJSONUtils::encodeValue( id ) );

if ( mIncludeAttributes || mIncludeGeometry )
if ( mIncludeAttributes || mIncludeGeometry || !extraProperties.isEmpty() )
s += ",\n";
else
s += '\n';
Expand All @@ -52,32 +53,49 @@ QString QgsJSONExporter::exportFeature( const QgsFeature& feature, const QVarian
}
s += " \"geometry\":\n ";
s += geom->exportToGeoJSON( mPrecision );
if ( mIncludeAttributes )
if ( mIncludeAttributes || !extraProperties.isEmpty() )
s += ",\n";
else
s += '\n';
}

if ( mIncludeAttributes )
if ( mIncludeAttributes || !extraProperties.isEmpty() )
{
//read all attribute values from the feature
s += " \"properties\":{\n";

const QgsFields* fields = feature.fields();
int attributeCounter = 0;

for ( int i = 0; i < fields->count(); ++i )
if ( mIncludeAttributes )
{
if ( !mAttributeIndexes.isEmpty() && !mAttributeIndexes.contains( i ) )
continue;
const QgsFields* fields = feature.fields();

if ( attributeCounter > 0 )
s += ",\n";
QVariant val = feature.attributes().at( i );
for ( int i = 0; i < fields->count(); ++i )
{
if ( !mAttributeIndexes.isEmpty() && !mAttributeIndexes.contains( i ) )
continue;

s += QString( " \"%1\":%2" ).arg( fields->at( i ).name(), QgsJSONUtils::encodeValue( val ) );
if ( attributeCounter > 0 )
s += ",\n";
QVariant val = feature.attributes().at( i );

++attributeCounter;
s += QString( " \"%1\":%2" ).arg( fields->at( i ).name(), QgsJSONUtils::encodeValue( val ) );

++attributeCounter;
}
}

if ( !extraProperties.isEmpty() )
{
QVariantMap::const_iterator it = extraProperties.constBegin();
for ( ; it != extraProperties.constEnd(); ++it )
{
if ( attributeCounter > 0 )
s += ",\n";

s += QString( " \"%1\":%2" ).arg( it.key(), QgsJSONUtils::encodeValue( it.value() ) );

++attributeCounter;
}
}

s += "\n }\n";
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsjsonutils.h
Expand Up @@ -85,11 +85,13 @@ class CORE_EXPORT QgsJSONExporter

/** 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.
* @returns GeoJSON string
*/
QString exportFeature( const QgsFeature& feature,
const QVariantMap& extraProperties = QVariantMap(),
const QVariant& id = QVariant() ) const;

private:
Expand Down
2 changes: 1 addition & 1 deletion src/server/qgswfsserver.cpp
Expand Up @@ -1913,7 +1913,7 @@ QString QgsWFSServer::createFeatureGeoJSON( QgsFeature* feat, int prec, QgsCoord
exporter.setIncludeAttributes( !attrsToExport.isEmpty() );
exporter.setAttributes( attrsToExport );

return exporter.exportFeature( f, id );
return exporter.exportFeature( f, QVariantMap(), id );
}

QDomElement QgsWFSServer::createFeatureGML2( QgsFeature* feat, QDomDocument& doc, int prec, QgsCoordinateReferenceSystem& crs, const QgsAttributeList& attrIndexes, const QSet<QString>& excludedAttributes ) /*const*/
Expand Down
38 changes: 38 additions & 0 deletions tests/src/python/test_qgsjsonutils.py
Expand Up @@ -248,5 +248,43 @@ def testJSONExporter(self):
}"""
self.assertEqual(exporter.exportFeature(feature, id=29), expected)

# test injecting extra attributes
expected = """{
"type":"Feature",
"id":5,
"properties":{
"name":"Valsier Peninsula",
"cost":6.8,
"population":198,
"extra":"val1",
"extra2":2
}
}"""
self.assertEqual(exporter.exportFeature(feature, extraProperties={"extra": "val1", "extra2": 2}), expected)

exporter.setIncludeAttributes(False)
expected = """{
"type":"Feature",
"id":5,
"properties":{
"extra":"val1",
"extra2":{"nested_map":5,
"nested_map2":"val"},
"extra3":[1,2,3]
}
}"""
self.assertEqual(exporter.exportFeature(feature, extraProperties={"extra": "val1", "extra2": {"nested_map": 5, "nested_map2": "val"}, "extra3": [1, 2, 3]}), expected)
exporter.setIncludeGeometry(True)
expected = """{
"type":"Feature",
"id":5,
"geometry":
{"type": "Point", "coordinates": [5, 6]},
"properties":{
"extra":"val1",
"extra2":2
}
}"""

if __name__ == "__main__":
unittest.main()

0 comments on commit 9041c95

Please sign in to comment.