18#include <nlohmann/json.hpp>
45#include <QJsonDocument>
49#include "moc_qgsjsonutils.cpp"
51using namespace Qt::StringLiterals;
60 mTransform.setSourceCrs( mCrs );
65 mTransform.setDestinationCrs( mDestinationCrs );
74 mTransform.setSourceCrs( mCrs );
86 mTransform.setSourceCrs( mCrs );
100 catch ( json::type_error &ex )
105 catch ( json::other_error &ex )
118 const bool destinationCrsIsRfc7946Compliant = mDestinationCrs.authid() ==
"OGC:CRS84" || mDestinationCrs.authid() ==
"EPSG:4326" || mDestinationCrs.authid() ==
"CRS:84";
119 const bool sourceCrsIsRfc7946Compliant = ( mCrs.authid() ==
"OGC:CRS84" || mCrs.authid() ==
"CRS:84" || mCrs.authid() ==
"EPSG:4326" );
124 const bool includeGeometryInformation { !geom.
isNull() && mIncludeGeometry };
127 const bool mainGeometryIsRfc7946Compliant {
129 && destinationCrsIsRfc7946Compliant
134 {
"type",
"Feature" },
139 featureJson[
"conformsTo"] = {
"http://www.opengis.net/spec/json-fg-1/1.0/conf/core" };
140 if ( includeGeometryInformation )
144 featureJson[
"conformsTo"].push_back(
"http://www.opengis.net/spec/json-fg-1/1.0/conf/measures" );
145 featureJson[
"measures"] = { {
"enabled",
true } };
152 if ( !extraMembers.isEmpty() )
154 QVariantMap::const_iterator it = extraMembers.constBegin();
155 for ( ; it != extraMembers.constEnd(); ++it )
164 auto intId =
id.toLongLong( &ok );
167 featureJson[
"id"] = intId;
171 featureJson[
"id"] =
id.toString().toStdString();
176 featureJson[
"id"] =
nullptr;
180 featureJson[
"id"] = feature.
id();
186 if ( includeGeometryInformation )
190 if ( mTransformGeometries )
192 if ( mCrs.isValid() && !sourceCrsIsRfc7946Compliant && ( requiresCRS84geom || destinationCrsIsRfc7946Compliant ) )
196 transformedCRS84Geom.
transform( transformToCRS84 );
206 if ( destinationCrsIsRfc7946Compliant )
208 geom = transformedCRS84Geom;
210 else if ( mCrs.isValid() && mTransformGeometries )
224 std::function<void( json & )> invertCoords;
225 invertCoords = [&invertCoords]( json &geometry ) {
226 if ( geometry.contains(
"coordinates" ) )
228 invertCoords( geometry[
"coordinates"] );
230 else if ( geometry.contains(
"geometries" ) )
232 for ( json &geom : geometry[
"geometries"] )
234 invertCoords( geom );
237 else if ( geometry.is_array() && geometry.size() > 0 )
239 if ( geometry[0].is_array() )
241 for ( json &geom : geometry )
243 invertCoords( geom );
248 if ( geometry.size() >= 2 && geometry[0].is_number() && geometry[1].is_number() )
250 std::swap( geometry[0], geometry[1] );
256 auto addBbox = [&featureJson, &flatType,
this](
const QgsGeometry &geometry ) {
262 auto bbox = geometry.boundingBox();
264 = {
qgsRound( bbox.xMinimum(), this->mPrecision ),
qgsRound( bbox.yMinimum(), this->mPrecision ),
qgsRound( bbox.xMaximum(), this->mPrecision ),
qgsRound( bbox.yMaximum(), this->mPrecision ) };
267 switch ( mGeoJsonProfile )
272 addBbox( transformedCRS84Geom );
290 addBbox( transformedCRS84Geom );
291 if ( !mainGeometryIsRfc7946Compliant )
293 json place = geom.
asJsonObject( mPrecision, mGeoJsonProfile );
294 if ( mDestinationCrs.hasAxisInverted() )
296 invertCoords( place );
298 featureJson[
"place"] = place;
307 if ( !mainGeometryIsRfc7946Compliant )
309 json place = geom.
asJsonObject( mPrecision, mGeoJsonProfile );
310 if ( mDestinationCrs.hasAxisInverted() )
312 invertCoords( place );
314 featureJson[
"place"] = place;
318 featureJson[
"geometry"] = geom.
asJsonObject( mPrecision, mGeoJsonProfile );
326 featureJson[
"geometry"] =
nullptr;
331 if ( mIncludeAttributes || !extraProperties.isEmpty() )
334 if ( mIncludeAttributes )
338 QStringList formattersAllowList;
339 formattersAllowList << u
"KeyValue"_s << u
"List"_s << u
"ValueRelation"_s << u
"ValueMap"_s;
341 for (
int i = 0; i < fields.
count(); ++i )
343 if ( ( !mAttributeIndexes.isEmpty() && !mAttributeIndexes.contains( i ) ) || mExcludedAttributeIndexes.contains( i ) )
348 if ( mUseFieldFormatters && mLayer )
352 if ( formattersAllowList.contains( fieldFormatter->
id() ) )
356 QString name = fields.
at( i ).
name();
357 if ( mAttributeDisplayName )
359 name = mLayer->attributeDisplayName( i );
365 if ( !extraProperties.isEmpty() )
367 QVariantMap::const_iterator it = extraProperties.constBegin();
368 for ( ; it != extraProperties.constEnd(); ++it )
375 if ( mLayer && mIncludeRelatedAttributes )
378 for (
const auto &relation : std::as_const( relations ) )
383 json relatedFeatureAttributes;
387 QVector<QVariant> attributeWidgetCaches;
390 for (
const QgsField &field : fields )
394 attributeWidgetCaches.append( fieldFormatter->
createCache( childLayer, fieldIndex, setup.
config() ) );
403 properties[relation.name().toStdString()] = relatedFeatureAttributes;
407 featureJson[
"properties"] = properties;
419 json data { {
"type",
"FeatureCollection" }, {
"features", json::array() } };
420 const bool omitCollectionLevelInformation = mOmitCollectionLevelInformation;
421 mOmitCollectionLevelInformation =
true;
422 switch ( mGeoJsonProfile )
436 json conformsTo = json::array( { {
"http://www.opengis.net/spec/json-fg-1/1.0/conf/core" } } );
438 bool hasCircularArcs =
false;
439 bool hasMeasure =
false;
446 hasCircularArcs =
true;
454 if ( hasCircularArcs )
456 conformsTo.push_back( {
"http://www.opengis.net/spec/json-fg-1/1.0/conf/circular-arcs" } );
460 conformsTo.push_back( {
"http://www.opengis.net/spec/json-fg-1/1.0/conf/measures" } );
461 data[
"measures"] = { {
"enabled",
true } };
463 data[
"conformsTo"] = conformsTo;
467 mOmitCollectionLevelInformation = omitCollectionLevelInformation;
473 mDestinationCrs = destinationCrs;
474 mTransform.setDestinationCrs( mDestinationCrs );
479 return mGeoJsonProfile;
484 mGeoJsonProfile = profile;
494 encoding = QTextCodec::codecForName(
"UTF-8" );
502 encoding = QTextCodec::codecForName(
"UTF-8" );
512 switch ( value.userType() )
514 case QMetaType::Type::Int:
515 case QMetaType::Type::UInt:
516 case QMetaType::Type::LongLong:
517 case QMetaType::Type::ULongLong:
518 case QMetaType::Type::Double:
519 return value.toString();
521 case QMetaType::Type::Bool:
522 return value.toBool() ?
"true" :
"false";
524 case QMetaType::Type::QStringList:
525 case QMetaType::Type::QVariantList:
526 case QMetaType::Type::QVariantMap:
527 return QString::fromUtf8( QJsonDocument::fromVariant( value ).toJson( QJsonDocument::Compact ) );
530 case QMetaType::Type::QString:
532 = value.toString().replace(
'\\',
"\\\\"_L1 ).replace(
'"',
"\\\""_L1 ).replace(
'\r',
"\\r"_L1 ).replace(
'\b',
"\\b"_L1 ).replace(
'\t',
"\\t"_L1 ).replace(
'/',
"\\/"_L1 ).replace(
'\n',
"\\n"_L1 );
534 return v.prepend(
'"' ).append(
'"' );
542 for (
int i = 0; i < fields.
count(); ++i )
554 val = fieldFormatter->
representValue( layer, i, setup.
config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
559 return attrs.prepend(
'{' ).
append(
'}' );
564 QString errorMessage;
568 const auto jObj( json::parse( json.toStdString() ) );
569 if ( !jObj.is_array() )
571 throw json::parse_error::create( 0, 0, u
"JSON value must be an array"_s.toStdString(), &jObj );
573 for (
const auto &item : jObj )
577 if ( item.is_number_integer() )
581 else if ( item.is_number_unsigned() )
583 v = item.get<
unsigned>();
585 else if ( item.is_number_float() )
588 v = item.get<
double>();
590 else if ( item.is_string() )
592 v = QString::fromStdString( item.get<std::string>() );
594 else if ( item.is_boolean() )
596 v = item.get<
bool>();
598 else if ( item.is_null() )
605 if ( type != QMetaType::Type::UnknownType )
607 if ( !v.convert(
static_cast<int>( type ) ) )
609 QgsLogger::warning( u
"Cannot convert json array element to specified type, ignoring: %1"_s.arg( v.toString() ) );
613 result.push_back( v );
618 result.push_back( v );
622 catch ( json::parse_error &ex )
624 errorMessage = ex.what();
638 if ( !coords.is_array() || coords.size() < 2 || coords.size() > 4 )
640 QgsDebugError( u
"JSON Point geometry coordinates must be an array of two, three or four numbers"_s );
644 const double x = coords[0].get<
double >();
645 const double y = coords[1].get<
double >();
646 if ( coords.size() == 2 )
648 return std::make_unique< QgsPoint >( x, y );
650 else if ( coords.size() == 3 )
652 const double zOrM = coords[2].get<
double >();
654 return std::make_unique< QgsPoint >( x, y, std::numeric_limits<double>::quiet_NaN(), zOrM );
656 return std::make_unique< QgsPoint >( x, y, zOrM );
660 const double z = coords[2].get<
double >();
661 const double m = coords[3].get<
double >();
662 return std::make_unique< QgsPoint >( x, y, z, m );
668 if ( !coords.is_array() )
670 QgsDebugError( u
"JSON LineString geometry coordinates must be an array"_s );
674 const std::size_t coordsSize = coords.size();
676 if ( coordsSize == 0 )
679 return std::make_unique< QgsLineString >();
682 if ( coordsSize < 2 )
684 QgsDebugError( u
"JSON LineString geometry coordinates must contain at least two positions"_s );
692 x.resize( coordsSize );
693 y.resize( coordsSize );
694 z.resize( coordsSize );
695 m.resize( coordsSize );
697 double *xOut = x.data();
698 double *yOut = y.data();
699 double *zOut = z.data();
700 double *mOut = m.data();
702 for (
const auto &coord : coords )
704 if ( !coord.is_array() || coord.size() < 2 || coord.size() > 4 )
706 QgsDebugError( u
"JSON LineString geometry coordinates must be an array of two, three or four numbers"_s );
710 *xOut++ = coord[0].get<
double >();
711 *yOut++ = coord[1].get<
double >();
712 if ( coord.size() == 4 )
714 *zOut++ = coord[2].get<
double >();
715 *mOut++ = coord[3].get<
double >();
717 else if ( coord.size() == 3 )
721 *mOut++ = coord[2].get<
double >();
722 *zOut++ = std::numeric_limits< double >::quiet_NaN();
726 *zOut++ = coord[2].get<
double >();
727 *mOut++ = std::numeric_limits< double >::quiet_NaN();
733 *zOut++ = std::numeric_limits< double >::quiet_NaN();
737 return std::make_unique< QgsLineString >( x, y, hasZ ? z : QVector<double>(), hasM ? m : QVector<double>() );
742 if ( !coords.is_array() )
744 QgsDebugError( u
"JSON Polygon geometry coordinates must be an array"_s );
748 if ( coords.empty() )
751 return std::make_unique< QgsPolygon >();
754 const std::size_t coordsSize = coords.size();
761 auto polygon = std::make_unique< QgsPolygon >( exterior.release() );
762 for ( std::size_t i = 1; i < coordsSize; ++i )
769 polygon->addInteriorRing( ring.release() );
776 const auto hasM = hasMIn || ( geometry.contains(
"measures" ) && geometry[
"measures"].contains(
"enabled" ) && geometry[
"measures"][
"enabled"].get<bool>() );
778 if ( !geometry.is_object() )
784 if ( !geometry.contains(
"type" ) )
790 const QString type = QString::fromStdString( geometry[
"type"].get< std::string >() );
791 if ( type.compare(
"Point"_L1, Qt::CaseInsensitive ) == 0 )
793 if ( !geometry.contains(
"coordinates" ) )
795 QgsDebugError( u
"JSON Point geometry must contain 'coordinates'"_s );
799 const json &coords = geometry[
"coordinates"];
802 else if ( type.compare(
"MultiPoint"_L1, Qt::CaseInsensitive ) == 0 )
804 if ( !geometry.contains(
"coordinates" ) )
806 QgsDebugError( u
"JSON MultiPoint geometry must contain 'coordinates'"_s );
810 const json &coords = geometry[
"coordinates"];
812 if ( !coords.is_array() )
814 QgsDebugError( u
"JSON MultiPoint geometry coordinates must be an array"_s );
818 auto multiPoint = std::make_unique< QgsMultiPoint >();
819 multiPoint->reserve(
static_cast< int >( coords.size() ) );
820 for (
const auto &pointCoords : coords )
827 multiPoint->addGeometry( point.release() );
832 else if ( type.compare(
"LineString"_L1, Qt::CaseInsensitive ) == 0 )
834 if ( !geometry.contains(
"coordinates" ) )
836 QgsDebugError( u
"JSON LineString geometry must contain 'coordinates'"_s );
840 const json &coords = geometry[
"coordinates"];
843 else if ( type.compare(
"MultiLineString"_L1, Qt::CaseInsensitive ) == 0 )
845 if ( !geometry.contains(
"coordinates" ) )
847 QgsDebugError( u
"JSON MultiLineString geometry must contain 'coordinates'"_s );
851 const json &coords = geometry[
"coordinates"];
853 if ( !coords.is_array() )
855 QgsDebugError( u
"JSON MultiLineString geometry coordinates must be an array"_s );
859 auto multiLineString = std::make_unique< QgsMultiLineString >();
860 multiLineString->reserve(
static_cast< int >( coords.size() ) );
861 for (
const auto &lineCoords : coords )
868 multiLineString->addGeometry( line.release() );
871 return multiLineString;
873 else if ( type.compare(
"Polygon"_L1, Qt::CaseInsensitive ) == 0 )
875 if ( !geometry.contains(
"coordinates" ) )
877 QgsDebugError( u
"JSON Polygon geometry must contain 'coordinates'"_s );
881 const json &coords = geometry[
"coordinates"];
882 if ( !coords.is_array() )
884 QgsDebugError( u
"JSON Polygon geometry coordinates must be an array"_s );
890 else if ( type.compare(
"MultiPolygon"_L1, Qt::CaseInsensitive ) == 0 )
892 if ( !geometry.contains(
"coordinates" ) )
894 QgsDebugError( u
"JSON MultiPolygon geometry must contain 'coordinates'"_s );
898 const json &coords = geometry[
"coordinates"];
900 if ( !coords.is_array() )
902 QgsDebugError( u
"JSON MultiPolygon geometry coordinates must be an array"_s );
906 auto multiPolygon = std::make_unique< QgsMultiPolygon >();
907 multiPolygon->reserve(
static_cast< int >( coords.size() ) );
908 for (
const auto &polygonCoords : coords )
915 multiPolygon->addGeometry( polygon.release() );
922 else if ( type.compare(
"CircularString"_L1, Qt::CaseInsensitive ) == 0 )
924 if ( !geometry.contains(
"coordinates" ) )
926 QgsDebugError( u
"JSON CircularString geometry must contain 'coordinates'"_s );
930 const json &coords = geometry[
"coordinates"];
932 if ( coords.empty() )
934 return std::make_unique< QgsCircularString >();
937 if ( !coords.is_array() || coords.size() % 2 == 0 || coords.size() < 3 )
939 QgsDebugError( u
"JSON CircularString geometry coordinates must be an array of at least 3 coordinates and the total number must be an odd number"_s );
943 const bool hasZ = coords[0].is_array() && ( coords[0].size() > 3 || ( coords[0].size() == 3 && !hasM ) );
946 x.reserve( coords.size() );
948 y.reserve( coords.size() );
951 z.reserve( coords.size() );
954 m.reserve( coords.size() );
956 for (
const auto &pointCoords : coords )
961 QgsDebugError( u
"Invalid point in CircularString geometry"_s );
964 x.append( point->x() );
965 y.append( point->y() );
967 z.append( point->z() );
969 m.append( point->m() );
971 return std::make_unique< QgsCircularString >( x, y, z, m );
973 else if ( type.compare(
"CompoundCurve"_L1, Qt::CaseInsensitive ) == 0 )
975 if ( !geometry.contains(
"geometries" ) )
977 QgsDebugError( u
"JSON CompoundCurve geometry must contain 'geometries'"_s );
980 const json &geometries = geometry[
"geometries"];
981 if ( !geometries.is_array() )
983 QgsDebugError( u
"JSON CompoundCurve geometry geometries must be an array"_s );
986 auto compoundCurve = std::make_unique< QgsCompoundCurve >();
987 for (
const auto &geometry : geometries )
997 QgsDebugError( u
"JSON CompoundCurve geometries must be of type LineString or CircularString"_s );
1000 compoundCurve->addCurve(
static_cast< QgsCurve *
>(
object.release() ) );
1002 return compoundCurve;
1004 else if ( type.compare(
"CurvePolygon"_L1, Qt::CaseInsensitive ) == 0 )
1006 if ( !geometry.contains(
"geometries" ) )
1008 QgsDebugError( u
"JSON CurvePolygon geometry must contain 'geometries'"_s );
1011 const json &geometries = geometry[
"geometries"];
1012 if ( !geometries.is_array() )
1014 QgsDebugError( u
"JSON CurvePolygon geometries must be an array"_s );
1017 auto curvePolygon = std::make_unique< QgsCurvePolygon>();
1018 bool isExterior =
true;
1019 for (
const auto &geometry : geometries )
1029 QgsDebugError( u
"JSON CurvePolygon geometries must be of type LineString, CircularString or CompoundCurve"_s );
1034 curvePolygon->setExteriorRing(
static_cast< QgsCurve *
>(
object.release() ) );
1039 curvePolygon->addInteriorRing(
static_cast< QgsCurve *
>(
object.release() ) );
1042 return curvePolygon;
1044 else if ( type.compare(
"MultiCurve"_L1, Qt::CaseInsensitive ) == 0 )
1046 if ( !geometry.contains(
"geometries" ) )
1048 QgsDebugError( u
"JSON MultiCurve geometry must contain 'geometries'"_s );
1051 const json &geometries = geometry[
"geometries"];
1052 if ( !geometries.is_array() )
1054 QgsDebugError( u
"JSON MultiCurve geometries must be an array"_s );
1057 auto multiCurve = std::make_unique< QgsMultiCurve>();
1058 for (
const auto &geometry : geometries )
1068 QgsDebugError( u
"JSON MultiCurve geometries must be of type LineString, CircularString or CompoundCurve"_s );
1071 multiCurve->addGeometry(
static_cast< QgsCurve *
>(
object.release() ) );
1075 else if ( type.compare(
"MultiSurface"_L1, Qt::CaseInsensitive ) == 0 )
1077 if ( !geometry.contains(
"geometries" ) )
1079 QgsDebugError( u
"JSON MultiSurface geometry must contain 'geometries'"_s );
1082 const json &geometries = geometry[
"geometries"];
1083 if ( !geometries.is_array() )
1085 QgsDebugError( u
"JSON MultiSurface geometries must be an array"_s );
1088 auto multiSurface = std::make_unique< QgsMultiSurface >();
1089 for (
const auto &geometry : geometries )
1099 QgsDebugError( u
"JSON MultiSurface geometries must be of type Polygon or CurvePolygon"_s );
1102 multiSurface->addGeometry(
static_cast< QgsSurface *
>(
object.release() ) );
1104 return multiSurface;
1106 else if ( type.compare(
"GeometryCollection"_L1, Qt::CaseInsensitive ) == 0 )
1108 if ( !geometry.contains(
"geometries" ) )
1110 QgsDebugError( u
"JSON GeometryCollection geometry must contain 'geometries'"_s );
1114 const json &geometries = geometry[
"geometries"];
1116 if ( !geometries.is_array() )
1118 QgsDebugError( u
"JSON GeometryCollection geometries must be an array"_s );
1122 auto collection = std::make_unique< QgsGeometryCollection >();
1123 collection->reserve(
static_cast< int >( geometries.size() ) );
1124 for (
const auto &geometry : geometries )
1131 collection->addGeometry(
object.release() );
1137 QgsDebugError( u
"Unhandled GeoJSON geometry type: %1"_s.arg( type ) );
1143 if ( !geometry.is_object() )
1145 QgsDebugError( u
"JSON geometry value must be an object"_s );
1156 const auto jObj( json::parse( geometry.toStdString() ) );
1159 catch ( json::parse_error &ex )
1161 QgsDebugError( u
"Cannot parse json (%1): %2"_s.arg( geometry, ex.what() ) );
1178 if ( val.userType() == QMetaType::Type::QVariantMap )
1180 const QVariantMap &vMap = val.toMap();
1181 json jMap = json::object();
1182 for (
auto it = vMap.constBegin(); it != vMap.constEnd(); it++ )
1188 else if ( val.userType() == QMetaType::Type::QVariantList || val.userType() == QMetaType::Type::QStringList )
1190 const QVariantList &vList = val.toList();
1191 json jList = json::array();
1192 for (
const auto &v : vList )
1200 switch ( val.userType() )
1202 case QMetaType::Int:
1203 case QMetaType::UInt:
1204 case QMetaType::LongLong:
1205 case QMetaType::ULongLong:
1206 j = val.toLongLong();
1208 case QMetaType::Double:
1209 case QMetaType::Float:
1212 case QMetaType::Bool:
1215 case QMetaType::QByteArray:
1216 j = val.toByteArray().toBase64().toStdString();
1219 j = val.toString().toStdString();
1229 const QVariant res =
parseJson( jsonString, error );
1231 if ( !error.isEmpty() )
1233 QgsLogger::warning( u
"Cannot parse json (%1): %2"_s.arg( error, QString::fromStdString( jsonString ) ) );
1243 const json j = json::parse( jsonString );
1246 catch ( json::parse_error &ex )
1248 error = QString::fromStdString( ex.what() );
1250 catch ( json::type_error &ex )
1252 error = QString::fromStdString( ex.what() );
1260 bool isPrimitive =
true;
1262 std::function<QVariant( json )> _parser { [&]( json jObj ) -> QVariant {
1264 if ( jObj.is_array() )
1266 isPrimitive =
false;
1267 QVariantList results;
1268 results.reserve( jObj.size() );
1269 for (
const auto &item : jObj )
1271 results.push_back( _parser( item ) );
1275 else if ( jObj.is_object() )
1277 isPrimitive =
false;
1278 QVariantMap results;
1279 for (
const auto &item : jObj.items() )
1281 const auto key { QString::fromStdString( item.key() ) };
1282 const auto value { _parser( item.value() ) };
1283 results[key] = value;
1289 if ( jObj.is_number_unsigned() )
1293 const qulonglong num { jObj.get<qulonglong>() };
1294 if ( num <= std::numeric_limits<int>::max() )
1296 result =
static_cast<int>( num );
1298 else if ( num <= std::numeric_limits<qlonglong>::max() )
1300 result =
static_cast<qlonglong
>( num );
1307 else if ( jObj.is_number_integer() )
1309 const qlonglong num { jObj.get<qlonglong>() };
1310 if ( num <= std::numeric_limits<int>::max() && num >= std::numeric_limits<int>::lowest() )
1312 result =
static_cast<int>( num );
1319 else if ( jObj.is_boolean() )
1321 result = jObj.get<
bool>();
1323 else if ( jObj.is_number_float() )
1326 result = jObj.get<
double>();
1328 else if ( jObj.is_string() )
1330 if ( isPrimitive && jObj.get<std::string>().length() == 0 )
1332 result = QString::fromStdString( jObj.get<std::string>() ).append(
"\"" ).insert( 0,
"\"" );
1336 result = QString::fromStdString( jObj.get<std::string>() );
1339 else if ( jObj.is_null() )
1347 return _parser( value );
1352 return jsonString.isEmpty() ? QVariant() :
parseJson( jsonString.toStdString() );
1359 for (
int i = 0; i < fields.
count(); ++i )
1363 if ( layer && useFieldFormatters )
1368 val = fieldFormatter->
representValue( layer, i, setup.
config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
1380 if ( crs.
authid() ==
"EPSG:4326" || crs.
authid() ==
"CRS:84" || crs.
authid() ==
"OGC:CRS84" )
1391 value[
"crs"][
"type"] =
"name";
1392 value[
"crs"][
"properties"][
"name"] = crs.
toOgcUrn().toStdString();
1398 value[
"coordRefSys"] = crs.
toOgcUri().toStdString();
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
GeoJsonProfile
GeoJson export Profile according to OGC Features and Geometries JSON - Part 1: Core https://docs....
@ Legacy
Legacy GeoJson profile used in QGIS prior to 4.2, which included some non-standard extensions and dev...
@ Rfc7946
GeoJson profile compliant with RFC7946 standard "http://www.opengis.net/def/profile/OGC/0/rfc7946".
@ JsonFg
GeoJson profile from OGC Features and Geometries JSON Part 1: core "http://www.opengis....
@ JsonFgPlus
GeoJson profile from OGC Features and Geometries JSON Part 1: core "http://www.opengis....
WkbType
The WKB type describes the number of dimensions a geometry has.
@ CompoundCurve
CompoundCurve.
@ MultiPolygon
MultiPolygon.
@ MultiLineString
MultiLineString.
@ CircularString
CircularString.
@ GeometryCollection
GeometryCollection.
@ CurvePolygon
CurvePolygon.
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QString toOgcUri() const
Returns the crs as OGC URI (format: http://www.opengis.net/def/crs/OGC/1.3/CRS84) Returns an empty st...
QString toOgcUrn() const
Returns the crs as OGC URN (format: urn:ogc:def:crs:OGC:1.3:CRS84) Returns an empty string on failure...
Custom exception class for Coordinate Reference System related exceptions.
Abstract base class for curved geometry type.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Encapsulate a field in an attribute table or data source.
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Container of fields for a vector layer.
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
A geometry is the spatial representation of a feature.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
virtual json asJsonObject(int precision=17, Qgis::GeoJsonProfile profile=Qgis::GeoJsonProfile::Legacy) const
Exports the geometry to a json object with the give precision and following the specified GeoJSON pro...
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.).
Qgis::GeoJsonProfile geoJsonProfile() const
Returns the GeoJSON profile to use for export.
json exportFeaturesToJsonObject(const QgsFeatureList &features) const
Returns a GeoJSON object representation of a list of features (feature collection).
void setSourceCrs(const QgsCoordinateReferenceSystem &crs)
Sets the source CRS for feature geometries.
QString exportFeature(const QgsFeature &feature, const QVariantMap &extraProperties=QVariantMap(), const QVariant &id=QVariant(), int indent=-1, const QVariantMap &extraMembers=QVariantMap()) const
Returns a GeoJSON string representation of a feature.
void setDestinationCrs(const QgsCoordinateReferenceSystem &destinationCrs)
Set the destination CRS for feature geometry transformation to destinationCrs, this defaults to EPSG:...
QgsVectorLayer * vectorLayer() const
Returns the associated vector layer, if set.
int precision() const
Returns the maximum number of decimal places to use in geometry coordinates.
void setGeoJsonProfile(Qgis::GeoJsonProfile profile)
Sets the GeoJSON profile to use for export.
QString exportFeatures(const QgsFeatureList &features, int indent=-1) const
Returns a GeoJSON string representation of a list of features (feature collection).
void setVectorLayer(QgsVectorLayer *vectorLayer)
Sets the associated vector layer (required for related attribute export).
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source CRS for feature geometries.
QgsJsonExporter(QgsVectorLayer *vectorLayer=nullptr, int precision=6)
Constructor for QgsJsonExporter.
json exportFeatureToJsonObject(const QgsFeature &feature, const QVariantMap &extraProperties=QVariantMap(), const QVariant &id=QVariant(), const QVariantMap &extraMembers=QVariantMap()) const
Returns a GeoJson representation of a feature.
static void addCrsInfo(json &value, const QgsCoordinateReferenceSystem &crs, Qgis::GeoJsonProfile profile=Qgis::GeoJsonProfile::Legacy)
Add crs information entry in json object regarding old GeoJSON specification format if it differs fro...
static QgsGeometry geometryFromGeoJson(const json &geometry)
Parses a GeoJSON "geometry" value to a QgsGeometry object.
static QString exportAttributes(const QgsFeature &feature, QgsVectorLayer *layer=nullptr, const QVector< QVariant > &attributeWidgetCaches=QVector< QVariant >())
Exports all attributes from a QgsFeature as a JSON map type.
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields=QgsFields(), QTextCodec *encoding SIP_PYARGREMOVE6=nullptr)
Attempts to parse a GeoJSON string to a collection of features.
static Q_INVOKABLE QString encodeValue(const QVariant &value)
Encodes a value to a JSON string representation, adding appropriate quotations and escaping where req...
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned and ...
static QVariant geometryToGeoJsonVariant(const QgsGeometry &geometry)
Converts a geometry to a GeoJSON compatible variant.
static Q_INVOKABLE QVariantList parseArray(const QString &json, QMetaType::Type type=QMetaType::Type::UnknownType)
Parse a simple array (depth=1).
static json exportAttributesToJsonObject(const QgsFeature &feature, QgsVectorLayer *layer=nullptr, const QVector< QVariant > &attributeWidgetCaches=QVector< QVariant >(), bool useFieldFormatters=true)
Exports all attributes from a QgsFeature as a json object.
static QVariant jsonToVariant(const json &value)
Converts a JSON value to a QVariant, in case of parsing error an invalid QVariant is returned.
static QgsFields stringToFields(const QString &string, QTextCodec *encoding SIP_PYARGREMOVE6=nullptr)
Attempts to retrieve the fields from a GeoJSON string representing a collection of features.
static json jsonFromVariant(const QVariant &v)
Converts a QVariant v to a json object.
static void warning(const QString &msg)
Goes to qWarning.
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields, QTextCodec *encoding)
Attempts to parse a string representing a collection of features using OGR.
static QgsFields stringToFields(const QString &string, QTextCodec *encoding)
Attempts to retrieve the fields from a string representing a collection of features using OGR.
QgsRelationManager * relationManager
static QgsProject * instance()
Returns the QgsProject singleton instance.
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
static QMetaType::Type variantTypeToMetaType(QVariant::Type variantType)
Converts a QVariant::Type to a QMetaType::Type.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
Represents a vector layer which manages a vector based dataset.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places.
QList< QgsFeature > QgsFeatureList
std::unique_ptr< QgsAbstractGeometry > parseGeometryFromGeoJson(const json &geometry, bool hasMIn=false)
std::unique_ptr< QgsPolygon > parsePolygonFromGeoJson(const json &coords, bool hasM=false)
std::unique_ptr< QgsPoint > parsePointFromGeoJson(const json &coords, bool hasM=false)
std::unique_ptr< QgsLineString > parseLineStringFromGeoJson(const json &coords, bool hasM=false)
#define QgsDebugError(str)