Skip to content

Commit 34d468e

Browse files
committedMay 9, 2016
Allow setting list of attributes to exclude from json exports
1 parent 9041c95 commit 34d468e

File tree

4 files changed

+149
-56
lines changed

4 files changed

+149
-56
lines changed
 

‎python/core/qgsjsonutils.sip

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,36 @@ class QgsJSONExporter
5555
* @param attributes list of attribute indexes, or an empty list to include all
5656
* attributes
5757
* @see attributes()
58+
* @see setExcludedAttributes()
59+
* @note Attributes excluded via setExcludedAttributes() take precedence over
60+
* attributes specified by this method.
5861
*/
5962
void setAttributes( const QgsAttributeList& attributes );
6063

6164
/** Returns the list of attributes which will be included in the JSON exports, or
6265
* an empty list if all attributes will be included.
6366
* @see setAttributes()
67+
* @see excludedAttributes()
68+
* @note Attributes excluded via excludedAttributes() take precedence over
69+
* attributes returned by this method.
6470
*/
6571
QgsAttributeList attributes() const;
6672

73+
/** Sets a list of attributes to specifically exclude from the JSON exports. Excluded attributes
74+
* take precedence over attributes included via setAttributes().
75+
* @param attributes list of attribute indexes to exclude
76+
* @see excludedAttributes()
77+
* @see setAttributes()
78+
*/
79+
void setExcludedAttributes( const QgsAttributeList& attributes );
80+
81+
/** Returns a list of attributes which will be specifically excluded from the JSON exports. Excluded attributes
82+
* take precedence over attributes included via attributes().
83+
* @see setExcludedAttributes()
84+
* @see attributes()
85+
*/
86+
QgsAttributeList excludedAttributes() const;
87+
6788
/** Returns a GeoJSON string representation of a feature.
6889
* @param feature feature to convert
6990
* @param extraProperties map of extra attributes to include in feature's properties

‎src/core/qgsjsonutils.cpp

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -29,56 +29,29 @@ QgsJSONExporter::QgsJSONExporter( int precision, bool includeGeometry, bool incl
2929
QString QgsJSONExporter::exportFeature( const QgsFeature& feature, const QVariantMap& extraProperties,
3030
const QVariant& id ) const
3131
{
32-
QString s = "{\n \"type\":\"Feature\",\n";
33-
34-
// ID
35-
s += QString( " \"id\":%1" ).arg( !id.isValid() ? QString::number( feature.id() ) : QgsJSONUtils::encodeValue( id ) );
36-
37-
if ( mIncludeAttributes || mIncludeGeometry || !extraProperties.isEmpty() )
38-
s += ",\n";
39-
else
40-
s += '\n';
41-
42-
const QgsGeometry* geom = feature.constGeometry();
43-
if ( geom && !geom->isEmpty() && mIncludeGeometry )
44-
{
45-
QgsRectangle box = geom->boundingBox();
46-
47-
if ( QgsWKBTypes::flatType( geom->geometry()->wkbType() ) != QgsWKBTypes::Point )
48-
{
49-
s += QString( " \"bbox\":[%1, %2, %3, %4],\n" ).arg( qgsDoubleToString( box.xMinimum(), mPrecision ),
50-
qgsDoubleToString( box.yMinimum(), mPrecision ),
51-
qgsDoubleToString( box.xMaximum(), mPrecision ),
52-
qgsDoubleToString( box.yMaximum(), mPrecision ) );
53-
}
54-
s += " \"geometry\":\n ";
55-
s += geom->exportToGeoJSON( mPrecision );
56-
if ( mIncludeAttributes || !extraProperties.isEmpty() )
57-
s += ",\n";
58-
else
59-
s += '\n';
60-
}
32+
//first step is to build up the properties list
33+
QString properties;
6134

35+
int attributeCounter = 0;
6236
if ( mIncludeAttributes || !extraProperties.isEmpty() )
6337
{
6438
//read all attribute values from the feature
65-
s += " \"properties\":{\n";
66-
int attributeCounter = 0;
39+
6740

6841
if ( mIncludeAttributes )
6942
{
7043
const QgsFields* fields = feature.fields();
7144

7245
for ( int i = 0; i < fields->count(); ++i )
7346
{
74-
if ( !mAttributeIndexes.isEmpty() && !mAttributeIndexes.contains( i ) )
47+
if (( !mAttributeIndexes.isEmpty() && !mAttributeIndexes.contains( i ) ) || mExcludedAttributeIndexes.contains( i ) )
7548
continue;
7649

7750
if ( attributeCounter > 0 )
78-
s += ",\n";
51+
properties += ",\n";
7952
QVariant val = feature.attributes().at( i );
8053

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

8356
++attributeCounter;
8457
}
@@ -90,18 +63,53 @@ QString QgsJSONExporter::exportFeature( const QgsFeature& feature, const QVarian
9063
for ( ; it != extraProperties.constEnd(); ++it )
9164
{
9265
if ( attributeCounter > 0 )
93-
s += ",\n";
66+
properties += ",\n";
9467

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

9770
++attributeCounter;
9871
}
9972
}
73+
}
74+
bool hasProperties = attributeCounter > 0;
10075

101-
s += "\n }\n";
76+
QString s = "{\n \"type\":\"Feature\",\n";
77+
78+
// ID
79+
s += QString( " \"id\":%1" ).arg( !id.isValid() ? QString::number( feature.id() ) : QgsJSONUtils::encodeValue( id ) );
80+
81+
if ( hasProperties || mIncludeGeometry )
82+
s += ",\n";
83+
else
84+
s += '\n';
85+
86+
const QgsGeometry* geom = feature.constGeometry();
87+
if ( geom && !geom->isEmpty() && mIncludeGeometry )
88+
{
89+
QgsRectangle box = geom->boundingBox();
90+
91+
if ( QgsWKBTypes::flatType( geom->geometry()->wkbType() ) != QgsWKBTypes::Point )
92+
{
93+
s += QString( " \"bbox\":[%1, %2, %3, %4],\n" ).arg( qgsDoubleToString( box.xMinimum(), mPrecision ),
94+
qgsDoubleToString( box.yMinimum(), mPrecision ),
95+
qgsDoubleToString( box.xMaximum(), mPrecision ),
96+
qgsDoubleToString( box.yMaximum(), mPrecision ) );
97+
}
98+
s += " \"geometry\":\n ";
99+
s += geom->exportToGeoJSON( mPrecision );
100+
if ( hasProperties )
101+
s += ",\n";
102+
else
103+
s += '\n';
104+
}
105+
106+
if ( hasProperties )
107+
{
108+
//read all attribute values from the feature
109+
s += " \"properties\":{\n" + properties + "\n }\n";
102110
}
103111

104-
s += "}";
112+
s += '}';
105113

106114
return s;
107115
}

‎src/core/qgsjsonutils.h

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,36 @@ class CORE_EXPORT QgsJSONExporter
7474
* @param attributes list of attribute indexes, or an empty list to include all
7575
* attributes
7676
* @see attributes()
77+
* @see setExcludedAttributes()
78+
* @note Attributes excluded via setExcludedAttributes() take precedence over
79+
* attributes specified by this method.
7780
*/
7881
void setAttributes( const QgsAttributeList& attributes ) { mAttributeIndexes = attributes; }
7982

8083
/** Returns the list of attributes which will be included in the JSON exports, or
8184
* an empty list if all attributes will be included.
8285
* @see setAttributes()
86+
* @see excludedAttributes()
87+
* @note Attributes excluded via excludedAttributes() take precedence over
88+
* attributes returned by this method.
8389
*/
8490
QgsAttributeList attributes() const { return mAttributeIndexes; }
8591

92+
/** Sets a list of attributes to specifically exclude from the JSON exports. Excluded attributes
93+
* take precedence over attributes included via setAttributes().
94+
* @param attributes list of attribute indexes to exclude
95+
* @see excludedAttributes()
96+
* @see setAttributes()
97+
*/
98+
void setExcludedAttributes( const QgsAttributeList& attributes ) { mExcludedAttributeIndexes = attributes; }
99+
100+
/** Returns a list of attributes which will be specifically excluded from the JSON exports. Excluded attributes
101+
* take precedence over attributes included via attributes().
102+
* @see setExcludedAttributes()
103+
* @see attributes()
104+
*/
105+
QgsAttributeList excludedAttributes() const { return mExcludedAttributeIndexes; }
106+
86107
/** Returns a GeoJSON string representation of a feature.
87108
* @param feature feature to convert
88109
* @param extraProperties map of extra attributes to include in feature's properties
@@ -100,8 +121,12 @@ class CORE_EXPORT QgsJSONExporter
100121
int mPrecision;
101122

102123
//! List of attribute indexes to include in export, or empty list to include all attributes
124+
//! @see mExcludedAttributeIndexes
103125
QgsAttributeList mAttributeIndexes;
104126

127+
//! List of attribute indexes to exclude from export
128+
QgsAttributeList mExcludedAttributeIndexes;
129+
105130
//! Whether to include geometry in JSON export
106131
bool mIncludeGeometry;
107132

@@ -139,24 +164,6 @@ class CORE_EXPORT QgsJSONUtils
139164
*/
140165
static QgsFields stringToFields( const QString& string, QTextCodec* encoding );
141166

142-
/** Returns a GeoJSON string representation of a feature.
143-
* @param feature feature to convert
144-
* @param precision maximum number of decimal places to use for geometry coordinates
145-
* @param attrIndexes list of attribute indexes to include in GeoJSON, or an empty list to include
146-
* all attributes
147-
* @param includeGeom set to false to avoid including the geometry representation in the JSON output
148-
* @param includeAttributes set to false to avoid including any attribute values in the JSON output
149-
* @param id optional ID to use as GeoJSON feature's ID instead of input feature's ID. If omitted, feature's
150-
* ID is used.
151-
* @returns GeoJSON string
152-
*/
153-
static QString featureToGeoJSON( const QgsFeature& feature,
154-
int precision = 17,
155-
const QgsAttributeList& attrIndexes = QgsAttributeList(),
156-
bool includeGeom = true,
157-
bool includeAttributes = true,
158-
const QVariant& id = QVariant() );
159-
160167
/** Encodes a value to a JSON string representation, adding appropriate quotations and escaping
161168
* where required.
162169
* @param value value to encode

‎tests/src/python/test_qgsjsonutils.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,63 @@ def testJSONExporter(self):
198198
self.assertEqual(exporter.exportFeature(feature), expected)
199199
exporter.setAttributes([])
200200

201+
# text excluding attributes
202+
203+
exporter.setExcludedAttributes([1])
204+
self.assertEqual(exporter.excludedAttributes(), [1])
205+
expected = """{
206+
"type":"Feature",
207+
"id":5,
208+
"geometry":
209+
{"type": "Point", "coordinates": [5, 6]},
210+
"properties":{
211+
"name":"Valsier Peninsula",
212+
"population":198
213+
}
214+
}"""
215+
self.assertEqual(exporter.exportFeature(feature), expected)
216+
217+
exporter.setExcludedAttributes([1, 2])
218+
self.assertEqual(exporter.excludedAttributes(), [1, 2])
219+
expected = """{
220+
"type":"Feature",
221+
"id":5,
222+
"geometry":
223+
{"type": "Point", "coordinates": [5, 6]},
224+
"properties":{
225+
"name":"Valsier Peninsula"
226+
}
227+
}"""
228+
self.assertEqual(exporter.exportFeature(feature), expected)
229+
230+
exporter.setExcludedAttributes([0, 1, 2])
231+
self.assertEqual(exporter.excludedAttributes(), [0, 1, 2])
232+
expected = """{
233+
"type":"Feature",
234+
"id":5,
235+
"geometry":
236+
{"type": "Point", "coordinates": [5, 6]}
237+
}"""
238+
self.assertEqual(exporter.exportFeature(feature), expected)
239+
240+
# test that excluded attributes take precedence over included
241+
242+
exporter.setAttributes([1, 2])
243+
exporter.setExcludedAttributes([0, 1])
244+
expected = """{
245+
"type":"Feature",
246+
"id":5,
247+
"geometry":
248+
{"type": "Point", "coordinates": [5, 6]},
249+
"properties":{
250+
"population":198
251+
}
252+
}"""
253+
self.assertEqual(exporter.exportFeature(feature), expected)
254+
255+
exporter.setAttributes([])
256+
exporter.setExcludedAttributes([])
257+
201258
# test excluding geometry
202259
exporter.setIncludeGeometry(False)
203260
self.assertEqual(exporter.includeGeometry(), False)

0 commit comments

Comments
 (0)
Please sign in to comment.