16#include "moc_qgsgml.cpp"
31#include <QNetworkRequest>
32#include <QNetworkReply>
33#include <QProgressDialog>
38#include <QRegularExpression>
44using namespace nlohmann;
46#ifndef NS_SEPARATOR_DEFINED
47#define NS_SEPARATOR_DEFINED
48static const char NS_SEPARATOR =
'?';
51static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
56 const QString &geometryAttribute,
58 : mParser(
typeName, geometryAttribute, fields )
62 const int index = mTypeName.indexOf(
':' );
63 if ( index != -1 && index < mTypeName.length() )
65 mTypeName = mTypeName.mid( index + 1 );
74 QNetworkRequest request( uri );
77 if ( !authcfg.isEmpty() )
82 tr(
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
89 else if ( !userName.isNull() || !password.isNull() )
91 request.setRawHeader(
"Authorization",
"Basic " + QStringLiteral(
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
95 if ( !authcfg.isEmpty() )
101 tr(
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
109 connect( reply, &QNetworkReply::finished,
this, &QgsGml::setFinished );
110 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsGml::handleProgressEvent );
113 QProgressDialog *progressDialog =
nullptr;
114 QWidget *mainWindow =
nullptr;
115 const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
116 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
118 if ( ( *it )->objectName() == QLatin1String(
"QgisApp" ) )
126 progressDialog =
new QProgressDialog( tr(
"Loading GML data\n%1" ).arg( mTypeName ), tr(
"Abort" ), 0, 0, mainWindow );
127 progressDialog->setWindowModality( Qt::ApplicationModal );
130 connect( progressDialog, &QProgressDialog::canceled,
this, &QgsGml::setFinished );
131 progressDialog->show();
141 const QByteArray readData = reply->readAll();
142 if ( !readData.isEmpty() )
145 if ( !mParser.
processData( readData, atEnd, errorMsg ) )
149 QCoreApplication::processEvents();
152 fillMapsFromParser();
154 const QNetworkReply::NetworkError replyError = reply->error();
155 const QString replyErrorString = reply->errorString();
158 delete progressDialog;
163 tr(
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
177 calculateExtentFromFeatures();
192 if ( !mParser.
processData( data,
true , errorMsg ) )
195 fillMapsFromParser();
205void QgsGml::fillMapsFromParser()
208 const auto constFeatures = features;
212 const QString &gmlId = featPair.second;
213 mFeatures.insert( feat->
id(), feat );
214 if ( !gmlId.isEmpty() )
216 mIdMap.insert( feat->
id(), gmlId );
221void QgsGml::setFinished()
226void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
228 if ( totalSteps < 0 )
238void QgsGml::calculateExtentFromFeatures()
240 if ( mFeatures.empty() )
247 bool bboxInitialized =
false;
249 for (
int i = 0; i < mFeatures.size(); ++i )
251 currentFeature = mFeatures[i];
252 if ( !currentFeature )
256 currentGeometry = currentFeature->
geometry();
257 if ( !currentGeometry.
isNull() )
259 if ( !bboxInitialized )
262 bboxInitialized =
true;
287 const QString &geometryAttribute,
290 bool invertAxisOrientation )
292 , mTypeNameBA( mTypeName.toUtf8() )
293 , mTypeNamePtr( mTypeNameBA.constData() )
294 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
295 , mWkbType(
Qgis::WkbType::Unknown )
296 , mGeometryAttribute( geometryAttribute )
297 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
298 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
299 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
301 , mIsException( false )
302 , mTruncatedResponse( false )
304 , mFeatureTupleDepth( 0 )
306 , mCurrentWKB( nullptr, 0 )
307 , mBoundedByNullFound( false )
309 , mCoorMode( Coordinate )
311 , mAxisOrientationLogic( axisOrientationLogic )
312 , mInvertAxisOrientationRequest( invertAxisOrientation )
313 , mInvertAxisOrientation( invertAxisOrientation )
314 , mNumberReturned( -1 )
315 , mNumberMatched( -1 )
316 , mFoundUnhandledGeometryElement( false )
318 mThematicAttributes.clear();
319 for (
int i = 0; i < fields.
size(); i++ )
321 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
326 const int index = mTypeName.indexOf(
':' );
327 if ( index != -1 && index < mTypeName.length() )
329 mTypeName = mTypeName.mid( index + 1 );
330 mTypeNameBA = mTypeName.toUtf8();
331 mTypeNamePtr = mTypeNameBA.constData();
332 mTypeNameUTF8Len = strlen( mTypeNamePtr );
338static QString stripNS(
const QString &
string )
340 const int index =
string.indexOf(
':' );
341 if ( index != -1 && index <
string.length() )
343 return string.mid( index + 1 );
350 const QMap< QString, QPair<QString, QString> > &fieldNameToSrcLayerNameFieldNameMap,
352 bool invertAxisOrientation )
353 : mLayerProperties( layerProperties )
354 , mTypeNameUTF8Len( 0 )
355 , mWkbType(
Qgis::WkbType::Unknown )
356 , mGeometryAttributeUTF8Len( 0 )
358 , mIsException( false )
359 , mTruncatedResponse( false )
361 , mFeatureTupleDepth( 0 )
363 , mCurrentWKB( nullptr, 0 )
364 , mBoundedByNullFound( false )
366 , mCoorMode( Coordinate )
368 , mAxisOrientationLogic( axisOrientationLogic )
369 , mInvertAxisOrientationRequest( invertAxisOrientation )
370 , mInvertAxisOrientation( invertAxisOrientation )
371 , mNumberReturned( -1 )
372 , mNumberMatched( -1 )
373 , mFoundUnhandledGeometryElement( false )
375 mThematicAttributes.clear();
376 for (
int i = 0; i < fields.
size(); i++ )
378 const QMap< QString, QPair<QString, QString> >::const_iterator att_it = fieldNameToSrcLayerNameFieldNameMap.constFind( fields.
at( i ).
name() );
379 if ( att_it != fieldNameToSrcLayerNameFieldNameMap.constEnd() )
381 if ( mLayerProperties.size() == 1 )
382 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
384 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
387 bool alreadyFoundGeometry =
false;
388 for (
int i = 0; i < mLayerProperties.size(); i++ )
391 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
393 if ( alreadyFoundGeometry )
395 QgsDebugMsgLevel( QStringLiteral(
"Will ignore geometry field %1 from typename %2" ).
396 arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ), 2 );
397 mLayerProperties[i].mGeometryAttribute.clear();
399 alreadyFoundGeometry =
true;
401 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
404 if ( mLayerProperties.size() == 1 )
406 mTypeName = mLayerProperties[0].mName;
407 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
408 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
409 mGeometryAttributePtr = mGeometryAttributeBA.constData();
410 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
411 const int index = mTypeName.indexOf(
':' );
412 if ( index != -1 && index < mTypeName.length() )
414 mTypeName = mTypeName.mid( index + 1 );
416 mTypeNameBA = mTypeName.toUtf8();
417 mTypeNamePtr = mTypeNameBA.constData();
418 mTypeNameUTF8Len = strlen( mTypeNamePtr );
428 const QMap<QString, QPair<QString, bool>> &fieldNameToXPathMapAndIsNestedContent,
429 const QMap<QString, QString> &mapNamespacePrefixToURI )
431 for (
auto iter = fieldNameToXPathMapAndIsNestedContent.constBegin(); iter != fieldNameToXPathMapAndIsNestedContent.constEnd(); ++iter )
433 mMapXPathToFieldNameAndIsNestedContent[iter.value().first] = QPair<QString, bool>( iter.key(), iter.value().second );
435 for (
auto iter = mapNamespacePrefixToURI.constBegin(); iter != mapNamespacePrefixToURI.constEnd(); ++iter )
436 mMapNamespaceURIToNamespacePrefix[iter.value()] = iter.key();
442 XML_ParserFree( mParser );
445 const auto constMFeatureList = mFeatureList;
448 delete featPair.first;
451 delete mCurrentFeature;
467 QByteArray data = pdata;
472 QString strData = mCodec->toUnicode( pdata );
473 data = strData.toUtf8();
476 if ( XML_Parse( mParser, data, data.size(), atEnd ) == XML_STATUS_ERROR )
478 const XML_Error errorCode = XML_GetErrorCode( mParser );
479 if ( !mCodec && errorCode == XML_ERROR_UNKNOWN_ENCODING )
483 const thread_local QRegularExpression reEncoding( QStringLiteral(
"<?xml.*encoding=['\"]([^'\"]*)['\"].*?>" ),
484 QRegularExpression::CaseInsensitiveOption );
485 QRegularExpressionMatch match = reEncoding.match( pdata );
486 const QString encoding = match.hasMatch() ? match.captured( 1 ) : QString();
487 mCodec = !encoding.isEmpty() ? QTextCodec::codecForName( encoding.toLatin1() ) :
nullptr;
491 XML_ParserFree( mParser );
493 createParser( QByteArrayLiteral(
"UTF-8" ) );
499 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" )
500 .arg( XML_ErrorString( errorCode ) )
501 .arg( XML_GetCurrentLineNumber( mParser ) )
502 .arg( XML_GetCurrentColumnNumber( mParser ) );
512 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
513 mFeatureList.clear();
521static json jsonFromString(
const QString &s )
526 if ( s.indexOf(
'.' ) >= 0 || s.indexOf(
'e' ) >= 0 )
528 const auto doubleVal = s.toDouble( &conversionOk );
531 return json( doubleVal );
536 else if ( !s.isEmpty() && s[0] !=
'0' )
538 const auto longlongVal = s.toLongLong( &conversionOk );
541 return json( longlongVal );
545 return json( s.toStdString() );
548#define LOCALNAME_EQUALS(string_constant) \
549 ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 )
548#define LOCALNAME_EQUALS(string_constant) \ …
551void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
553 const int elLen =
static_cast<int>( strlen( el ) );
554 const char *pszSep = strchr( el, NS_SEPARATOR );
555 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
556 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
557 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
558 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
562 if ( !mGMLNameSpaceURIPtr && pszSep )
576 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
579 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
580 parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
582 mGeometryString.append(
"<", 1 );
583 mGeometryString.append( pszLocalName, localNameLen );
584 mGeometryString.append(
" ", 1 );
585 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
587 const size_t nAttrLen = strlen( attrIter[0] );
590 if ( nAttrLen > GML32_NAMESPACE_LEN &&
591 attrIter[0][GML32_NAMESPACE_LEN] ==
'?' &&
594 mGeometryString.append(
"gml:" );
595 mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
597 else if ( nAttrLen > GML_NAMESPACE_LEN &&
598 attrIter[0][GML_NAMESPACE_LEN] ==
'?' &&
599 memcmp( attrIter[0],
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
601 mGeometryString.append(
"gml:" );
602 mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
606 mGeometryString.append( attrIter[0] );
608 mGeometryString.append(
"=\"", 2 );
609 mGeometryString.append( attrIter[1] );
610 mGeometryString.append(
"\" ", 2 );
613 mGeometryString.append(
">", 1 );
616 if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
618 mParseModeStack.push( Coordinate );
619 mCoorMode = QgsGmlStreamingParser::Coordinate;
621 mCoordinateSeparator = readAttribute( QStringLiteral(
"cs" ), attr );
622 if ( mCoordinateSeparator.isEmpty() )
624 mCoordinateSeparator =
',';
626 mTupleSeparator = readAttribute( QStringLiteral(
"ts" ), attr );
627 if ( mTupleSeparator.isEmpty() )
629 mTupleSeparator =
' ';
632 else if ( !mAttributeValIsNested && isGMLNS &&
635 mParseModeStack.push( QgsGmlStreamingParser::PosList );
636 if ( mCoorMode == QgsGmlStreamingParser::PosList )
638 if ( !mStringCash.isEmpty() )
640 mStringCash.append( QLatin1Char(
' ' ) );
647 mCoorMode = QgsGmlStreamingParser::PosList;
648 if ( elDimension == 0 )
650 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
652 const int dimension = srsDimension.toInt( &ok );
655 elDimension = dimension;
659 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
661 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
662 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
664 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
665 mFoundUnhandledGeometryElement =
false;
666 mGeometryString.clear();
670 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
672 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
674 mBoundedByNullFound =
false;
676 else if ( parseMode == BoundingBox &&
679 mParseModeStack.push( QgsGmlStreamingParser::Null );
680 mBoundedByNullFound =
true;
682 else if ( parseMode == BoundingBox &&
686 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
688 else if ( parseMode == Envelope &&
691 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
694 else if ( parseMode == Envelope &&
697 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
700 else if ( parseMode == None && !mTypeNamePtr &&
703 Q_ASSERT( !mCurrentFeature );
704 mCurrentFeature =
new QgsFeature( mFeatureCount );
706 const QgsAttributes attributes( mThematicAttributes.size() );
708 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
709 mCurrentFeatureId.clear();
711 else if ( parseMode == Tuple )
713 const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
714 const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
715 if ( iter != mMapTypeNameToProperties.constEnd() )
717 mFeatureTupleDepth = mParseDepth;
718 mCurrentTypename = currentTypename;
719 mGeometryAttribute.clear();
720 if ( mCurrentWKB.size() == 0 )
722 mGeometryAttribute = iter.value().mGeometryAttribute;
724 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
725 mGeometryAttributePtr = mGeometryAttributeBA.constData();
726 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
727 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
729 if ( mGMLNameSpaceURI.isEmpty() )
731 id = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
739 id = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
748 id = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
749 if ( !mCurrentFeatureId.isEmpty() )
750 mCurrentFeatureId +=
'|';
751 mCurrentFeatureId += id;
754 else if ( parseMode == None &&
755 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
757 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
759 Q_ASSERT( !mCurrentFeature );
760 mCurrentFeature =
new QgsFeature( mFeatureCount );
762 const QgsAttributes attributes( mThematicAttributes.size() );
764 mParseModeStack.push( QgsGmlStreamingParser::Feature );
765 mCurrentXPathWithinFeature.clear();
766 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
767 if ( mCurrentFeatureId.isEmpty() )
772 if ( mGMLNameSpaceURI.isEmpty() )
774 mCurrentFeatureId = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
775 if ( !mCurrentFeatureId.isEmpty() )
782 mCurrentFeatureId = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
783 if ( !mCurrentFeatureId.isEmpty() )
791 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
795 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
799 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
803 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"LineString" ) )
807 else if ( !mAttributeValIsNested && isGMLNS &&
808 localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
811 mCurrentWKBFragments.push_back( QList<QByteArray>() );
813 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
816 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
818 mCurrentWKBFragments.push_back( QList<QByteArray>() );
823 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
825 mCurrentWKBFragments.push_back( QList<QByteArray>() );
830 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
832 else if ( parseMode == FeatureTuple )
834 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
835 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
837 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
838 mAttributeName = mCurrentTypename +
'|' + localName;
842 else if ( parseMode == Feature )
844 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
845 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
847 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
848 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
849 if ( !mCurrentXPathWithinFeature.isEmpty() )
850 mCurrentXPathWithinFeature.append(
'/' );
851 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
853 mCurrentXPathWithinFeature.append( *nsIter );
854 mCurrentXPathWithinFeature.append(
':' );
856 mCurrentXPathWithinFeature.append( localName );
857 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( mCurrentXPathWithinFeature );
858 mAttributeValIsNested =
false;
859 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
861 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
862 mAttributeDepth = mParseDepth;
863 mAttributeName = xpathIter->first;
864 mAttributeValIsNested = xpathIter->second;
865 if ( mAttributeValIsNested )
867 mAttributeJson = json::object();
868 mAttributeJsonCurrentStack.clear();
869 mAttributeJsonCurrentStack.push( &mAttributeJson );
874 else if ( mThematicAttributes.contains( localName ) )
876 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
877 mAttributeDepth = mParseDepth;
878 mAttributeName = localName;
885 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
887 const QString name = readAttribute( QStringLiteral(
"name" ), attr );
888 if ( mThematicAttributes.contains( name ) )
890 const QString value = readAttribute( QStringLiteral(
"value" ), attr );
891 setAttribute( name, value );
896 else if ( parseMode == Attribute && mAttributeValIsNested )
898 const std::string localName( pszLocalName, localNameLen );
899 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
900 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
901 const std::string nodeName = nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() ? ( *nsIter ).toStdString() +
':' + localName : localName;
903 addStringContentToJson();
905 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
906 auto iter = jsonParent.find( nodeName );
907 if ( iter != jsonParent.end() )
909 if ( iter->type() != json::value_t::array )
911 auto array = json::array();
912 array.emplace_back( std::move( *iter ) );
915 iter->push_back( json::object() );
916 mAttributeJsonCurrentStack.push( &( iter->back() ) );
920 auto res = jsonParent.emplace( nodeName, json::object() );
924 nlohmann::json *ptr = &( *( res.first ) );
926 mAttributeJsonCurrentStack.push( ptr );
931 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
933 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
937 mNumberReturned = -1;
939 const QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
947 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
952 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
957 mTruncatedResponse =
true;
959 else if ( !mGeometryString.empty() &&
975 mFoundUnhandledGeometryElement =
true;
979 if ( !mParseModeStack.isEmpty() &&
980 ( mParseModeStack.back() == Feature ||
981 mParseModeStack.back() == Attribute ) &&
982 !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
984 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
986 const char *questionMark = strchr( attrIter[0],
'?' );
990 const QString nsURI( QString::fromUtf8( attrIter[0],
static_cast<int>( questionMark - attrIter[0] ) ) );
991 const QString localName( QString::fromUtf8( questionMark + 1 ) );
992 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
993 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
995 key.append( *nsIter );
998 key.append( localName );
1002 const QString localName( QString::fromUtf8( attrIter[0] ) );
1003 key.append( localName );
1006 if ( mAttributeValIsNested && mParseModeStack.back() == Attribute )
1008 mAttributeJsonCurrentStack.top()->emplace(
1010 jsonFromString( QString::fromUtf8( attrIter[1] ) ) );
1014 QString xpath( mCurrentXPathWithinFeature );
1015 if ( !xpath.isEmpty() )
1016 xpath.append(
'/' );
1017 xpath.append( key );
1018 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( xpath );
1019 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
1021 setAttribute( xpathIter->first, QString::fromUtf8( attrIter[1] ) );
1027 if ( !mGeometryString.empty() )
1030 if ( elDimension == 0 && isGeom )
1034 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
1036 const int dimension = srsDimension.toInt( &ok );
1039 elDimension = dimension;
1043 if ( elDimension != 0 || mDimensionStack.isEmpty() )
1045 mDimensionStack.push( elDimension );
1049 mDimensionStack.push( mDimensionStack.back() );
1052 if ( mEpsg == 0 && isGeom )
1054 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
1056 QgsDebugError( QStringLiteral(
"error, could not get epsg id" ) );
1067void QgsGmlStreamingParser::endElement(
const XML_Char *el )
1071 const int elLen =
static_cast<int>( strlen( el ) );
1072 const char *pszSep = strchr( el, NS_SEPARATOR );
1073 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
1074 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
1075 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
1076 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
1078 const int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
1080 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
1082 if ( parseMode == Feature || ( parseMode == Attribute && mAttributeDepth == mParseDepth ) )
1084 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
1086 const auto nPos = mCurrentXPathWithinFeature.lastIndexOf(
'/' );
1088 mCurrentXPathWithinFeature.clear();
1090 mCurrentXPathWithinFeature.resize( nPos );
1094 if ( parseMode == Attribute && mAttributeValIsNested )
1096 if ( !mStringCash.isEmpty() )
1098 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1099 if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
1101 jsonParent = jsonFromString( mStringCash );
1103 else if ( jsonParent.type() == json::value_t::object )
1105 addStringContentToJson();
1107 mStringCash.clear();
1110 mAttributeJsonCurrentStack.pop();
1113 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
1115 mParseModeStack.pop();
1117 else if ( parseMode == PosList && isGMLNS &&
1120 mDimension = lastDimension;
1121 mParseModeStack.pop();
1123 else if ( parseMode == AttributeTuple &&
1124 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
1126 mParseModeStack.pop();
1128 setAttribute( mAttributeName, mStringCash );
1130 else if ( parseMode == Attribute && mAttributeDepth == mParseDepth )
1132 mParseModeStack.pop();
1135 if ( mAttributeValIsNested )
1137 mAttributeValIsNested =
false;
1138 auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
1139 if ( iter == mMapFieldNameToJSONContent.end() )
1141 mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
1145 QString &str = iter.value();
1146 if ( str[0] ==
'[' && str.back() ==
']' )
1152 str.insert( 0,
'[' );
1155 str.append( QString::fromStdString( mAttributeJson.dump() ) );
1161 setAttribute( mAttributeName, mStringCash );
1164 else if ( parseMode == Geometry &&
1165 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
1166 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1168 mParseModeStack.pop();
1169 if ( mFoundUnhandledGeometryElement )
1175 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
1176 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
1177 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
1179 g.
fromWkb( pabyBuffer, wkbSize );
1180 if ( mInvertAxisOrientation )
1182 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1184 Q_ASSERT( mCurrentFeature );
1188 mGeometryString.clear();
1190 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
1193 if ( mCurrentExtent.
isNull() &&
1194 !mBoundedByNullFound &&
1195 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
1197 QgsDebugError( QStringLiteral(
"creation of bounding box failed" ) );
1199 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
1200 !mCurrentFeature && mFeatureCount == 0 )
1202 mLayerExtent = mCurrentExtent;
1206 mParseModeStack.pop();
1210 mParseModeStack.pop();
1212 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
1214 mParseModeStack.pop();
1216 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
1218 QList<QgsPointXY> points;
1219 pointsFromPosListString( points, mStringCash, 2 );
1220 if ( points.size() == 1 )
1225 mParseModeStack.pop();
1227 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
1229 QList<QgsPointXY> points;
1230 pointsFromPosListString( points, mStringCash, 2 );
1231 if ( points.size() == 1 )
1236 mParseModeStack.pop();
1238 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
1240 mParseModeStack.pop();
1241 mFeatureTupleDepth = 0;
1243 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
1245 ( parseMode == Feature &&
1246 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
1247 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
1249 Q_ASSERT( mCurrentFeature );
1252 if ( mCurrentWKB.size() > 0 )
1257 mCurrentWKB = QByteArray();
1259 else if ( !mCurrentExtent.
isEmpty() )
1266 for (
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
1268 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
1269 const int attrIndex = att_it.value().first;
1270 mCurrentFeature->
setAttribute( attrIndex, iter.value() );
1272 mMapFieldNameToJSONContent.clear();
1276 mCurrentFeature =
nullptr;
1278 mParseModeStack.pop();
1280 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
1282 QList<QgsPointXY> pointList;
1283 if ( pointsFromString( pointList, mStringCash ) != 0 )
1287 mStringCash.clear();
1289 if ( pointList.isEmpty() )
1292 if ( parseMode == QgsGmlStreamingParser::Geometry )
1295 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
1308 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
1312 if ( !mCurrentWKBFragments.isEmpty() )
1314 mCurrentWKBFragments.last().push_back( wkbPtr );
1322 else if ( !mAttributeValIsNested &&
1327 QList<QgsPointXY> pointList;
1328 if ( pointsFromString( pointList, mStringCash ) != 0 )
1332 mStringCash.clear();
1334 if ( parseMode == QgsGmlStreamingParser::Geometry )
1336 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
1349 if ( getLineWKB( wkbPtr, pointList ) != 0 )
1353 if ( !mCurrentWKBFragments.isEmpty() )
1355 mCurrentWKBFragments.last().push_back( wkbPtr );
1363 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1366 QList<QgsPointXY> pointList;
1367 if ( pointsFromString( pointList, mStringCash ) != 0 )
1371 mStringCash.clear();
1374 if ( getRingWKB( wkbPtr, pointList ) != 0 )
1379 if ( !mCurrentWKBFragments.isEmpty() )
1381 mCurrentWKBFragments.last().push_back( wkbPtr );
1388 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1396 if ( parseMode == Geometry )
1398 createPolygonFromFragments();
1401 else if ( parseMode == MultiPoint && isGMLNS &&
1405 mParseModeStack.pop();
1406 createMultiPointFromFragments();
1408 else if ( parseMode == MultiLine && isGMLNS &&
1412 mParseModeStack.pop();
1413 createMultiLineFromFragments();
1415 else if ( parseMode == MultiPolygon && isGMLNS &&
1419 mParseModeStack.pop();
1420 createMultiPolygonFromFragments();
1424 mParseModeStack.pop();
1426 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1428 mExceptionText = mStringCash;
1429 mParseModeStack.pop();
1432 if ( !mGeometryString.empty() )
1434 mGeometryString.append(
"</", 2 );
1435 mGeometryString.append( pszLocalName, localNameLen );
1436 mGeometryString.append(
">", 1 );
1441void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1444 if ( mParseModeStack.isEmpty() )
1449 if ( !mGeometryString.empty() )
1451 mGeometryString.append( chars, len );
1454 const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1455 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1456 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1457 parseMode == QgsGmlStreamingParser::Coordinate ||
1458 parseMode == QgsGmlStreamingParser::PosList ||
1459 parseMode == QgsGmlStreamingParser::LowerCorner ||
1460 parseMode == QgsGmlStreamingParser::UpperCorner ||
1461 parseMode == QgsGmlStreamingParser::ExceptionText )
1463 mStringCash.append( QString::fromUtf8( chars, len ) );
1467void QgsGmlStreamingParser::addStringContentToJson()
1469 const QString s( mStringCash.trimmed() );
1472 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1473 auto textIter = jsonParent.find(
"_text" );
1474 if ( textIter != jsonParent.end() )
1476 if ( textIter->type() != json::value_t::array )
1478 auto array = json::array();
1479 array.emplace_back( std::move( *textIter ) );
1482 textIter->emplace_back( jsonFromString( s ) );
1486 jsonParent.emplace(
"_text", jsonFromString( s ) );
1489 mStringCash.clear();
1492void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1495 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1496 bool conversionOk =
true;
1497 if ( att_it != mThematicAttributes.constEnd() )
1500 switch ( att_it.value().second.type() )
1502 case QMetaType::Type::Double:
1503 var = QVariant( value.toDouble( &conversionOk ) );
1505 case QMetaType::Type::Int:
1506 var = QVariant( value.toInt( &conversionOk ) );
1508 case QMetaType::Type::LongLong:
1509 var = QVariant( value.toLongLong( &conversionOk ) );
1511 case QMetaType::Type::QDateTime:
1512 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1515 var = QVariant( value );
1518 if ( ! conversionOk )
1522 Q_ASSERT( mCurrentFeature );
1523 mCurrentFeature->
setAttribute( att_it.value().first, var );
1527int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1532 if ( strcmp( attr[i],
"srsName" ) == 0 )
1534 const QString
srsName( attr[i + 1] );
1546 const int eNr = code.toInt( &conversionOk );
1547 if ( !conversionOk )
1560 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1571QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1576 if ( attributeName.compare( attr[i] ) == 0 )
1578 return QString::fromUtf8( attr[i + 1] );
1585bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1587 QList<QgsPointXY> points;
1588 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1593 if ( points.size() < 2 )
1598 r.
set( points[0], points[1] );
1603int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const
1606 const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1607 QStringList tuples_coordinates;
1609 bool conversionSuccess;
1611 QStringList::const_iterator tupleIterator;
1612 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1614 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1615 if ( tuples_coordinates.size() < 2 )
1619 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1620 if ( !conversionSuccess )
1624 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1625 if ( !conversionSuccess )
1634int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const
1637 const QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1639 if ( coordinates.size() % dimension != 0 )
1641 QgsDebugError( QStringLiteral(
"Wrong number of coordinates" ) );
1644 const int ncoor = coordinates.size() / dimension;
1645 for (
int i = 0; i < ncoor; i++ )
1647 bool conversionSuccess;
1648 const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1649 if ( !conversionSuccess )
1653 const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1654 if ( !conversionSuccess )
1663int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const
1665 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1667 return pointsFromCoordinateString( points, coordString );
1669 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1671 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1676int QgsGmlStreamingParser::getPointWKB( QByteArray &wkbPtr,
const QgsPointXY &point )
const
1678 const int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1679 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1687int QgsGmlStreamingParser::getLineWKB( QByteArray &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const
1689 const int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1690 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1696 QList<QgsPointXY>::const_iterator iter;
1697 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1699 fillPtr << iter->x() << iter->y();
1705int QgsGmlStreamingParser::getRingWKB( QByteArray &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const
1707 const int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1708 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1712 fillPtr << ringCoordinates.size();
1714 QList<QgsPointXY>::const_iterator iter;
1715 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1717 fillPtr << iter->x() << iter->y();
1723int QgsGmlStreamingParser::createMultiLineFromFragments()
1725 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1726 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1733 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1734 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1736 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1737 wkbPtr += wkbIt->size();
1740 mCurrentWKBFragments.clear();
1745int QgsGmlStreamingParser::createMultiPointFromFragments()
1747 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1748 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1753 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1754 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1756 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1757 wkbPtr += wkbIt->size();
1760 mCurrentWKBFragments.clear();
1766int QgsGmlStreamingParser::createPolygonFromFragments()
1768 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1769 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1774 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1775 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1777 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1778 wkbPtr += wkbIt->size();
1781 mCurrentWKBFragments.clear();
1786int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1789 size += 1 + 2 *
sizeof( int );
1790 size += totalWKBFragmentSize();
1791 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1793 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1799 auto outerWkbIt = mCurrentWKBFragments.constBegin();
1801 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1806 auto innerWkbIt = outerWkbIt->constBegin();
1807 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1809 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1810 wkbPtr += innerWkbIt->size();
1814 mCurrentWKBFragments.clear();
1819int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1822 for (
const QList<QByteArray> &list : std::as_const( mCurrentWKBFragments ) )
1824 for (
const QByteArray &i : list )
1832void QgsGmlStreamingParser::createParser(
const QByteArray &encoding )
1834 Q_ASSERT( !mParser );
1836 mParser = XML_ParserCreateNS( encoding.isEmpty() ?
nullptr : encoding.data(), NS_SEPARATOR );
1837 XML_SetUserData( mParser,
this );
1838 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
1839 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
Provides global constants and enumerations 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.
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...
Q_INVOKABLE 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)
Emitted when the total number of bytes to read changes.
void dataReadProgress(int progress)
Emitted when data reading progresses.
QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)
QgsCoordinateReferenceSystem crs() const
Returns the spatial reference system for features.
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)
Emitted when data reading progresses or the total number of bytes to read changes.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
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. http://www.opengis.net/def/crs/EPSG/0/4326.
@ X_OGC_URN
E.g. urn:x-ogc:def:crs:EPSG::4326.
@ UNKNOWN
Unknown/unhandled flavor.
@ OGC_URN
E.g. urn:ogc:def:crs:EPSG::4326.
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 rectangle specified with double values.
void setYMinimum(double y)
Set the minimum y value.
void setXMinimum(double x)
Set the minimum x value.
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.
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