29#include <QNetworkRequest>
30#include <QNetworkReply>
31#include <QProgressDialog>
36#include <QRegularExpression>
42using namespace nlohmann;
44static const char NS_SEPARATOR =
'?';
45static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
50 const QString &geometryAttribute,
52 : mParser(
typeName, geometryAttribute, fields )
56 const int index = mTypeName.indexOf(
':' );
57 if ( index != -1 && index < mTypeName.length() )
59 mTypeName = mTypeName.mid( index + 1 );
68 QNetworkRequest request( uri );
71 if ( !authcfg.isEmpty() )
76 tr(
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
83 else if ( !userName.isNull() || !password.isNull() )
85 request.setRawHeader(
"Authorization",
"Basic " + QStringLiteral(
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
89 if ( !authcfg.isEmpty() )
95 tr(
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
103 connect( reply, &QNetworkReply::finished,
this, &QgsGml::setFinished );
104 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsGml::handleProgressEvent );
107 QProgressDialog *progressDialog =
nullptr;
108 QWidget *mainWindow =
nullptr;
109 const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
110 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
112 if ( ( *it )->objectName() == QLatin1String(
"QgisApp" ) )
120 progressDialog =
new QProgressDialog( tr(
"Loading GML data\n%1" ).arg( mTypeName ), tr(
"Abort" ), 0, 0, mainWindow );
121 progressDialog->setWindowModality( Qt::ApplicationModal );
124 connect( progressDialog, &QProgressDialog::canceled,
this, &QgsGml::setFinished );
125 progressDialog->show();
135 const QByteArray readData = reply->readAll();
136 if ( !readData.isEmpty() )
139 if ( !mParser.
processData( readData, atEnd, errorMsg ) )
143 QCoreApplication::processEvents();
146 fillMapsFromParser();
148 const QNetworkReply::NetworkError replyError = reply->error();
149 const QString replyErrorString = reply->errorString();
152 delete progressDialog;
157 tr(
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
171 calculateExtentFromFeatures();
186 if ( !mParser.
processData( data,
true , errorMsg ) )
189 fillMapsFromParser();
199void QgsGml::fillMapsFromParser()
202 const auto constFeatures = features;
206 const QString &gmlId = featPair.second;
207 mFeatures.insert( feat->
id(), feat );
208 if ( !gmlId.isEmpty() )
210 mIdMap.insert( feat->
id(), gmlId );
215void QgsGml::setFinished()
220void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
222 if ( totalSteps < 0 )
232void QgsGml::calculateExtentFromFeatures()
234 if ( mFeatures.empty() )
241 bool bboxInitialized =
false;
243 for (
int i = 0; i < mFeatures.size(); ++i )
245 currentFeature = mFeatures[i];
246 if ( !currentFeature )
250 currentGeometry = currentFeature->
geometry();
251 if ( !currentGeometry.
isNull() )
253 if ( !bboxInitialized )
256 bboxInitialized =
true;
281 const QString &geometryAttribute,
284 bool invertAxisOrientation )
286 , mTypeNameBA( mTypeName.toUtf8() )
287 , mTypeNamePtr( mTypeNameBA.constData() )
288 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
289 , mWkbType(
Qgis::WkbType::Unknown )
290 , mGeometryAttribute( geometryAttribute )
291 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
292 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
293 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
295 , mIsException( false )
296 , mTruncatedResponse( false )
298 , mFeatureTupleDepth( 0 )
300 , mCurrentWKB( nullptr, 0 )
301 , mBoundedByNullFound( false )
303 , mCoorMode( Coordinate )
305 , mAxisOrientationLogic( axisOrientationLogic )
306 , mInvertAxisOrientationRequest( invertAxisOrientation )
307 , mInvertAxisOrientation( invertAxisOrientation )
308 , mNumberReturned( -1 )
309 , mNumberMatched( -1 )
310 , mFoundUnhandledGeometryElement( false )
312 mThematicAttributes.clear();
313 for (
int i = 0; i < fields.
size(); i++ )
315 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
320 const int index = mTypeName.indexOf(
':' );
321 if ( index != -1 && index < mTypeName.length() )
323 mTypeName = mTypeName.mid( index + 1 );
324 mTypeNameBA = mTypeName.toUtf8();
325 mTypeNamePtr = mTypeNameBA.constData();
326 mTypeNameUTF8Len = strlen( mTypeNamePtr );
332static QString stripNS(
const QString &
string )
334 const int index =
string.indexOf(
':' );
335 if ( index != -1 && index <
string.length() )
337 return string.mid( index + 1 );
344 const QMap< QString, QPair<QString, QString> > &fieldNameToSrcLayerNameFieldNameMap,
346 bool invertAxisOrientation )
347 : mLayerProperties( layerProperties )
348 , mTypeNameUTF8Len( 0 )
349 , mWkbType(
Qgis::WkbType::Unknown )
350 , mGeometryAttributeUTF8Len( 0 )
352 , mIsException( false )
353 , mTruncatedResponse( false )
355 , mFeatureTupleDepth( 0 )
357 , mCurrentWKB( nullptr, 0 )
358 , mBoundedByNullFound( false )
360 , mCoorMode( Coordinate )
362 , mAxisOrientationLogic( axisOrientationLogic )
363 , mInvertAxisOrientationRequest( invertAxisOrientation )
364 , mInvertAxisOrientation( invertAxisOrientation )
365 , mNumberReturned( -1 )
366 , mNumberMatched( -1 )
367 , mFoundUnhandledGeometryElement( false )
369 mThematicAttributes.clear();
370 for (
int i = 0; i < fields.
size(); i++ )
372 const QMap< QString, QPair<QString, QString> >::const_iterator att_it = fieldNameToSrcLayerNameFieldNameMap.constFind( fields.
at( i ).
name() );
373 if ( att_it != fieldNameToSrcLayerNameFieldNameMap.constEnd() )
375 if ( mLayerProperties.size() == 1 )
376 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
378 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
381 bool alreadyFoundGeometry =
false;
382 for (
int i = 0; i < mLayerProperties.size(); i++ )
385 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
387 if ( alreadyFoundGeometry )
389 QgsDebugMsgLevel( QStringLiteral(
"Will ignore geometry field %1 from typename %2" ).
390 arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ), 2 );
391 mLayerProperties[i].mGeometryAttribute.clear();
393 alreadyFoundGeometry =
true;
395 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
398 if ( mLayerProperties.size() == 1 )
400 mTypeName = mLayerProperties[0].mName;
401 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
402 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
403 mGeometryAttributePtr = mGeometryAttributeBA.constData();
404 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
405 const int index = mTypeName.indexOf(
':' );
406 if ( index != -1 && index < mTypeName.length() )
408 mTypeName = mTypeName.mid( index + 1 );
410 mTypeNameBA = mTypeName.toUtf8();
411 mTypeNamePtr = mTypeNameBA.constData();
412 mTypeNameUTF8Len = strlen( mTypeNamePtr );
422 const QMap<QString, QPair<QString, bool>> &fieldNameToXPathMapAndIsNestedContent,
423 const QMap<QString, QString> &mapNamespacePrefixToURI )
425 for (
auto iter = fieldNameToXPathMapAndIsNestedContent.constBegin(); iter != fieldNameToXPathMapAndIsNestedContent.constEnd(); ++iter )
427 mMapXPathToFieldNameAndIsNestedContent[iter.value().first] = QPair<QString, bool>( iter.key(), iter.value().second );
429 for (
auto iter = mapNamespacePrefixToURI.constBegin(); iter != mapNamespacePrefixToURI.constEnd(); ++iter )
430 mMapNamespaceURIToNamespacePrefix[iter.value()] = iter.key();
436 XML_ParserFree( mParser );
439 const auto constMFeatureList = mFeatureList;
442 delete featPair.first;
445 delete mCurrentFeature;
461 QByteArray data = pdata;
466 QString strData = mCodec->toUnicode( pdata );
467 data = strData.toUtf8();
470 if ( XML_Parse( mParser, data, data.size(), atEnd ) == XML_STATUS_ERROR )
472 const XML_Error errorCode = XML_GetErrorCode( mParser );
473 if ( !mCodec && errorCode == XML_ERROR_UNKNOWN_ENCODING )
477 const thread_local QRegularExpression reEncoding( QStringLiteral(
"<?xml.*encoding=['\"]([^'\"]*)['\"].*?>" ),
478 QRegularExpression::CaseInsensitiveOption );
479 QRegularExpressionMatch match = reEncoding.match( pdata );
480 const QString encoding = match.hasMatch() ? match.captured( 1 ) : QString();
481 mCodec = !encoding.isEmpty() ? QTextCodec::codecForName( encoding.toLatin1() ) :
nullptr;
485 XML_ParserFree( mParser );
487 createParser( QByteArrayLiteral(
"UTF-8" ) );
493 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" )
494 .arg( XML_ErrorString( errorCode ) )
495 .arg( XML_GetCurrentLineNumber( mParser ) )
496 .arg( XML_GetCurrentColumnNumber( mParser ) );
506 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
507 mFeatureList.clear();
515static json jsonFromString(
const QString &s )
520 if ( s.indexOf(
'.' ) >= 0 || s.indexOf(
'e' ) >= 0 )
522 const auto doubleVal = s.toDouble( &conversionOk );
525 return json( doubleVal );
530 else if ( !s.isEmpty() && s[0] !=
'0' )
532 const auto longlongVal = s.toLongLong( &conversionOk );
535 return json( longlongVal );
539 return json( s.toStdString() );
542#define LOCALNAME_EQUALS(string_constant) \
543 ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 )
542#define LOCALNAME_EQUALS(string_constant) \ …
545void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
547 const int elLen =
static_cast<int>( strlen( el ) );
548 const char *pszSep = strchr( el, NS_SEPARATOR );
549 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
550 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
551 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
552 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
556 if ( !mGMLNameSpaceURIPtr && pszSep )
570 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
573 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
574 parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
576 mGeometryString.append(
"<", 1 );
577 mGeometryString.append( pszLocalName, localNameLen );
578 mGeometryString.append(
" ", 1 );
579 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
581 const size_t nAttrLen = strlen( attrIter[0] );
584 if ( nAttrLen > GML32_NAMESPACE_LEN &&
585 attrIter[0][GML32_NAMESPACE_LEN] ==
'?' &&
588 mGeometryString.append(
"gml:" );
589 mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
591 else if ( nAttrLen > GML_NAMESPACE_LEN &&
592 attrIter[0][GML_NAMESPACE_LEN] ==
'?' &&
593 memcmp( attrIter[0],
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
595 mGeometryString.append(
"gml:" );
596 mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
600 mGeometryString.append( attrIter[0] );
602 mGeometryString.append(
"=\"", 2 );
603 mGeometryString.append( attrIter[1] );
604 mGeometryString.append(
"\" ", 2 );
607 mGeometryString.append(
">", 1 );
610 if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
612 mParseModeStack.push( Coordinate );
613 mCoorMode = QgsGmlStreamingParser::Coordinate;
615 mCoordinateSeparator = readAttribute( QStringLiteral(
"cs" ), attr );
616 if ( mCoordinateSeparator.isEmpty() )
618 mCoordinateSeparator =
',';
620 mTupleSeparator = readAttribute( QStringLiteral(
"ts" ), attr );
621 if ( mTupleSeparator.isEmpty() )
623 mTupleSeparator =
' ';
626 else if ( !mAttributeValIsNested && isGMLNS &&
629 mParseModeStack.push( QgsGmlStreamingParser::PosList );
630 mCoorMode = QgsGmlStreamingParser::PosList;
632 if ( elDimension == 0 )
634 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
636 const int dimension = srsDimension.toInt( &ok );
639 elDimension = dimension;
643 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
645 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
646 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
648 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
649 mFoundUnhandledGeometryElement =
false;
650 mGeometryString.clear();
653 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
655 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
657 mBoundedByNullFound =
false;
659 else if ( parseMode == BoundingBox &&
662 mParseModeStack.push( QgsGmlStreamingParser::Null );
663 mBoundedByNullFound =
true;
665 else if ( parseMode == BoundingBox &&
669 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
671 else if ( parseMode == Envelope &&
674 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
677 else if ( parseMode == Envelope &&
680 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
683 else if ( parseMode == None && !mTypeNamePtr &&
686 Q_ASSERT( !mCurrentFeature );
687 mCurrentFeature =
new QgsFeature( mFeatureCount );
689 const QgsAttributes attributes( mThematicAttributes.size() );
691 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
692 mCurrentFeatureId.clear();
694 else if ( parseMode == Tuple )
696 const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
697 const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
698 if ( iter != mMapTypeNameToProperties.constEnd() )
700 mFeatureTupleDepth = mParseDepth;
701 mCurrentTypename = currentTypename;
702 mGeometryAttribute.clear();
703 if ( mCurrentWKB.
size() == 0 )
705 mGeometryAttribute = iter.value().mGeometryAttribute;
707 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
708 mGeometryAttributePtr = mGeometryAttributeBA.constData();
709 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
710 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
712 if ( mGMLNameSpaceURI.isEmpty() )
714 id = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
722 id = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
731 id = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
732 if ( !mCurrentFeatureId.isEmpty() )
733 mCurrentFeatureId +=
'|';
734 mCurrentFeatureId += id;
737 else if ( parseMode == None &&
738 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
740 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
742 Q_ASSERT( !mCurrentFeature );
743 mCurrentFeature =
new QgsFeature( mFeatureCount );
745 const QgsAttributes attributes( mThematicAttributes.size() );
747 mParseModeStack.push( QgsGmlStreamingParser::Feature );
748 mCurrentXPathWithinFeature.clear();
749 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
750 if ( mCurrentFeatureId.isEmpty() )
755 if ( mGMLNameSpaceURI.isEmpty() )
757 mCurrentFeatureId = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
758 if ( !mCurrentFeatureId.isEmpty() )
765 mCurrentFeatureId = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
766 if ( !mCurrentFeatureId.isEmpty() )
774 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
778 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
782 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
786 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"LineString" ) )
790 else if ( !mAttributeValIsNested && isGMLNS &&
791 localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
794 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
796 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
799 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
801 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
806 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
808 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
813 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
815 else if ( parseMode == FeatureTuple )
817 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
818 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
820 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
821 mAttributeName = mCurrentTypename +
'|' + localName;
825 else if ( parseMode == Feature )
827 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
828 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
830 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
831 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
832 if ( !mCurrentXPathWithinFeature.isEmpty() )
833 mCurrentXPathWithinFeature.append(
'/' );
834 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
836 mCurrentXPathWithinFeature.append( *nsIter );
837 mCurrentXPathWithinFeature.append(
':' );
839 mCurrentXPathWithinFeature.append( localName );
840 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( mCurrentXPathWithinFeature );
841 mAttributeValIsNested =
false;
842 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
844 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
845 mAttributeDepth = mParseDepth;
846 mAttributeName = xpathIter->first;
847 mAttributeValIsNested = xpathIter->second;
848 if ( mAttributeValIsNested )
850 mAttributeJson = json::object();
851 mAttributeJsonCurrentStack.clear();
852 mAttributeJsonCurrentStack.push( &mAttributeJson );
857 else if ( mThematicAttributes.contains( localName ) )
859 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
860 mAttributeDepth = mParseDepth;
861 mAttributeName = localName;
868 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
870 const QString name = readAttribute( QStringLiteral(
"name" ), attr );
871 if ( mThematicAttributes.contains( name ) )
873 const QString value = readAttribute( QStringLiteral(
"value" ), attr );
874 setAttribute( name, value );
879 else if ( parseMode == Attribute && mAttributeValIsNested )
881 const std::string localName( pszLocalName, localNameLen );
882 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
883 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
884 const std::string nodeName = nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() ? ( *nsIter ).toStdString() +
':' + localName : localName;
886 addStringContentToJson();
888 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
889 auto iter = jsonParent.find( nodeName );
890 if ( iter != jsonParent.end() )
892 if ( iter->type() != json::value_t::array )
894 auto array = json::array();
895 array.emplace_back( std::move( *iter ) );
898 iter->push_back( json::object() );
899 mAttributeJsonCurrentStack.push( &( iter->back() ) );
903 auto res = jsonParent.emplace( nodeName, json::object() );
907 nlohmann::json *ptr = &( *( res.first ) );
909 mAttributeJsonCurrentStack.push( ptr );
914 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
916 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
920 mNumberReturned = -1;
922 const QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
930 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
935 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
940 mTruncatedResponse =
true;
942 else if ( !mGeometryString.empty() &&
958 mFoundUnhandledGeometryElement =
true;
962 if ( !mParseModeStack.isEmpty() &&
963 ( mParseModeStack.back() == Feature ||
964 mParseModeStack.back() == Attribute ) &&
965 !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
967 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
969 const char *questionMark = strchr( attrIter[0],
'?' );
973 const QString nsURI( QString::fromUtf8( attrIter[0],
static_cast<int>( questionMark - attrIter[0] ) ) );
974 const QString localName( QString::fromUtf8( questionMark + 1 ) );
975 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
976 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
978 key.append( *nsIter );
981 key.append( localName );
985 const QString localName( QString::fromUtf8( attrIter[0] ) );
986 key.append( localName );
989 if ( mAttributeValIsNested && mParseModeStack.back() == Attribute )
991 mAttributeJsonCurrentStack.top()->emplace(
993 jsonFromString( QString::fromUtf8( attrIter[1] ) ) );
997 QString xpath( mCurrentXPathWithinFeature );
998 if ( !xpath.isEmpty() )
1000 xpath.append( key );
1001 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( xpath );
1002 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
1004 setAttribute( xpathIter->first, QString::fromUtf8( attrIter[1] ) );
1010 if ( !mGeometryString.empty() )
1013 if ( elDimension == 0 && isGeom )
1017 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
1019 const int dimension = srsDimension.toInt( &ok );
1022 elDimension = dimension;
1026 if ( elDimension != 0 || mDimensionStack.isEmpty() )
1028 mDimensionStack.push( elDimension );
1032 mDimensionStack.push( mDimensionStack.back() );
1035 if ( mEpsg == 0 && isGeom )
1037 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
1039 QgsDebugError( QStringLiteral(
"error, could not get epsg id" ) );
1050void QgsGmlStreamingParser::endElement(
const XML_Char *el )
1054 const int elLen =
static_cast<int>( strlen( el ) );
1055 const char *pszSep = strchr( el, NS_SEPARATOR );
1056 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
1057 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
1058 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
1059 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
1061 const int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
1063 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
1065 if ( parseMode == Feature || ( parseMode == Attribute && mAttributeDepth == mParseDepth ) )
1067 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
1069 const auto nPos = mCurrentXPathWithinFeature.lastIndexOf(
'/' );
1071 mCurrentXPathWithinFeature.clear();
1073 mCurrentXPathWithinFeature.resize( nPos );
1077 if ( parseMode == Attribute && mAttributeValIsNested )
1079 if ( !mStringCash.isEmpty() )
1081 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1082 if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
1084 jsonParent = jsonFromString( mStringCash );
1086 else if ( jsonParent.type() == json::value_t::object )
1088 addStringContentToJson();
1090 mStringCash.clear();
1093 mAttributeJsonCurrentStack.pop();
1096 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
1098 mParseModeStack.pop();
1100 else if ( parseMode == PosList && isGMLNS &&
1103 mDimension = lastDimension;
1104 mParseModeStack.pop();
1106 else if ( parseMode == AttributeTuple &&
1107 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
1109 mParseModeStack.pop();
1111 setAttribute( mAttributeName, mStringCash );
1113 else if ( parseMode == Attribute && mAttributeDepth == mParseDepth )
1115 mParseModeStack.pop();
1118 if ( mAttributeValIsNested )
1120 mAttributeValIsNested =
false;
1121 auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
1122 if ( iter == mMapFieldNameToJSONContent.end() )
1124 mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
1128 QString &
str = iter.value();
1129 if (
str[0] ==
'[' &&
str.back() ==
']' )
1135 str.insert( 0,
'[' );
1138 str.append( QString::fromStdString( mAttributeJson.dump() ) );
1144 setAttribute( mAttributeName, mStringCash );
1147 else if ( parseMode == Geometry &&
1148 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
1149 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1151 mParseModeStack.pop();
1152 if ( mFoundUnhandledGeometryElement )
1158 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
1159 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
1160 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
1162 g.
fromWkb( pabyBuffer, wkbSize );
1163 if ( mInvertAxisOrientation )
1165 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1167 Q_ASSERT( mCurrentFeature );
1171 mGeometryString.clear();
1173 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
1176 if ( mCurrentExtent.
isNull() &&
1177 !mBoundedByNullFound &&
1178 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
1180 QgsDebugError( QStringLiteral(
"creation of bounding box failed" ) );
1182 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
1183 !mCurrentFeature && mFeatureCount == 0 )
1185 mLayerExtent = mCurrentExtent;
1189 mParseModeStack.pop();
1193 mParseModeStack.pop();
1195 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
1197 mParseModeStack.pop();
1199 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
1201 QList<QgsPointXY> points;
1202 pointsFromPosListString( points, mStringCash, 2 );
1203 if ( points.size() == 1 )
1208 mParseModeStack.pop();
1210 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
1212 QList<QgsPointXY> points;
1213 pointsFromPosListString( points, mStringCash, 2 );
1214 if ( points.size() == 1 )
1219 mParseModeStack.pop();
1221 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
1223 mParseModeStack.pop();
1224 mFeatureTupleDepth = 0;
1226 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
1228 ( parseMode == Feature &&
1229 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
1230 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
1232 Q_ASSERT( mCurrentFeature );
1235 if ( mCurrentWKB.
size() > 0 )
1242 else if ( !mCurrentExtent.
isEmpty() )
1249 for (
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
1251 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
1252 const int attrIndex = att_it.value().first;
1253 mCurrentFeature->
setAttribute( attrIndex, iter.value() );
1255 mMapFieldNameToJSONContent.clear();
1259 mCurrentFeature =
nullptr;
1261 mParseModeStack.pop();
1263 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
1265 QList<QgsPointXY> pointList;
1266 if ( pointsFromString( pointList, mStringCash ) != 0 )
1271 if ( pointList.isEmpty() )
1274 if ( parseMode == QgsGmlStreamingParser::Geometry )
1277 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
1290 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
1294 if ( !mCurrentWKBFragments.isEmpty() )
1296 mCurrentWKBFragments.last().push_back( wkbPtr );
1305 else if ( !mAttributeValIsNested &&
1310 QList<QgsPointXY> pointList;
1311 if ( pointsFromString( pointList, mStringCash ) != 0 )
1315 if ( parseMode == QgsGmlStreamingParser::Geometry )
1317 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
1330 if ( getLineWKB( wkbPtr, pointList ) != 0 )
1334 if ( !mCurrentWKBFragments.isEmpty() )
1336 mCurrentWKBFragments.last().push_back( wkbPtr );
1345 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1348 QList<QgsPointXY> pointList;
1349 if ( pointsFromString( pointList, mStringCash ) != 0 )
1355 if ( getRingWKB( wkbPtr, pointList ) != 0 )
1360 if ( !mCurrentWKBFragments.isEmpty() )
1362 mCurrentWKBFragments.last().push_back( wkbPtr );
1370 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1378 if ( parseMode == Geometry )
1380 createPolygonFromFragments();
1383 else if ( parseMode == MultiPoint && isGMLNS &&
1387 mParseModeStack.pop();
1388 createMultiPointFromFragments();
1390 else if ( parseMode == MultiLine && isGMLNS &&
1394 mParseModeStack.pop();
1395 createMultiLineFromFragments();
1397 else if ( parseMode == MultiPolygon && isGMLNS &&
1401 mParseModeStack.pop();
1402 createMultiPolygonFromFragments();
1406 mParseModeStack.pop();
1408 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1410 mExceptionText = mStringCash;
1411 mParseModeStack.pop();
1414 if ( !mGeometryString.empty() )
1416 mGeometryString.append(
"</", 2 );
1417 mGeometryString.append( pszLocalName, localNameLen );
1418 mGeometryString.append(
">", 1 );
1423void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1426 if ( mParseModeStack.isEmpty() )
1431 if ( !mGeometryString.empty() )
1433 mGeometryString.append( chars, len );
1436 const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1437 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1438 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1439 parseMode == QgsGmlStreamingParser::Coordinate ||
1440 parseMode == QgsGmlStreamingParser::PosList ||
1441 parseMode == QgsGmlStreamingParser::LowerCorner ||
1442 parseMode == QgsGmlStreamingParser::UpperCorner ||
1443 parseMode == QgsGmlStreamingParser::ExceptionText )
1445 mStringCash.append( QString::fromUtf8( chars, len ) );
1449void QgsGmlStreamingParser::addStringContentToJson()
1451 const QString s( mStringCash.trimmed() );
1454 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1455 auto textIter = jsonParent.find(
"_text" );
1456 if ( textIter != jsonParent.end() )
1458 if ( textIter->type() != json::value_t::array )
1460 auto array = json::array();
1461 array.emplace_back( std::move( *textIter ) );
1464 textIter->emplace_back( jsonFromString( s ) );
1468 jsonParent.emplace(
"_text", jsonFromString( s ) );
1471 mStringCash.clear();
1474void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1477 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1478 bool conversionOk =
true;
1479 if ( att_it != mThematicAttributes.constEnd() )
1482 switch ( att_it.value().second.type() )
1484 case QVariant::Double:
1485 var = QVariant( value.toDouble( &conversionOk ) );
1488 var = QVariant( value.toInt( &conversionOk ) );
1490 case QVariant::LongLong:
1491 var = QVariant( value.toLongLong( &conversionOk ) );
1493 case QVariant::DateTime:
1494 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1497 var = QVariant( value );
1500 if ( ! conversionOk )
1504 Q_ASSERT( mCurrentFeature );
1505 mCurrentFeature->
setAttribute( att_it.value().first, var );
1509int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1514 if ( strcmp( attr[i],
"srsName" ) == 0 )
1516 const QString
srsName( attr[i + 1] );
1528 const int eNr = code.toInt( &conversionOk );
1529 if ( !conversionOk )
1542 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1553QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1558 if ( attributeName.compare( attr[i] ) == 0 )
1560 return QString::fromUtf8( attr[i + 1] );
1567bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1569 QList<QgsPointXY> points;
1570 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1575 if ( points.size() < 2 )
1580 r.
set( points[0], points[1] );
1585int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const
1588 const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1589 QStringList tuples_coordinates;
1591 bool conversionSuccess;
1593 QStringList::const_iterator tupleIterator;
1594 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1596 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1597 if ( tuples_coordinates.size() < 2 )
1601 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1602 if ( !conversionSuccess )
1606 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1607 if ( !conversionSuccess )
1616int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const
1619 const QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1621 if ( coordinates.size() % dimension != 0 )
1623 QgsDebugError( QStringLiteral(
"Wrong number of coordinates" ) );
1626 const int ncoor = coordinates.size() / dimension;
1627 for (
int i = 0; i < ncoor; i++ )
1629 bool conversionSuccess;
1630 const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1631 if ( !conversionSuccess )
1635 const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1636 if ( !conversionSuccess )
1645int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const
1647 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1649 return pointsFromCoordinateString( points, coordString );
1651 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1653 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1660 const int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1661 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1669int QgsGmlStreamingParser::getLineWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const
1671 const int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1672 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1678 QList<QgsPointXY>::const_iterator iter;
1679 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1681 fillPtr << iter->x() << iter->y();
1687int QgsGmlStreamingParser::getRingWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const
1689 const int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1690 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1694 fillPtr << ringCoordinates.size();
1696 QList<QgsPointXY>::const_iterator iter;
1697 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1699 fillPtr << iter->x() << iter->y();
1705int QgsGmlStreamingParser::createMultiLineFromFragments()
1707 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1708 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1715 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1716 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1718 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1719 wkbPtr += wkbIt->
size();
1723 mCurrentWKBFragments.clear();
1728int QgsGmlStreamingParser::createMultiPointFromFragments()
1730 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1731 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1736 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1737 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1739 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1740 wkbPtr += wkbIt->
size();
1744 mCurrentWKBFragments.clear();
1750int QgsGmlStreamingParser::createPolygonFromFragments()
1752 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1753 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1758 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1759 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1761 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1762 wkbPtr += wkbIt->
size();
1766 mCurrentWKBFragments.clear();
1771int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1774 size += 1 + 2 *
sizeof( int );
1775 size += totalWKBFragmentSize();
1776 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1778 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1784 QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
1786 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1791 QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
1792 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1794 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1795 wkbPtr += innerWkbIt->
size();
1796 delete[] *innerWkbIt;
1800 mCurrentWKBFragments.clear();
1805int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1808 const auto constMCurrentWKBFragments = mCurrentWKBFragments;
1809 for (
const QList<QgsWkbPtr> &list : constMCurrentWKBFragments )
1811 const auto constList = list;
1820void QgsGmlStreamingParser::createParser(
const QByteArray &encoding )
1822 Q_ASSERT( !mParser );
1824 mParser = XML_ParserCreateNS( encoding.isEmpty() ?
nullptr : encoding.data(), NS_SEPARATOR );
1825 XML_SetUserData( mParser,
this );
1826 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
1827 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
The Qgis class provides global constants for use throughout the application.
@ Critical
Critical/error message.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ MultiPolygon
MultiPolygon.
@ MultiLineString
MultiLineString.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static endian_t endian()
Returns whether this machine uses big or little endian.
This class represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool hasAxisInverted() const
Returns whether the axis order is inverted for the CRS compared to the order east/north (longitude/la...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
void setValid(bool validity)
Sets the validity of the feature.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Container of fields for a vector layer.
int size() 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.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
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.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
QPair< QgsFeature *, QString > QgsGmlFeaturePtrGmlIdPair
void setFieldsXPath(const QMap< QString, QPair< QString, bool > > &fieldNameToSrcLayerNameFieldNameMap, const QMap< QString, QString > &namespacePrefixToURIMap)
Define the XPath of the attributes and whether they are made of nested content.
int numberReturned() const
Returns WFS 2.0 "numberReturned" or WFS 1.1 "numberOfFeatures" attribute, or -1 if invalid/not found.
Qgis::WkbType wkbType() const
Returns the geometry type.
AxisOrientationLogic
Axis orientation logic.
@ Honour_EPSG
Honour EPSG axis order.
@ Honour_EPSG_if_urn
Honour EPSG axis order only if srsName is of the form urn:ogc:def:crs:EPSG:
int numberMatched() const
Returns WFS 2.0 "numberMatched" attribute, or -1 if invalid/not found.
QgsGmlStreamingParser(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields, AxisOrientationLogic axisOrientationLogic=Honour_EPSG_if_urn, bool invertAxisOrientation=false)
Constructor.
bool processData(const QByteArray &data, bool atEnd, QString &errorMsg)
Process a new chunk of data.
int getEPSGCode() const
Returns the EPSG code, or 0 if unknown.
QVector< QgsGmlFeaturePtrGmlIdPair > getAndStealReadyFeatures()
Returns the list of features that have been completely parsed.
QString srsName() const
Returns the value of the srsName attribute.
void totalStepsUpdate(int totalSteps)
void dataReadProgress(int progress)
QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)
QgsCoordinateReferenceSystem crs() const
Returns features spatial reference system.
int getFeatures(const QString &uri, Qgis::WkbType *wkbType, QgsRectangle *extent=nullptr, const QString &userName=QString(), const QString &password=QString(), const QString &authcfg=QString())
Does the Http GET request to the wfs server.
void dataProgressAndSteps(int progress, int totalSteps)
Also emit signal with progress and totalSteps together (this is better for the status message)
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
@ OGC_HTTP_URI
e.g. urn:x-ogc:def:crs:EPSG::4326
@ X_OGC_URN
e.g. urn:ogc:def:crs:EPSG::4326
@ OGC_URN
e.g. http://www.opengis.net/gml/srs/epsg.xml#4326 (called "OGC HTTP URL" in GeoServer WFS configurati...
static CRSFlavor parseCrsName(const QString &crsName, QString &authority, QString &code)
Parse a CRS name in one of the flavors of OGC services, and decompose it as authority and code.
A class to represent a 2D point.
A rectangle specified with double values.
void setYMinimum(double y)
Set the minimum y value.
void setXMinimum(double x)
Set the minimum x value.
bool isNull() const
Test if the rectangle is null (holding no spatial information).
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
void setYMaximum(double y)
Set the maximum y value.
void setXMaximum(double x)
Set the maximum x value.
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
bool isEmpty() const
Returns true if the rectangle has no area.
void setNull()
Mark a rectangle as being null (holding no spatial information).
std::unique_ptr< std::remove_pointer< OGRGeometryH >::type, OGRGeometryDeleter > ogr_geometry_unique_ptr
Scoped OGR geometry.
#define LOCALNAME_EQUALS(string_constant)
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
#define QgsSetRequestInitiatorClass(request, _class)
const QgsCoordinateReferenceSystem & crs