Indent on JSON export

This commit is contained in:
Alessandro Pasotti 2019-05-03 19:02:58 +02:00
parent 290909f9bb
commit bd3d75fce8
8 changed files with 638 additions and 476 deletions

View File

@ -219,7 +219,8 @@ take precedence over attributes included via attributes().
QString exportFeature( const QgsFeature &feature, QString exportFeature( const QgsFeature &feature,
const QVariantMap &extraProperties = QVariantMap(), const QVariantMap &extraProperties = QVariantMap(),
const QVariant &id = QVariant() ) const; const QVariant &id = QVariant(),
int indent = -1 ) const;
%Docstring %Docstring
Returns a GeoJSON string representation of a feature. Returns a GeoJSON string representation of a feature.
@ -227,6 +228,7 @@ Returns a GeoJSON string representation of a feature.
:param extraProperties: map of extra attributes to include in feature's properties :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 :param id: optional ID to use as GeoJSON feature's ID instead of input feature's ID. If omitted, feature's
ID is used. ID is used.
:param indent: number of indentation spaces for generated JSON (defaults to none)
:return: GeoJSON string :return: GeoJSON string
@ -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 %Docstring
Returns a GeoJSON string representation of a list of features (feature collection). Returns a GeoJSON string representation of a list of features (feature collection).
:param features: features to convert :param features: features to convert
:param indent: number of indentation spaces for generated JSON (defaults to none)
:return: GeoJSON string :return: GeoJSON string

View File

@ -69,9 +69,9 @@ QgsCoordinateReferenceSystem QgsJsonExporter::sourceCrs() const
} }
QString QgsJsonExporter::exportFeature( const QgsFeature &feature, const QVariantMap &extraProperties, 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 json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, const QVariantMap &extraProperties, const QVariant &id ) const
@ -82,7 +82,16 @@ json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, cons
}; };
if ( id.isValid() ) 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 else
{ {
@ -213,15 +222,19 @@ json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, cons
return featureJson; 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; const auto constFeatures = features;
for ( const QgsFeature &feature : constFeatures ) 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 ) );
} }
// //
@ -328,19 +341,41 @@ QVariantList QgsJsonUtils::parseArray( const QString &json, QVariant::Type type
json QgsJsonUtils::jsonFromVariant( const QVariant &val ) json QgsJsonUtils::jsonFromVariant( const QVariant &val )
{ {
if ( val.type() == QVariant::Type::Map )
switch ( val.userType() )
{ {
case QMetaType::Int: const auto vMap { val.toMap() };
case QMetaType::UInt: auto jMap { json::object() };
case QMetaType::LongLong: for ( auto it = vMap.constBegin(); it != vMap.constEnd(); it++ )
case QMetaType::ULongLong: {
return val.toLongLong(); jMap[ it.key().toStdString() ] = jsonFromVariant( it.value() );
case QMetaType::Double: }
case QMetaType::Float: return jMap;
return val.toDouble(); }
default: else if ( val.type() == QVariant::Type::List )
return val.toString().toStdString(); {
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();
}
} }
} }

View File

@ -198,13 +198,15 @@ class CORE_EXPORT QgsJsonExporter
* \param extraProperties map of extra attributes to include in feature's properties * \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 * \param id optional ID to use as GeoJSON feature's ID instead of input feature's ID. If omitted, feature's
* ID is used. * ID is used.
* \param indent number of indentation spaces for generated JSON (defaults to none)
* \returns GeoJSON string * \returns GeoJSON string
* \see exportFeatures() * \see exportFeatures()
* \see exportFeatureToJsonObject() * \see exportFeatureToJsonObject()
*/ */
QString exportFeature( const QgsFeature &feature, QString exportFeature( const QgsFeature &feature,
const QVariantMap &extraProperties = QVariantMap(), const QVariantMap &extraProperties = QVariantMap(),
const QVariant &id = QVariant() ) const; const QVariant &id = QVariant(),
int indent = -1 ) const;
/** /**
* Returns a QJsonObject representation of a feature. * Returns a QJsonObject representation of a feature.
@ -223,10 +225,11 @@ class CORE_EXPORT QgsJsonExporter
/** /**
* Returns a GeoJSON string representation of a list of features (feature collection). * Returns a GeoJSON string representation of a list of features (feature collection).
* \param features features to convert * \param features features to convert
* \param indent number of indentation spaces for generated JSON (defaults to none)
* \returns GeoJSON string * \returns GeoJSON string
* \see exportFeature() * \see exportFeature()
*/ */
QString exportFeatures( const QgsFeatureList &features ) const; QString exportFeatures( const QgsFeatureList &features, int indent = -1 ) const;
private: private:

View File

@ -157,24 +157,11 @@ void TestQgisAppClipboard::copyToText()
// GeoJSON // GeoJSON
settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::GeoJSON ); settings.setEnumValue( QStringLiteral( "/qgis/copyFeatureFormat" ), QgsClipboard::GeoJSON );
result = mQgisApp->clipboard()->generateClipboardText(); result = mQgisApp->clipboard()->generateClipboardText();
QString expected = "{ \"type\": \"FeatureCollection\",\n \"features\":[\n" QString expected = "{\"features\":[{\"geometry\":{\"coordinates\":[5.0,6.0],\"type\":\"Point\"},\"id\":5,"
"{\n \"type\":\"Feature\",\n" "\"properties\":{\"int_field\":9,\"string_field\":\"val\"},\"type\":\"Feature\"},"
" \"id\":5,\n" "{\"geometry\":{\"coordinates\":[7.0,8.0],\"type\":\"Point\"},\"id\":6,"
" \"geometry\":\n" "\"properties\":{\"int_field\":19,\"string_field\":\"val2\"},\"type\":\"Feature\"}],"
" {\"type\": \"Point\", \"coordinates\": [5, 6]},\n" "\"type\":\"FeatureCollection\"}";
" \"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]}";
QCOMPARE( result, expected ); QCOMPARE( result, expected );
// test CRS is transformed correctly for GeoJSON // test CRS is transformed correctly for GeoJSON
@ -191,7 +178,7 @@ void TestQgisAppClipboard::copyToText()
// just test coordinates as integers - that's enough to verify that reprojection has occurred // just test coordinates as integers - that's enough to verify that reprojection has occurred
// and helps avoid rounding issues // and helps avoid rounding issues
QRegExp regex( "\\[([-\\d.]+), ([-\\d.]+)\\]" ); QRegExp regex( "\\[([-\\d.]+),([-\\d.]+)\\]" );
( void )regex.indexIn( result ); ( void )regex.indexIn( result );
QStringList list = regex.capturedTexts(); QStringList list = regex.capturedTexts();
QCOMPARE( list.count(), 3 ); QCOMPARE( list.count(), 3 );

View File

@ -174,17 +174,22 @@ class TestQgsJsonUtils(unittest.TestCase):
exporter = QgsJsonExporter() exporter = QgsJsonExporter()
expected = """{ expected = """{
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 5.0,
{"type": "Point", "coordinates": [5, 6]}, 6.0
"properties":{ ],
"name":"Valsier Peninsula", "type": "Point"
"cost":6.8, },
"population":198 "id": 5,
} "properties": {
"cost": 6.8,
"name": "Valsier Peninsula",
"population": 198
},
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
# test with linestring for bbox inclusion # test with linestring for bbox inclusion
l = QgsLineString() l = QgsLineString()
@ -192,35 +197,58 @@ class TestQgsJsonUtils(unittest.TestCase):
feature.setGeometry(QgsGeometry(QgsLineString(l))) feature.setGeometry(QgsGeometry(QgsLineString(l)))
expected = """{ expected = """{
"type":"Feature", "bbox": [
"id":5, [
"bbox":[5, 6, 15, 16], 5.0,
"geometry": 6.0,
{"type": "LineString", "coordinates": [ [5, 6], [15, 16]]}, 15.0,
"properties":{ 16.0
"name":"Valsier Peninsula", ]
"cost":6.8, ],
"population":198 "geometry": {
} "coordinates": [
[
5.0,
6.0
],
[
15.0,
16.0
]
],
"type": "LineString"
},
"id": 5,
"properties": {
"cost": 6.8,
"name": "Valsier Peninsula",
"population": 198
},
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
# test that precision is respected # test that precision is respected
feature.setGeometry(QgsGeometry(QgsPoint(5.444444444, 6.333333333))) feature.setGeometry(QgsGeometry(QgsPoint(5.444444444, 6.333333333)))
exporter.setPrecision(3) exporter.setPrecision(3)
self.assertEqual(exporter.precision(), 3) self.assertEqual(exporter.precision(), 3)
expected = """{ expected = """{
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 5.444,
{"type": "Point", "coordinates": [5.444, 6.333]}, 6.333
"properties":{ ],
"name":"Valsier Peninsula", "type": "Point"
"cost":6.8, },
"population":198 "id": 5,
} "properties": {
"cost": 6.8,
"name": "Valsier Peninsula",
"population": 198
},
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) feature.setGeometry(QgsGeometry(QgsPoint(5, 6)))
exporter.setPrecision(17) exporter.setPrecision(17)
@ -228,29 +256,39 @@ class TestQgsJsonUtils(unittest.TestCase):
exporter.setAttributes([0, 2]) exporter.setAttributes([0, 2])
self.assertEqual(exporter.attributes(), [0, 2]) self.assertEqual(exporter.attributes(), [0, 2])
expected = """{ expected = """{
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 5.0,
{"type": "Point", "coordinates": [5, 6]}, 6.0
"properties":{ ],
"name":"Valsier Peninsula", "type": "Point"
"population":198 },
} "id": 5,
"properties": {
"name": "Valsier Peninsula",
"population": 198
},
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
exporter.setAttributes([1]) exporter.setAttributes([1])
self.assertEqual(exporter.attributes(), [1]) self.assertEqual(exporter.attributes(), [1])
expected = """{ expected = """{
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 5.0,
{"type": "Point", "coordinates": [5, 6]}, 6.0
"properties":{ ],
"cost":6.8 "type": "Point"
} },
"id": 5,
"properties": {
"cost": 6.8
},
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
exporter.setAttributes([]) exporter.setAttributes([])
# text excluding attributes # text excluding attributes
@ -258,55 +296,75 @@ class TestQgsJsonUtils(unittest.TestCase):
exporter.setExcludedAttributes([1]) exporter.setExcludedAttributes([1])
self.assertEqual(exporter.excludedAttributes(), [1]) self.assertEqual(exporter.excludedAttributes(), [1])
expected = """{ expected = """{
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 5.0,
{"type": "Point", "coordinates": [5, 6]}, 6.0
"properties":{ ],
"name":"Valsier Peninsula", "type": "Point"
"population":198 },
} "id": 5,
"properties": {
"name": "Valsier Peninsula",
"population": 198
},
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
exporter.setExcludedAttributes([1, 2]) exporter.setExcludedAttributes([1, 2])
self.assertEqual(exporter.excludedAttributes(), [1, 2]) self.assertEqual(exporter.excludedAttributes(), [1, 2])
expected = """{ expected = """{
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 5.0,
{"type": "Point", "coordinates": [5, 6]}, 6.0
"properties":{ ],
"name":"Valsier Peninsula" "type": "Point"
} },
"id": 5,
"properties": {
"name": "Valsier Peninsula"
},
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
exporter.setExcludedAttributes([0, 1, 2]) exporter.setExcludedAttributes([0, 1, 2])
self.assertEqual(exporter.excludedAttributes(), [0, 1, 2]) self.assertEqual(exporter.excludedAttributes(), [0, 1, 2])
expected = """{ expected = """{
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 5.0,
{"type": "Point", "coordinates": [5, 6]}, 6.0
"properties":null ],
"type": "Point"
},
"id": 5,
"properties": null,
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
# test that excluded attributes take precedence over included # test that excluded attributes take precedence over included
exporter.setAttributes([1, 2]) exporter.setAttributes([1, 2])
exporter.setExcludedAttributes([0, 1]) exporter.setExcludedAttributes([0, 1])
expected = """{ expected = """{
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 5.0,
{"type": "Point", "coordinates": [5, 6]}, 6.0
"properties":{ ],
"population":198 "type": "Point"
} },
"id": 5,
"properties": {
"population": 198
},
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
exporter.setAttributes([]) exporter.setAttributes([])
exporter.setExcludedAttributes([]) exporter.setExcludedAttributes([])
@ -317,16 +375,16 @@ class TestQgsJsonUtils(unittest.TestCase):
feature.setGeometry(QgsGeometry(QgsLineString(l))) feature.setGeometry(QgsGeometry(QgsLineString(l)))
expected = """{ expected = """{
"type":"Feature", "geometry": null,
"id":5, "id": 5,
"geometry":null, "properties": {
"properties":{ "cost": 6.8,
"name":"Valsier Peninsula", "name": "Valsier Peninsula",
"cost":6.8, "population": 198
"population":198 },
} "type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
exporter.setIncludeGeometry(True) exporter.setIncludeGeometry(True)
feature.setGeometry(QgsGeometry(QgsPoint(5, 6))) feature.setGeometry(QgsGeometry(QgsPoint(5, 6)))
@ -335,76 +393,90 @@ class TestQgsJsonUtils(unittest.TestCase):
exporter.setIncludeAttributes(False) exporter.setIncludeAttributes(False)
self.assertEqual(exporter.includeAttributes(), False) self.assertEqual(exporter.includeAttributes(), False)
expected = """{ expected = """{
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 5.0,
{"type": "Point", "coordinates": [5, 6]}, 6.0
"properties":null ],
"type": "Point"
},
"id": 5,
"properties": null,
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
exporter.setIncludeGeometry(False) exporter.setIncludeGeometry(False)
expected = """{ expected = """{
"type":"Feature", "geometry": null,
"id":5, "id": 5,
"geometry":null, "properties": null,
"properties":null "type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
exporter.setIncludeAttributes(True) exporter.setIncludeAttributes(True)
# test overriding ID # test overriding ID
expected = """{ expected = """{
"type":"Feature", "geometry": null,
"id":29, "id": 29,
"geometry":null, "properties": {
"properties":{ "cost": 6.8,
"name":"Valsier Peninsula", "name": "Valsier Peninsula",
"cost":6.8, "population": 198
"population":198 },
} "type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature, id=29), expected) self.assertEqual(exporter.exportFeature(feature, id=29, indent=2), expected)
expected = """{
"geometry": null,
"id": "mylayer.29",
"properties": {
"cost": 6.8,
"name": "Valsier Peninsula",
"population": 198
},
"type": "Feature"
}"""
self.assertEqual(exporter.exportFeature(feature, id="mylayer.29", indent=2), expected)
# test injecting extra attributes # test injecting extra attributes
expected = """{ expected = """{
"type":"Feature", "geometry": null,
"id":5, "id": 5,
"geometry":null, "properties": {
"properties":{ "cost": 6.8,
"name":"Valsier Peninsula", "extra": "val1",
"cost":6.8, "extra2": 2,
"population":198, "name": "Valsier Peninsula",
"extra":"val1", "population": 198
"extra2":2 },
} "type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature, extraProperties={"extra": "val1", "extra2": 2}), expected) self.assertEqual(exporter.exportFeature(feature, extraProperties={"extra": "val1", "extra2": 2}, indent=2), expected)
exporter.setIncludeAttributes(False) exporter.setIncludeAttributes(False)
expected = """{ expected = """{
"type":"Feature", "geometry": null,
"id":5, "id": 5,
"geometry":null, "properties": {
"properties":{ "extra": "val1",
"extra":"val1", "extra2": {
"extra2":{"nested_map":5, "nested_map": 5,
"nested_map2":"val"}, "nested_map2": "val"
"extra3":[1,2,3] },
} "extra3": [
1,
2,
3
]
},
"type": "Feature"
}""" }"""
expected2 = """{
"type":"Feature", exp_f = exporter.exportFeature(feature, extraProperties={"extra": "val1", "extra2": {"nested_map": 5, "nested_map2": "val"}, "extra3": [1, 2, 3]}, indent=2)
"id":5, self.assertEqual(exp_f, expected)
"geometry":null,
"properties":{
"extra":"val1",
"extra2":{"nested_map":5,"nested_map2":"val"},
"extra3":[1,2,3]
}
}"""
exp_f = exporter.exportFeature(feature, extraProperties={"extra": "val1", "extra2": {"nested_map": 5, "nested_map2": "val"}, "extra3": [1, 2, 3]})
self.assertTrue(exp_f == expected or exp_f == expected2)
exporter.setIncludeGeometry(True) exporter.setIncludeGeometry(True)
def testExportFeatureFieldFormatter(self): def testExportFeatureFieldFormatter(self):
@ -429,15 +501,15 @@ class TestQgsJsonUtils(unittest.TestCase):
exporter.setVectorLayer(source) exporter.setVectorLayer(source)
expected = """{ expected = """{
"type":"Feature", "geometry": null,
"id":0, "id": 0,
"geometry":null, "properties": {
"properties":{ "fldint": "one",
"fldtxt":"test1", "fldtxt": "test1"
"fldint":"one" },
} "type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(pf1), expected) self.assertEqual(exporter.exportFeature(pf1, indent=2), expected)
def testExportFeatureCrs(self): def testExportFeatureCrs(self):
""" Test CRS transform when exporting features """ """ Test CRS transform when exporting features """
@ -468,15 +540,20 @@ class TestQgsJsonUtils(unittest.TestCase):
# low precision, only need rough coordinate to check and don't want to deal with rounding errors # low precision, only need rough coordinate to check and don't want to deal with rounding errors
exporter.setPrecision(1) exporter.setPrecision(1)
expected = """{ expected = """{
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 145.0,
{"type": "Point", "coordinates": [145, -37.9]}, -37.9
"properties":{ ],
"fldtxt":"test point" "type": "Point"
} },
"id": 5,
"properties": {
"fldtxt": "test point"
},
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(feature), expected) self.assertEqual(exporter.exportFeature(feature, indent=2), expected)
def testExportFeatureRelations(self): def testExportFeatureRelations(self):
""" Test exporting a feature with relations """ """ Test exporting a feature with relations """
@ -528,90 +605,107 @@ class TestQgsJsonUtils(unittest.TestCase):
self.assertEqual(exporter.includeRelated(), True) self.assertEqual(exporter.includeRelated(), True)
expected = """{ expected = """{
"type":"Feature", "geometry": null,
"id":0, "id": 0,
"geometry":null, "properties": {
"properties":{ "fldint": 67,
"fldtxt":"test1", "fldtxt": "test1",
"fldint":67, "foreignkey": 123,
"foreignkey":123, "relation one": [
"relation one":[{"x":"foo", {
"y":123, "x": "foo",
"z":321}, "y": 123,
{"x":"bar", "z": 321
"y":123, },
"z":654}] {
} "x": "bar",
"y": 123,
"z": 654
}
]
},
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(pf1), expected) self.assertEqual(exporter.exportFeature(pf1, indent=2), expected)
expected = """{ expected = """{
"type":"Feature", "geometry": null,
"id":0, "id": 0,
"geometry":null, "properties": {
"properties":{ "fldint": 68,
"fldtxt":"test2", "fldtxt": "test2",
"fldint":68, "foreignkey": 124,
"foreignkey":124, "relation one": [
"relation one":[{"x":"foobar", {
"y":124, "x": "foobar",
"z":554}] "y": 124,
} "z": 554
}
]
},
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(pf2), expected)
self.assertEqual(exporter.exportFeature(pf2, indent=2), expected)
# with field formatter # with field formatter
setup = QgsEditorWidgetSetup('ValueMap', {"map": {"apples": 123, "bananas": 124}}) setup = QgsEditorWidgetSetup('ValueMap', {"map": {"apples": 123, "bananas": 124}})
child.setEditorWidgetSetup(1, setup) child.setEditorWidgetSetup(1, setup)
expected = """{ expected = """{
"type":"Feature", "geometry": null,
"id":0, "id": 0,
"geometry":null, "properties": {
"properties":{ "fldint": 67,
"fldtxt":"test1", "fldtxt": "test1",
"fldint":67, "foreignkey": 123,
"foreignkey":123, "relation one": [
"relation one":[{"x":"foo", {
"y":"apples", "x": "foo",
"z":321}, "y": "apples",
{"x":"bar", "z": 321
"y":"apples", },
"z":654}] {
} "x": "bar",
"y": "apples",
"z": 654
}
]
},
"type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(pf1), expected) self.assertEqual(exporter.exportFeature(pf1, indent=2), expected)
# test excluding related attributes # test excluding related attributes
exporter.setIncludeRelated(False) exporter.setIncludeRelated(False)
self.assertEqual(exporter.includeRelated(), False) self.assertEqual(exporter.includeRelated(), False)
expected = """{ expected = """{
"type":"Feature", "geometry": null,
"id":0, "id": 0,
"geometry":null, "properties": {
"properties":{ "fldint": 68,
"fldtxt":"test2", "fldtxt": "test2",
"fldint":68, "foreignkey": 124
"foreignkey":124 },
} "type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(pf2), expected) self.assertEqual(exporter.exportFeature(pf2, indent=2), expected)
# test without vector layer set # test without vector layer set
exporter.setIncludeRelated(True) exporter.setIncludeRelated(True)
exporter.setVectorLayer(None) exporter.setVectorLayer(None)
expected = """{ expected = """{
"type":"Feature", "geometry": null,
"id":0, "id": 0,
"geometry":null, "properties": {
"properties":{ "fldint": 68,
"fldtxt":"test2", "fldtxt": "test2",
"fldint":68, "foreignkey": 124
"foreignkey":124 },
} "type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(pf2), expected) self.assertEqual(exporter.exportFeature(pf2, indent=2), expected)
def testExportFeatures(self): def testExportFeatures(self):
""" Test exporting feature collections """ """ Test exporting feature collections """
@ -628,53 +722,72 @@ class TestQgsJsonUtils(unittest.TestCase):
exporter = QgsJsonExporter() exporter = QgsJsonExporter()
# single feature # single feature
expected = """{ "type": "FeatureCollection", expected = """{
"features":[ "features": [
{ {
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 5.0,
{"type": "Point", "coordinates": [5, 6]}, 6.0
"properties":{ ],
"name":"Valsier Peninsula", "type": "Point"
"cost":6.8, },
"population":198 "id": 5,
} "properties": {
} "cost": 6.8,
]}""" "name": "Valsier Peninsula",
self.assertEqual(exporter.exportFeatures([feature]), expected) "population": 198
},
"type": "Feature"
}
],
"type": "FeatureCollection"
}"""
self.assertEqual(exporter.exportFeatures([feature], 2), expected)
# multiple features # multiple features
feature2 = QgsFeature(fields, 6) feature2 = QgsFeature(fields, 6)
feature2.setGeometry(QgsGeometry(QgsPoint(7, 8))) feature2.setGeometry(QgsGeometry(QgsPoint(7, 8)))
feature2.setAttributes(['Henry Gale Island', 9.7, 38]) feature2.setAttributes(['Henry Gale Island', 9.7, 38])
expected = """{ "type": "FeatureCollection", expected = """{
"features":[ "features": [
{ {
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 5.0,
{"type": "Point", "coordinates": [5, 6]}, 6.0
"properties":{ ],
"name":"Valsier Peninsula", "type": "Point"
"cost":6.8, },
"population":198 "id": 5,
} "properties": {
}, "cost": 6.8,
{ "name": "Valsier Peninsula",
"type":"Feature", "population": 198
"id":6, },
"geometry": "type": "Feature"
{"type": "Point", "coordinates": [7, 8]}, },
"properties":{ {
"name":"Henry Gale Island", "geometry": {
"cost":9.7, "coordinates": [
"population":38 7.0,
} 8.0
} ],
]}""" "type": "Point"
self.assertEqual(exporter.exportFeatures([feature, feature2]), expected) },
"id": 6,
"properties": {
"cost": 9.7,
"name": "Henry Gale Island",
"population": 38
},
"type": "Feature"
}
],
"type": "FeatureCollection"
}"""
self.assertEqual(exporter.exportFeatures([feature, feature2], 2), expected)
def testExportFeaturesWithLocale_regression20053(self): def testExportFeaturesWithLocale_regression20053(self):
""" Test exporting feature export with range widgets and locale different than C """ Test exporting feature export with range widgets and locale different than C
@ -693,22 +806,29 @@ class TestQgsJsonUtils(unittest.TestCase):
exporter = QgsJsonExporter() exporter = QgsJsonExporter()
# single feature # single feature
expected = """{ "type": "FeatureCollection", expected = """{
"features":[ "features": [
{ {
"type":"Feature", "geometry": {
"id":5, "coordinates": [
"geometry": 5.0,
{"type": "Point", "coordinates": [5, 6]}, 6.0
"properties":{ ],
"name":"Valsier Peninsula", "type": "Point"
"cost":6.8, },
"population":198000, "id": 5,
"date":"2018-09-10" "properties": {
} "cost": 6.8,
} "date": "2018-09-10",
]}""" "name": "Valsier Peninsula",
self.assertEqual(exporter.exportFeatures([feature]), expected) "population": 198000
},
"type": "Feature"
}
],
"type": "FeatureCollection"
}"""
self.assertEqual(exporter.exportFeatures([feature], 2), expected)
setup = QgsEditorWidgetSetup('Range', { setup = QgsEditorWidgetSetup('Range', {
'AllowNull': True, 'AllowNull': True,
@ -724,7 +844,7 @@ class TestQgsJsonUtils(unittest.TestCase):
QLocale.setDefault(QLocale('it')) QLocale.setDefault(QLocale('it'))
exporter.setVectorLayer(source) exporter.setVectorLayer(source)
self.assertEqual(exporter.exportFeatures([feature]), expected) self.assertEqual(exporter.exportFeatures([feature], 2), expected)
def testExportFieldAlias(self): def testExportFieldAlias(self):
""" Test exporting a feature with fields' alias """ """ Test exporting a feature with fields' alias """
@ -749,15 +869,15 @@ class TestQgsJsonUtils(unittest.TestCase):
exporter.setVectorLayer(source) exporter.setVectorLayer(source)
expected = """{ expected = """{
"type":"Feature", "geometry": null,
"id":0, "id": 0,
"geometry":null, "properties": {
"properties":{ "alias_fldint": 1,
"alias_fldtxt":"test1", "alias_fldtxt": "test1"
"alias_fldint":1 },
} "type": "Feature"
}""" }"""
self.assertEqual(exporter.exportFeature(pf1), expected) self.assertEqual(exporter.exportFeature(pf1, indent=2), expected)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,46 +1,50 @@
Content-Length: 992 *****
Content-Type: application/json; charset=utf-8 Content-Type: application/json; charset=utf-8
{"type": "FeatureCollection",
"features":[
{ {
"type":"Feature", "features": [
"id":"as_areas.18", {
"geometry":null, "geometry": null,
"properties":{ "id": "as_areas.18",
"fid":18, "properties": {
"gid":34, "bearbeiter": "scholle-b",
"datum":"2013-06-11", "bemerkung": "",
"bearbeiter":"scholle-b", "beschriftung": "",
"veranstaltung":"", "datum": "2013-06-11",
"beschriftung":"", "farbe": "255 0 0",
"name":"", "fid": 18,
"flaechentyp":"Schraffur", "flaeche": 12879.0,
"farbe":"255 0 0", "flaechentyp": "Schraffur",
"schraff_width":"2", "gid": 34,
"schraff_width_prt":"6.00", "last_change": "2013-06-11 10:03:45.52301+02",
"schraff_size":"10", "name": "",
"schraff_size_prt":"30.00", "schraff_size": "10",
"schraff_winkel":"45", "schraff_size_prt": "30.00",
"umrissfarbe":"0 0 0", "schraff_width": "2",
"umrisstyp":"durchgezogen", "schraff_width_prt": "6.00",
"umrissstaerke":"1", "schraff_winkel": "45",
"umrissstaerke_prt":"3.00", "umfang": 758.4703,
"umfang":758.4703, "umrissfarbe": "0 0 0",
"flaeche":12879, "umrissstaerke": "1",
"bemerkung":"", "umrissstaerke_prt": "3.00",
"last_change":"2013-06-11 10:03:45.52301+02" "umrisstyp": "durchgezogen",
} "veranstaltung": ""
},{ },
"type":"Feature", "type": "Feature"
"id":"cdb_lines.13", },
"geometry":null, {
"properties":{ "geometry": null,
"fid":13, "id": "cdb_lines.13",
"id":12, "properties": {
"typ":"Ortsteil", "fid": 13,
"name":"Fallersleben", "id": 12,
"ortsrat":"Fallersleben\/Sülfeld", "id_long": "",
"id_long":null "name": "Fallersleben",
} "ortsrat": "Fallersleben/Sülfeld",
}]} "typ": "Ortsteil"
},
"type": "Feature"
}
],
"type": "FeatureCollection"
}

View File

@ -1,82 +1,89 @@
Content-Length: 1124 *****
Content-Type: application/json; charset=utf-8 Content-Type: application/json; charset=utf-8
{"type": "FeatureCollection",
"features":[
{ {
"type":"Feature", "features": [
"id":"cdb_lines.13", {
"geometry":null, "geometry": null,
"properties":{ "id": "cdb_lines.13",
"fid":13, "properties": {
"id":12, "fid": 13,
"typ":"Ortsteil", "id": 12,
"name":"Fallersleben", "id_long": "",
"ortsrat":"Fallersleben\/Sülfeld", "name": "Fallersleben",
"id_long":null "ortsrat": "Fallersleben/Sülfeld",
} "typ": "Ortsteil"
},{ },
"type":"Feature", "type": "Feature"
"id":"as_areas.18", },
"geometry":null, {
"properties":{ "geometry": null,
"fid":18, "id": "as_areas.18",
"gid":34, "properties": {
"datum":"2013-06-11", "bearbeiter": "scholle-b",
"bearbeiter":"scholle-b", "bemerkung": "",
"veranstaltung":"", "beschriftung": "",
"beschriftung":"", "datum": "2013-06-11",
"name":"", "farbe": "255 0 0",
"flaechentyp":"Schraffur", "fid": 18,
"farbe":"255 0 0", "flaeche": 12879.0,
"schraff_width":"2", "flaechentyp": "Schraffur",
"schraff_width_prt":"6.00", "gid": 34,
"schraff_size":"10", "last_change": "2013-06-11 10:03:45.52301+02",
"schraff_size_prt":"30.00", "name": "",
"schraff_winkel":"45", "schraff_size": "10",
"umrissfarbe":"0 0 0", "schraff_size_prt": "30.00",
"umrisstyp":"durchgezogen", "schraff_width": "2",
"umrissstaerke":"1", "schraff_width_prt": "6.00",
"umrissstaerke_prt":"3.00", "schraff_winkel": "45",
"umfang":758.4703, "umfang": 758.4703,
"flaeche":12879, "umrissfarbe": "0 0 0",
"bemerkung":"", "umrissstaerke": "1",
"last_change":"2013-06-11 10:03:45.52301+02" "umrissstaerke_prt": "3.00",
} "umrisstyp": "durchgezogen",
},{ "veranstaltung": ""
"type":"Feature", },
"id":"as_areas_query_copy.18", "type": "Feature"
"geometry":null, },
"properties":{ {
"fid":18, "geometry": null,
"gid":34, "id": "as_areas_query_copy.18",
"datum":"2013-06-11", "properties": {
"bearbeiter":"scholle-b", "bearbeiter": "scholle-b",
"veranstaltung":"", "bemerkung": "",
"beschriftung":"", "beschriftung": "",
"name":"", "datum": "2013-06-11",
"flaechentyp":"Schraffur", "farbe": "255 0 0",
"farbe":"255 0 0", "fid": 18,
"schraff_width":"2", "flaeche": 12879.0,
"schraff_width_prt":"6.00", "flaechentyp": "Schraffur",
"schraff_size":"10", "gid": 34,
"schraff_size_prt":"30.00", "last_change": "2013-06-11 10:03:45.52301+02",
"schraff_winkel":"45", "name": "",
"umrissfarbe":"0 0 0", "schraff_size": "10",
"umrisstyp":"durchgezogen", "schraff_size_prt": "30.00",
"umrissstaerke":"1", "schraff_width": "2",
"umrissstaerke_prt":"3.00", "schraff_width_prt": "6.00",
"umfang":758.4703, "schraff_winkel": "45",
"flaeche":12879, "umfang": 758.4703,
"bemerkung":"", "umrissfarbe": "0 0 0",
"last_change":"2013-06-11 10:03:45.52301+02" "umrissstaerke": "1",
} "umrissstaerke_prt": "3.00",
},{"type":"Feature", "umrisstyp": "durchgezogen",
"id":"osm", "veranstaltung": ""
"properties":{ },
"Band 1": "255", "type": "Feature"
"Band 2": "255", },
"Band 3": "255", {
"Band 4": "255" "id": "osm",
} "properties": {
}]} "Band 1": "255",
"Band 2": "255",
"Band 3": "255",
"Band 4": "255"
},
"type": "Feature"
}
],
"type": "FeatureCollection"
}

View File

@ -1,34 +1,37 @@
***** *****
Content-Type: application/json; charset=utf-8 Content-Type: application/json; charset=utf-8
{"type": "FeatureCollection",
"features":[
{ {
"type":"Feature", "features": [
"id":"as_areas_query_copy.18", {
"geometry":null, "geometry": null,
"properties":{ "id": "as_areas_query_copy.18",
"fid":18, "properties": {
"gid":34, "bearbeiter": "scholle-b",
"datum":"2013-06-11", "bemerkung": "",
"bearbeiter":"scholle-b", "beschriftung": "",
"veranstaltung":"", "datum": "2013-06-11",
"beschriftung":"", "farbe": "255 0 0",
"name":"", "fid": 18,
"flaechentyp":"Schraffur", "flaeche": 12879.0,
"farbe":"255 0 0", "flaechentyp": "Schraffur",
"schraff_width":"2", "gid": 34,
"schraff_width_prt":"6.00", "last_change": "2013-06-11 10:03:45.52301+02",
"schraff_size":"10", "name": "",
"schraff_size_prt":"30.00", "schraff_size": "10",
"schraff_winkel":"45", "schraff_size_prt": "30.00",
"umrissfarbe":"0 0 0", "schraff_width": "2",
"umrisstyp":"durchgezogen", "schraff_width_prt": "6.00",
"umrissstaerke":"1", "schraff_winkel": "45",
"umrissstaerke_prt":"3.00", "umfang": 758.4703,
"umfang":758.4703, "umrissfarbe": "0 0 0",
"flaeche":12879, "umrissstaerke": "1",
"bemerkung":"", "umrissstaerke_prt": "3.00",
"last_change":"2013-06-11 10:03:45.52301+02" "umrisstyp": "durchgezogen",
} "veranstaltung": ""
}]} },
"type": "Feature"
}
],
"type": "FeatureCollection"
}