31 #include <QJsonDocument>
34 #include <nlohmann/json.hpp>
38 , mLayer( vectorLayer )
75 const QVariant &
id,
int indent )
const
84 {
"type",
"Feature" },
89 auto intId =
id.toLongLong( &ok );
92 featureJson[
"id"] = intId;
96 featureJson[
"id"] =
id.toString().toStdString();
101 featureJson[
"id"] =
nullptr;
105 featureJson[
"id"] = feature.
id();
109 if ( !geom.
isNull() && mIncludeGeometry )
116 if ( mTransformGeometries && transformed.
transform( mTransform ) == 0 )
128 featureJson[
"bbox" ] =
136 featureJson[
"geometry" ] = geom.
asJsonObject( mPrecision );
140 featureJson[
"geometry" ] =
nullptr;
144 int attributeCounter { 0 };
146 if ( mIncludeAttributes || !extraProperties.isEmpty() )
149 if ( mIncludeAttributes )
153 QStringList formattersAllowList;
154 formattersAllowList << QStringLiteral(
"KeyValue" )
155 << QStringLiteral(
"List" )
156 << QStringLiteral(
"ValueRelation" )
157 << QStringLiteral(
"ValueMap" );
159 for (
int i = 0; i < fields.
count(); ++i )
161 if ( ( !mAttributeIndexes.isEmpty() && !mAttributeIndexes.contains( i ) ) || mExcludedAttributeIndexes.contains( i ) )
170 if ( formattersAllowList.contains( fieldFormatter->
id() ) )
174 QString name = fields.
at( i ).
name();
175 if ( mAttributeDisplayName )
177 name = mLayer->attributeDisplayName( i );
184 if ( !extraProperties.isEmpty() )
186 QVariantMap::const_iterator it = extraProperties.constBegin();
187 for ( ; it != extraProperties.constEnd(); ++it )
195 if ( mLayer && mIncludeRelatedAttributes )
198 for (
const auto &relation : std::as_const( relations ) )
203 json relatedFeatureAttributes;
207 QVector<QVariant> attributeWidgetCaches;
214 attributeWidgetCaches.append( fieldFormatter->
createCache( childLayer, fieldIndex, setup.
config() ) );
223 properties[ relation.name().toStdString() ] = relatedFeatureAttributes;
228 featureJson[
"properties" ] = properties;
241 {
"type",
"FeatureCollection" },
242 {
"features", json::array() }
244 for (
const QgsFeature &feature : std::as_const( features ) )
258 encoding = QTextCodec::codecForName(
"UTF-8" );
266 encoding = QTextCodec::codecForName(
"UTF-8" );
273 if ( value.isNull() )
274 return QStringLiteral(
"null" );
276 switch ( value.type() )
280 case QVariant::LongLong:
281 case QVariant::ULongLong:
282 case QVariant::Double:
283 return value.toString();
286 return value.toBool() ?
"true" :
"false";
288 case QVariant::StringList:
291 return QString::fromUtf8( QJsonDocument::fromVariant( value ).toJson( QJsonDocument::Compact ) );
294 case QVariant::String:
295 QString v = value.toString()
296 .replace(
'\\', QLatin1String(
"\\\\" ) )
297 .replace(
'"', QLatin1String(
"\\\"" ) )
298 .replace(
'\r', QLatin1String(
"\\r" ) )
299 .replace(
'\b', QLatin1String(
"\\b" ) )
300 .replace(
'\t', QLatin1String(
"\\t" ) )
301 .replace(
'/', QLatin1String(
"\\/" ) )
302 .replace(
'\n', QLatin1String(
"\\n" ) );
304 return v.prepend(
'"' ).append(
'"' );
312 for (
int i = 0; i < fields.
count(); ++i )
315 attrs += QLatin1String(
",\n" );
324 val = fieldFormatter->
representValue( layer, i, setup.
config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
329 return attrs.prepend(
'{' ).append(
'}' );
334 QString errorMessage;
338 const auto jObj(
json::parse( json.toStdString() ) );
339 if ( ! jObj.is_array() )
341 throw json::parse_error::create( 0, 0, QStringLiteral(
"JSON value must be an array" ).toStdString() );
343 for (
const auto &item : jObj )
347 if ( item.is_number_integer() )
351 else if ( item.is_number_unsigned() )
353 v = item.get<
unsigned>();
355 else if ( item.is_number_float() )
358 v = item.get<
double>();
360 else if ( item.is_string() )
362 v = QString::fromStdString( item.get<std::string>() );
364 else if ( item.is_boolean() )
366 v = item.get<
bool>();
368 else if ( item.is_null() )
371 v = QVariant( type == QVariant::Type::Invalid ? QVariant::Type::Int : type );
375 if ( type != QVariant::Invalid )
377 if ( ! v.convert(
static_cast<int>( type ) ) )
379 QgsLogger::warning( QStringLiteral(
"Cannot convert json array element to specified type, ignoring: %1" ).arg( v.toString() ) );
383 result.push_back( v );
388 result.push_back( v );
392 catch ( json::parse_error &ex )
394 errorMessage = ex.what();
395 QgsLogger::warning( QStringLiteral(
"Cannot parse json (%1): %2" ).arg( ex.what(), json ) );
403 if ( val.isNull() || ! val.isValid() )
408 if ( val.type() == QVariant::Type::Map )
410 const QVariantMap &vMap = val.toMap();
411 json jMap = json::object();
412 for (
auto it = vMap.constBegin(); it != vMap.constEnd(); it++ )
418 else if ( val.type() == QVariant::Type::List || val.type() == QVariant::Type::StringList )
420 const QVariantList &vList = val.toList();
421 json jList = json::array();
422 for (
const auto &v : vList )
430 switch ( val.userType() )
433 case QMetaType::UInt:
434 case QMetaType::LongLong:
435 case QMetaType::ULongLong:
436 j = val.toLongLong();
438 case QMetaType::Double:
439 case QMetaType::Float:
442 case QMetaType::Bool:
445 case QMetaType::QByteArray:
446 j = val.toByteArray().toBase64().toStdString();
449 j = val.toString().toStdString();
459 bool isPrimitive =
true;
461 std::function<QVariant( json )> _parser { [ & ]( json jObj ) -> QVariant {
463 if ( jObj.is_array() )
466 QVariantList results;
467 for (
const auto &item : jObj )
469 results.push_back( _parser( item ) );
473 else if ( jObj.is_object() )
477 for (
const auto &item : jObj.items() )
479 const auto key { QString::fromStdString( item.key() ) };
480 const auto value { _parser( item.value() ) };
481 results[ key ] = value;
487 if ( jObj.is_number_integer() )
489 result = jObj.get<
int>();
491 else if ( jObj.is_number_unsigned() )
493 result = jObj.get<
unsigned>();
495 else if ( jObj.is_boolean() )
497 result = jObj.get<
bool>();
499 else if ( jObj.is_number_float() )
502 result = jObj.get<
double>();
504 else if ( jObj.is_string() )
506 if ( isPrimitive && jObj.get<std::string>().length() == 0 )
508 result = QString::fromStdString( jObj.get<std::string>() ).append(
"\"" ).insert( 0,
"\"" );
512 result = QString::fromStdString( jObj.get<std::string>() );
515 else if ( jObj.is_null() )
529 catch ( json::parse_error &ex )
531 QgsLogger::warning( QStringLiteral(
"Cannot parse json (%1): %2" ).arg( QString::fromStdString( ex.what() ),
532 QString::fromStdString( jsonString ) ) );
539 return parseJson( jsonString.toStdString() );
546 for (
int i = 0; i < fields.
count(); ++i )
555 val = fieldFormatter->
representValue( layer, i, setup.
config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Custom exception class for Coordinate Reference System related exceptions.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
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.
int count() const
Returns number of items.
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.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
virtual json asJsonObject(int precision=17) const
Exports the geometry to a json object.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
json exportFeatureToJsonObject(const QgsFeature &feature, const QVariantMap &extraProperties=QVariantMap(), const QVariant &id=QVariant()) const
Returns a QJsonObject representation of a feature.
json exportFeaturesToJsonObject(const QgsFeatureList &features) const
Returns a JSON object representation of a list of features (feature collection).
void setSourceCrs(const QgsCoordinateReferenceSystem &crs)
Sets the source CRS for feature geometries.
QgsVectorLayer * vectorLayer() const
Returns the associated vector layer, if set.
QString exportFeature(const QgsFeature &feature, const QVariantMap &extraProperties=QVariantMap(), const QVariant &id=QVariant(), int indent=-1) const
Returns a GeoJSON string representation of a feature.
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.
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields=QgsFields(), QTextCodec *encoding=nullptr)
Attempts to parse a GeoJSON string to a collection of features.
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 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.
static json exportAttributesToJsonObject(const QgsFeature &feature, QgsVectorLayer *layer=nullptr, const QVector< QVariant > &attributeWidgetCaches=QVector< QVariant >())
Exports all attributes from a QgsFeature as a json object.
static QgsFields stringToFields(const QString &string, QTextCodec *encoding=nullptr)
Attempts to retrieve the fields from a GeoJSON string representing a collection of features.
static Q_INVOKABLE QVariantList parseArray(const QString &json, QVariant::Type type=QVariant::Invalid)
Parse a simple array (depth=1)
static json jsonFromVariant(const QVariant &v)
Converts a QVariant v to a json object.
static void warning(const QString &msg)
Goes to qWarning.
QgsCoordinateReferenceSystem crs
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.
A rectangle specified with double values.
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
static Type flatType(Type type) SIP_HOLDGIL
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
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg, bool allowFragments)
const QgsCoordinateReferenceSystem & crs