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