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" );
122 || ( mTransformGeometries && destinationCrsIsRfc7946Compliant );
125 const bool geomRequiresTransformToDestinationCrs = mCrs != mDestinationCrs;
129 const bool includeGeometryInformation { !geom.
isNull() && mIncludeGeometry };
132 const bool mainGeometryIsRfc7946Compliant {
134 && destinationCrsIsRfc7946Compliant
139 {
"type",
"Feature" },
144 featureJson[
"conformsTo"] = {
"http://www.opengis.net/spec/json-fg-1/1.0/conf/core" };
145 if ( includeGeometryInformation )
149 featureJson[
"conformsTo"].push_back(
"http://www.opengis.net/spec/json-fg-1/1.0/conf/measures" );
150 featureJson[
"measures"] = { {
"enabled",
true } };
157 if ( !extraMembers.isEmpty() )
159 QVariantMap::const_iterator it = extraMembers.constBegin();
160 for ( ; it != extraMembers.constEnd(); ++it )
169 auto intId =
id.toLongLong( &ok );
172 featureJson[
"id"] = intId;
176 featureJson[
"id"] =
id.toString().toStdString();
181 featureJson[
"id"] =
nullptr;
185 featureJson[
"id"] = feature.
id();
191 if ( includeGeometryInformation )
196 if ( requiresCRS84geom )
198 if ( sourceCrsIsRfc7946Compliant )
200 transformedCRS84Geom = geom;
206 transformedCRS84Geom.
transform( transformToCRS84 );
218 if ( destinationCrsIsRfc7946Compliant )
220 geom = transformedCRS84Geom;
222 else if ( mCrs.isValid() )
236 std::function<void( json & )> invertCoords;
237 invertCoords = [&invertCoords]( json &geometry ) {
238 if ( geometry.contains(
"coordinates" ) )
240 invertCoords( geometry[
"coordinates"] );
242 else if ( geometry.contains(
"geometries" ) )
244 for ( json &geom : geometry[
"geometries"] )
246 invertCoords( geom );
249 else if ( geometry.is_array() && geometry.size() > 0 )
251 if ( geometry[0].is_array() )
253 for ( json &geom : geometry )
255 invertCoords( geom );
260 if ( geometry.size() >= 2 && geometry[0].is_number() && geometry[1].is_number() )
262 std::swap( geometry[0], geometry[1] );
268 auto addBbox = [&featureJson, &flatType,
this](
const QgsGeometry &geometry ) {
274 auto bbox = geometry.boundingBox();
276 = {
qgsRound( bbox.xMinimum(), this->mPrecision ),
qgsRound( bbox.yMinimum(), this->mPrecision ),
qgsRound( bbox.xMaximum(), this->mPrecision ),
qgsRound( bbox.yMaximum(), this->mPrecision ) };
279 switch ( mGeoJsonProfile )
284 addBbox( transformedCRS84Geom );
302 addBbox( transformedCRS84Geom );
303 if ( !mainGeometryIsRfc7946Compliant )
305 json place = geom.
asJsonObject( mPrecision, mGeoJsonProfile );
306 if ( mDestinationCrs.hasAxisInverted() )
308 invertCoords( place );
310 featureJson[
"place"] = place;
319 if ( !mainGeometryIsRfc7946Compliant )
321 json place = geom.
asJsonObject( mPrecision, mGeoJsonProfile );
322 if ( mDestinationCrs.hasAxisInverted() )
324 invertCoords( place );
326 featureJson[
"place"] = place;
330 featureJson[
"geometry"] = geom.
asJsonObject( mPrecision, mGeoJsonProfile );
338 featureJson[
"geometry"] =
nullptr;
343 if ( mIncludeAttributes || !extraProperties.isEmpty() )
346 if ( mIncludeAttributes )
350 QStringList formattersAllowList;
351 formattersAllowList << u
"KeyValue"_s << u
"List"_s << u
"ValueRelation"_s << u
"ValueMap"_s;
353 for (
int i = 0; i < fields.
count(); ++i )
355 if ( ( !mAttributeIndexes.isEmpty() && !mAttributeIndexes.contains( i ) ) || mExcludedAttributeIndexes.contains( i ) )
360 if ( mUseFieldFormatters && mLayer )
364 if ( formattersAllowList.contains( fieldFormatter->
id() ) )
368 QString name = fields.
at( i ).
name();
369 if ( mAttributeDisplayName )
371 name = mLayer->attributeDisplayName( i );
377 if ( !extraProperties.isEmpty() )
379 QVariantMap::const_iterator it = extraProperties.constBegin();
380 for ( ; it != extraProperties.constEnd(); ++it )
387 if ( mLayer && mIncludeRelatedAttributes )
390 for (
const auto &relation : std::as_const( relations ) )
395 json relatedFeatureAttributes;
399 QVector<QVariant> attributeWidgetCaches;
402 for (
const QgsField &field : fields )
406 attributeWidgetCaches.append( fieldFormatter->
createCache( childLayer, fieldIndex, setup.
config() ) );
415 properties[relation.name().toStdString()] = relatedFeatureAttributes;
419 featureJson[
"properties"] = properties;
431 json data { {
"type",
"FeatureCollection" }, {
"features", json::array() } };
432 const bool omitCollectionLevelInformation = mOmitCollectionLevelInformation;
433 mOmitCollectionLevelInformation =
true;
434 switch ( mGeoJsonProfile )
448 json conformsTo = json::array( { {
"http://www.opengis.net/spec/json-fg-1/1.0/conf/core" } } );
450 bool hasCircularArcs =
false;
451 bool hasMeasure =
false;
458 hasCircularArcs =
true;
466 if ( hasCircularArcs )
468 conformsTo.push_back( {
"http://www.opengis.net/spec/json-fg-1/1.0/conf/circular-arcs" } );
472 conformsTo.push_back( {
"http://www.opengis.net/spec/json-fg-1/1.0/conf/measures" } );
473 data[
"measures"] = { {
"enabled",
true } };
475 data[
"conformsTo"] = conformsTo;
479 mOmitCollectionLevelInformation = omitCollectionLevelInformation;
485 mDestinationCrs = destinationCrs;
486 mTransform.setDestinationCrs( mDestinationCrs );
491 return mGeoJsonProfile;
496 mGeoJsonProfile = profile;
506 encoding = QTextCodec::codecForName(
"UTF-8" );
514 encoding = QTextCodec::codecForName(
"UTF-8" );
524 switch ( value.userType() )
526 case QMetaType::Type::Int:
527 case QMetaType::Type::UInt:
528 case QMetaType::Type::LongLong:
529 case QMetaType::Type::ULongLong:
530 case QMetaType::Type::Double:
531 return value.toString();
533 case QMetaType::Type::Bool:
534 return value.toBool() ?
"true" :
"false";
536 case QMetaType::Type::QStringList:
537 case QMetaType::Type::QVariantList:
538 case QMetaType::Type::QVariantMap:
539 return QString::fromUtf8( QJsonDocument::fromVariant( value ).toJson( QJsonDocument::Compact ) );
542 case QMetaType::Type::QString:
544 = value.toString().replace(
'\\',
"\\\\"_L1 ).replace(
'"',
"\\\""_L1 ).replace(
'\r',
"\\r"_L1 ).replace(
'\b',
"\\b"_L1 ).replace(
'\t',
"\\t"_L1 ).replace(
'/',
"\\/"_L1 ).replace(
'\n',
"\\n"_L1 );
546 return v.prepend(
'"' ).append(
'"' );
554 for (
int i = 0; i < fields.
count(); ++i )
566 val = fieldFormatter->
representValue( layer, i, setup.
config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
571 return attrs.prepend(
'{' ).
append(
'}' );
576 QString errorMessage;
580 const auto jObj( json::parse( json.toStdString() ) );
581 if ( !jObj.is_array() )
583 throw json::parse_error::create( 0, 0, u
"JSON value must be an array"_s.toStdString(), &jObj );
585 for (
const auto &item : jObj )
589 if ( item.is_number_integer() )
593 else if ( item.is_number_unsigned() )
595 v = item.get<
unsigned>();
597 else if ( item.is_number_float() )
600 v = item.get<
double>();
602 else if ( item.is_string() )
604 v = QString::fromStdString( item.get<std::string>() );
606 else if ( item.is_boolean() )
608 v = item.get<
bool>();
610 else if ( item.is_null() )
617 if ( type != QMetaType::Type::UnknownType )
619 if ( !v.convert(
static_cast<int>( type ) ) )
621 QgsLogger::warning( u
"Cannot convert json array element to specified type, ignoring: %1"_s.arg( v.toString() ) );
625 result.push_back( v );
630 result.push_back( v );
634 catch ( json::parse_error &ex )
636 errorMessage = ex.what();
650 if ( !coords.is_array() || coords.size() < 2 || coords.size() > 4 )
652 QgsDebugError( u
"JSON Point geometry coordinates must be an array of two, three or four numbers"_s );
656 const double x = coords[0].get<
double >();
657 const double y = coords[1].get<
double >();
658 if ( coords.size() == 2 )
660 return std::make_unique< QgsPoint >( x, y );
662 else if ( coords.size() == 3 )
664 const double zOrM = coords[2].get<
double >();
666 return std::make_unique< QgsPoint >( x, y, std::numeric_limits<double>::quiet_NaN(), zOrM );
668 return std::make_unique< QgsPoint >( x, y, zOrM );
672 const double z = coords[2].get<
double >();
673 const double m = coords[3].get<
double >();
674 return std::make_unique< QgsPoint >( x, y, z, m );
680 if ( !coords.is_array() )
682 QgsDebugError( u
"JSON LineString geometry coordinates must be an array"_s );
686 const std::size_t coordsSize = coords.size();
688 if ( coordsSize == 0 )
691 return std::make_unique< QgsLineString >();
694 if ( coordsSize < 2 )
696 QgsDebugError( u
"JSON LineString geometry coordinates must contain at least two positions"_s );
704 x.resize( coordsSize );
705 y.resize( coordsSize );
706 z.resize( coordsSize );
707 m.resize( coordsSize );
709 double *xOut = x.data();
710 double *yOut = y.data();
711 double *zOut = z.data();
712 double *mOut = m.data();
714 for (
const auto &coord : coords )
716 if ( !coord.is_array() || coord.size() < 2 || coord.size() > 4 )
718 QgsDebugError( u
"JSON LineString geometry coordinates must be an array of two, three or four numbers"_s );
722 *xOut++ = coord[0].get<
double >();
723 *yOut++ = coord[1].get<
double >();
724 if ( coord.size() == 4 )
726 *zOut++ = coord[2].get<
double >();
727 *mOut++ = coord[3].get<
double >();
729 else if ( coord.size() == 3 )
733 *mOut++ = coord[2].get<
double >();
734 *zOut++ = std::numeric_limits< double >::quiet_NaN();
738 *zOut++ = coord[2].get<
double >();
739 *mOut++ = std::numeric_limits< double >::quiet_NaN();
745 *zOut++ = std::numeric_limits< double >::quiet_NaN();
749 return std::make_unique< QgsLineString >( x, y, hasZ ? z : QVector<double>(), hasM ? m : QVector<double>() );
754 if ( !coords.is_array() )
756 QgsDebugError( u
"JSON Polygon geometry coordinates must be an array"_s );
760 if ( coords.empty() )
763 return std::make_unique< QgsPolygon >();
766 const std::size_t coordsSize = coords.size();
773 auto polygon = std::make_unique< QgsPolygon >( exterior.release() );
774 for ( std::size_t i = 1; i < coordsSize; ++i )
781 polygon->addInteriorRing( ring.release() );
788 const auto hasM = hasMIn || ( geometry.contains(
"measures" ) && geometry[
"measures"].contains(
"enabled" ) && geometry[
"measures"][
"enabled"].get<bool>() );
790 if ( !geometry.is_object() )
796 if ( !geometry.contains(
"type" ) )
802 const QString type = QString::fromStdString( geometry[
"type"].get< std::string >() );
803 if ( type.compare(
"Point"_L1, Qt::CaseInsensitive ) == 0 )
805 if ( !geometry.contains(
"coordinates" ) )
807 QgsDebugError( u
"JSON Point geometry must contain 'coordinates'"_s );
811 const json &coords = geometry[
"coordinates"];
814 else if ( type.compare(
"MultiPoint"_L1, Qt::CaseInsensitive ) == 0 )
816 if ( !geometry.contains(
"coordinates" ) )
818 QgsDebugError( u
"JSON MultiPoint geometry must contain 'coordinates'"_s );
822 const json &coords = geometry[
"coordinates"];
824 if ( !coords.is_array() )
826 QgsDebugError( u
"JSON MultiPoint geometry coordinates must be an array"_s );
830 auto multiPoint = std::make_unique< QgsMultiPoint >();
831 multiPoint->reserve(
static_cast< int >( coords.size() ) );
832 for (
const auto &pointCoords : coords )
839 multiPoint->addGeometry( point.release() );
844 else if ( type.compare(
"LineString"_L1, Qt::CaseInsensitive ) == 0 )
846 if ( !geometry.contains(
"coordinates" ) )
848 QgsDebugError( u
"JSON LineString geometry must contain 'coordinates'"_s );
852 const json &coords = geometry[
"coordinates"];
855 else if ( type.compare(
"MultiLineString"_L1, Qt::CaseInsensitive ) == 0 )
857 if ( !geometry.contains(
"coordinates" ) )
859 QgsDebugError( u
"JSON MultiLineString geometry must contain 'coordinates'"_s );
863 const json &coords = geometry[
"coordinates"];
865 if ( !coords.is_array() )
867 QgsDebugError( u
"JSON MultiLineString geometry coordinates must be an array"_s );
871 auto multiLineString = std::make_unique< QgsMultiLineString >();
872 multiLineString->reserve(
static_cast< int >( coords.size() ) );
873 for (
const auto &lineCoords : coords )
880 multiLineString->addGeometry( line.release() );
883 return multiLineString;
885 else if ( type.compare(
"Polygon"_L1, Qt::CaseInsensitive ) == 0 )
887 if ( !geometry.contains(
"coordinates" ) )
889 QgsDebugError( u
"JSON Polygon geometry must contain 'coordinates'"_s );
893 const json &coords = geometry[
"coordinates"];
894 if ( !coords.is_array() )
896 QgsDebugError( u
"JSON Polygon geometry coordinates must be an array"_s );
902 else if ( type.compare(
"MultiPolygon"_L1, Qt::CaseInsensitive ) == 0 )
904 if ( !geometry.contains(
"coordinates" ) )
906 QgsDebugError( u
"JSON MultiPolygon geometry must contain 'coordinates'"_s );
910 const json &coords = geometry[
"coordinates"];
912 if ( !coords.is_array() )
914 QgsDebugError( u
"JSON MultiPolygon geometry coordinates must be an array"_s );
918 auto multiPolygon = std::make_unique< QgsMultiPolygon >();
919 multiPolygon->reserve(
static_cast< int >( coords.size() ) );
920 for (
const auto &polygonCoords : coords )
927 multiPolygon->addGeometry( polygon.release() );
934 else if ( type.compare(
"CircularString"_L1, Qt::CaseInsensitive ) == 0 )
936 if ( !geometry.contains(
"coordinates" ) )
938 QgsDebugError( u
"JSON CircularString geometry must contain 'coordinates'"_s );
942 const json &coords = geometry[
"coordinates"];
944 if ( coords.empty() )
946 return std::make_unique< QgsCircularString >();
949 if ( !coords.is_array() || coords.size() % 2 == 0 || coords.size() < 3 )
951 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 );
955 const bool hasZ = coords[0].is_array() && ( coords[0].size() > 3 || ( coords[0].size() == 3 && !hasM ) );
958 x.reserve( coords.size() );
960 y.reserve( coords.size() );
963 z.reserve( coords.size() );
966 m.reserve( coords.size() );
968 for (
const auto &pointCoords : coords )
973 QgsDebugError( u
"Invalid point in CircularString geometry"_s );
976 x.append( point->x() );
977 y.append( point->y() );
979 z.append( point->z() );
981 m.append( point->m() );
983 return std::make_unique< QgsCircularString >( x, y, z, m );
985 else if ( type.compare(
"CompoundCurve"_L1, Qt::CaseInsensitive ) == 0 )
987 if ( !geometry.contains(
"geometries" ) )
989 QgsDebugError( u
"JSON CompoundCurve geometry must contain 'geometries'"_s );
992 const json &geometries = geometry[
"geometries"];
993 if ( !geometries.is_array() )
995 QgsDebugError( u
"JSON CompoundCurve geometry geometries must be an array"_s );
998 auto compoundCurve = std::make_unique< QgsCompoundCurve >();
999 for (
const auto &geometry : geometries )
1009 QgsDebugError( u
"JSON CompoundCurve geometries must be of type LineString or CircularString"_s );
1012 compoundCurve->addCurve(
static_cast< QgsCurve *
>(
object.release() ) );
1014 return compoundCurve;
1016 else if ( type.compare(
"CurvePolygon"_L1, Qt::CaseInsensitive ) == 0 )
1018 if ( !geometry.contains(
"geometries" ) )
1020 QgsDebugError( u
"JSON CurvePolygon geometry must contain 'geometries'"_s );
1023 const json &geometries = geometry[
"geometries"];
1024 if ( !geometries.is_array() )
1026 QgsDebugError( u
"JSON CurvePolygon geometries must be an array"_s );
1029 auto curvePolygon = std::make_unique< QgsCurvePolygon>();
1030 bool isExterior =
true;
1031 for (
const auto &geometry : geometries )
1041 QgsDebugError( u
"JSON CurvePolygon geometries must be of type LineString, CircularString or CompoundCurve"_s );
1046 curvePolygon->setExteriorRing(
static_cast< QgsCurve *
>(
object.release() ) );
1051 curvePolygon->addInteriorRing(
static_cast< QgsCurve *
>(
object.release() ) );
1054 return curvePolygon;
1056 else if ( type.compare(
"MultiCurve"_L1, Qt::CaseInsensitive ) == 0 )
1058 if ( !geometry.contains(
"geometries" ) )
1060 QgsDebugError( u
"JSON MultiCurve geometry must contain 'geometries'"_s );
1063 const json &geometries = geometry[
"geometries"];
1064 if ( !geometries.is_array() )
1066 QgsDebugError( u
"JSON MultiCurve geometries must be an array"_s );
1069 auto multiCurve = std::make_unique< QgsMultiCurve>();
1070 for (
const auto &geometry : geometries )
1080 QgsDebugError( u
"JSON MultiCurve geometries must be of type LineString, CircularString or CompoundCurve"_s );
1083 multiCurve->addGeometry(
static_cast< QgsCurve *
>(
object.release() ) );
1087 else if ( type.compare(
"MultiSurface"_L1, Qt::CaseInsensitive ) == 0 )
1089 if ( !geometry.contains(
"geometries" ) )
1091 QgsDebugError( u
"JSON MultiSurface geometry must contain 'geometries'"_s );
1094 const json &geometries = geometry[
"geometries"];
1095 if ( !geometries.is_array() )
1097 QgsDebugError( u
"JSON MultiSurface geometries must be an array"_s );
1100 auto multiSurface = std::make_unique< QgsMultiSurface >();
1101 for (
const auto &geometry : geometries )
1111 QgsDebugError( u
"JSON MultiSurface geometries must be of type Polygon or CurvePolygon"_s );
1114 multiSurface->addGeometry(
static_cast< QgsSurface *
>(
object.release() ) );
1116 return multiSurface;
1118 else if ( type.compare(
"GeometryCollection"_L1, Qt::CaseInsensitive ) == 0 )
1120 if ( !geometry.contains(
"geometries" ) )
1122 QgsDebugError( u
"JSON GeometryCollection geometry must contain 'geometries'"_s );
1126 const json &geometries = geometry[
"geometries"];
1128 if ( !geometries.is_array() )
1130 QgsDebugError( u
"JSON GeometryCollection geometries must be an array"_s );
1134 auto collection = std::make_unique< QgsGeometryCollection >();
1135 collection->reserve(
static_cast< int >( geometries.size() ) );
1136 for (
const auto &geometry : geometries )
1143 collection->addGeometry(
object.release() );
1149 QgsDebugError( u
"Unhandled GeoJSON geometry type: %1"_s.arg( type ) );
1155 if ( !geometry.is_object() )
1157 QgsDebugError( u
"JSON geometry value must be an object"_s );
1168 const auto jObj( json::parse( geometry.toStdString() ) );
1171 catch ( json::parse_error &ex )
1173 QgsDebugError( u
"Cannot parse json (%1): %2"_s.arg( geometry, ex.what() ) );
1190 if ( val.userType() == QMetaType::Type::QVariantMap )
1192 const QVariantMap &vMap = val.toMap();
1193 json jMap = json::object();
1194 for (
auto it = vMap.constBegin(); it != vMap.constEnd(); it++ )
1200 else if ( val.userType() == QMetaType::Type::QVariantList || val.userType() == QMetaType::Type::QStringList )
1202 const QVariantList &vList = val.toList();
1203 json jList = json::array();
1204 for (
const auto &v : vList )
1212 switch ( val.userType() )
1214 case QMetaType::Int:
1215 case QMetaType::UInt:
1216 case QMetaType::LongLong:
1217 case QMetaType::ULongLong:
1218 j = val.toLongLong();
1220 case QMetaType::Double:
1221 case QMetaType::Float:
1224 case QMetaType::Bool:
1227 case QMetaType::QByteArray:
1228 j = val.toByteArray().toBase64().toStdString();
1231 j = val.toString().toStdString();
1241 const QVariant res =
parseJson( jsonString, error );
1243 if ( !error.isEmpty() )
1245 QgsLogger::warning( u
"Cannot parse json (%1): %2"_s.arg( error, QString::fromStdString( jsonString ) ) );
1255 const json j = json::parse( jsonString );
1258 catch ( json::parse_error &ex )
1260 error = QString::fromStdString( ex.what() );
1262 catch ( json::type_error &ex )
1264 error = QString::fromStdString( ex.what() );
1272 bool isPrimitive =
true;
1274 std::function<QVariant( json )> _parser { [&]( json jObj ) -> QVariant {
1276 if ( jObj.is_array() )
1278 isPrimitive =
false;
1279 QVariantList results;
1280 results.reserve( jObj.size() );
1281 for (
const auto &item : jObj )
1283 results.push_back( _parser( item ) );
1287 else if ( jObj.is_object() )
1289 isPrimitive =
false;
1290 QVariantMap results;
1291 for (
const auto &item : jObj.items() )
1293 const auto key { QString::fromStdString( item.key() ) };
1294 const auto value { _parser( item.value() ) };
1295 results[key] = value;
1301 if ( jObj.is_number_unsigned() )
1305 const qulonglong num { jObj.get<qulonglong>() };
1306 if ( num <= std::numeric_limits<int>::max() )
1308 result =
static_cast<int>( num );
1310 else if ( num <= std::numeric_limits<qlonglong>::max() )
1312 result =
static_cast<qlonglong
>( num );
1319 else if ( jObj.is_number_integer() )
1321 const qlonglong num { jObj.get<qlonglong>() };
1322 if ( num <= std::numeric_limits<int>::max() && num >= std::numeric_limits<int>::lowest() )
1324 result =
static_cast<int>( num );
1331 else if ( jObj.is_boolean() )
1333 result = jObj.get<
bool>();
1335 else if ( jObj.is_number_float() )
1338 result = jObj.get<
double>();
1340 else if ( jObj.is_string() )
1342 if ( isPrimitive && jObj.get<std::string>().length() == 0 )
1344 result = QString::fromStdString( jObj.get<std::string>() ).append(
"\"" ).insert( 0,
"\"" );
1348 result = QString::fromStdString( jObj.get<std::string>() );
1351 else if ( jObj.is_null() )
1359 return _parser( value );
1364 return jsonString.isEmpty() ? QVariant() :
parseJson( jsonString.toStdString() );
1371 for (
int i = 0; i < fields.
count(); ++i )
1375 if ( layer && useFieldFormatters )
1380 val = fieldFormatter->
representValue( layer, i, setup.
config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
1392 if ( crs.
authid() ==
"EPSG:4326" || crs.
authid() ==
"CRS:84" || crs.
authid() ==
"OGC:CRS84" )
1403 value[
"crs"][
"type"] =
"name";
1404 value[
"crs"][
"properties"][
"name"] = crs.
toOgcUrn().toStdString();
1410 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)