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 )
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 mCoorMode = QgsGmlStreamingParser::PosList;
638 if ( elDimension == 0 )
640 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
642 const int dimension = srsDimension.toInt( &ok );
645 elDimension = dimension;
649 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
651 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
652 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
654 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
655 mFoundUnhandledGeometryElement =
false;
656 mGeometryString.clear();
659 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
661 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
663 mBoundedByNullFound =
false;
665 else if ( parseMode == BoundingBox &&
668 mParseModeStack.push( QgsGmlStreamingParser::Null );
669 mBoundedByNullFound =
true;
671 else if ( parseMode == BoundingBox &&
675 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
677 else if ( parseMode == Envelope &&
680 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
683 else if ( parseMode == Envelope &&
686 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
689 else if ( parseMode == None && !mTypeNamePtr &&
692 Q_ASSERT( !mCurrentFeature );
693 mCurrentFeature =
new QgsFeature( mFeatureCount );
695 const QgsAttributes attributes( mThematicAttributes.size() );
697 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
698 mCurrentFeatureId.clear();
700 else if ( parseMode == Tuple )
702 const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
703 const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
704 if ( iter != mMapTypeNameToProperties.constEnd() )
706 mFeatureTupleDepth = mParseDepth;
707 mCurrentTypename = currentTypename;
708 mGeometryAttribute.clear();
709 if ( mCurrentWKB.
size() == 0 )
711 mGeometryAttribute = iter.value().mGeometryAttribute;
713 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
714 mGeometryAttributePtr = mGeometryAttributeBA.constData();
715 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
716 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
718 if ( mGMLNameSpaceURI.isEmpty() )
720 id = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
728 id = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
737 id = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
738 if ( !mCurrentFeatureId.isEmpty() )
739 mCurrentFeatureId +=
'|';
740 mCurrentFeatureId += id;
743 else if ( parseMode == None &&
744 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
746 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
748 Q_ASSERT( !mCurrentFeature );
749 mCurrentFeature =
new QgsFeature( mFeatureCount );
751 const QgsAttributes attributes( mThematicAttributes.size() );
753 mParseModeStack.push( QgsGmlStreamingParser::Feature );
754 mCurrentXPathWithinFeature.clear();
755 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
756 if ( mCurrentFeatureId.isEmpty() )
761 if ( mGMLNameSpaceURI.isEmpty() )
763 mCurrentFeatureId = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
764 if ( !mCurrentFeatureId.isEmpty() )
771 mCurrentFeatureId = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
772 if ( !mCurrentFeatureId.isEmpty() )
780 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
784 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
788 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
792 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"LineString" ) )
796 else if ( !mAttributeValIsNested && isGMLNS &&
797 localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
800 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
802 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
805 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
807 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
812 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
814 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
819 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
821 else if ( parseMode == FeatureTuple )
823 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
824 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
826 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
827 mAttributeName = mCurrentTypename +
'|' + localName;
831 else if ( parseMode == Feature )
833 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
834 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
836 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
837 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
838 if ( !mCurrentXPathWithinFeature.isEmpty() )
839 mCurrentXPathWithinFeature.append(
'/' );
840 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
842 mCurrentXPathWithinFeature.append( *nsIter );
843 mCurrentXPathWithinFeature.append(
':' );
845 mCurrentXPathWithinFeature.append( localName );
846 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( mCurrentXPathWithinFeature );
847 mAttributeValIsNested =
false;
848 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
850 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
851 mAttributeDepth = mParseDepth;
852 mAttributeName = xpathIter->first;
853 mAttributeValIsNested = xpathIter->second;
854 if ( mAttributeValIsNested )
856 mAttributeJson = json::object();
857 mAttributeJsonCurrentStack.clear();
858 mAttributeJsonCurrentStack.push( &mAttributeJson );
863 else if ( mThematicAttributes.contains( localName ) )
865 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
866 mAttributeDepth = mParseDepth;
867 mAttributeName = localName;
874 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
876 const QString name = readAttribute( QStringLiteral(
"name" ), attr );
877 if ( mThematicAttributes.contains( name ) )
879 const QString value = readAttribute( QStringLiteral(
"value" ), attr );
880 setAttribute( name, value );
885 else if ( parseMode == Attribute && mAttributeValIsNested )
887 const std::string localName( pszLocalName, localNameLen );
888 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
889 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
890 const std::string nodeName = nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() ? ( *nsIter ).toStdString() +
':' + localName : localName;
892 addStringContentToJson();
894 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
895 auto iter = jsonParent.find( nodeName );
896 if ( iter != jsonParent.end() )
898 if ( iter->type() != json::value_t::array )
900 auto array = json::array();
901 array.emplace_back( std::move( *iter ) );
904 iter->push_back( json::object() );
905 mAttributeJsonCurrentStack.push( &( iter->back() ) );
909 auto res = jsonParent.emplace( nodeName, json::object() );
913 nlohmann::json *ptr = &( *( res.first ) );
915 mAttributeJsonCurrentStack.push( ptr );
920 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
922 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
926 mNumberReturned = -1;
928 const QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
936 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
941 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
946 mTruncatedResponse =
true;
948 else if ( !mGeometryString.empty() &&
964 mFoundUnhandledGeometryElement =
true;
968 if ( !mParseModeStack.isEmpty() &&
969 ( mParseModeStack.back() == Feature ||
970 mParseModeStack.back() == Attribute ) &&
971 !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
973 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
975 const char *questionMark = strchr( attrIter[0],
'?' );
979 const QString nsURI( QString::fromUtf8( attrIter[0],
static_cast<int>( questionMark - attrIter[0] ) ) );
980 const QString localName( QString::fromUtf8( questionMark + 1 ) );
981 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
982 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
984 key.append( *nsIter );
987 key.append( localName );
991 const QString localName( QString::fromUtf8( attrIter[0] ) );
992 key.append( localName );
995 if ( mAttributeValIsNested && mParseModeStack.back() == Attribute )
997 mAttributeJsonCurrentStack.top()->emplace(
999 jsonFromString( QString::fromUtf8( attrIter[1] ) ) );
1003 QString xpath( mCurrentXPathWithinFeature );
1004 if ( !xpath.isEmpty() )
1005 xpath.append(
'/' );
1006 xpath.append( key );
1007 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( xpath );
1008 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
1010 setAttribute( xpathIter->first, QString::fromUtf8( attrIter[1] ) );
1016 if ( !mGeometryString.empty() )
1019 if ( elDimension == 0 && isGeom )
1023 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
1025 const int dimension = srsDimension.toInt( &ok );
1028 elDimension = dimension;
1032 if ( elDimension != 0 || mDimensionStack.isEmpty() )
1034 mDimensionStack.push( elDimension );
1038 mDimensionStack.push( mDimensionStack.back() );
1041 if ( mEpsg == 0 && isGeom )
1043 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
1045 QgsDebugError( QStringLiteral(
"error, could not get epsg id" ) );
1056void QgsGmlStreamingParser::endElement(
const XML_Char *el )
1060 const int elLen =
static_cast<int>( strlen( el ) );
1061 const char *pszSep = strchr( el, NS_SEPARATOR );
1062 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
1063 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
1064 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
1065 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
1067 const int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
1069 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
1071 if ( parseMode == Feature || ( parseMode == Attribute && mAttributeDepth == mParseDepth ) )
1073 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
1075 const auto nPos = mCurrentXPathWithinFeature.lastIndexOf(
'/' );
1077 mCurrentXPathWithinFeature.clear();
1079 mCurrentXPathWithinFeature.resize( nPos );
1083 if ( parseMode == Attribute && mAttributeValIsNested )
1085 if ( !mStringCash.isEmpty() )
1087 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1088 if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
1090 jsonParent = jsonFromString( mStringCash );
1092 else if ( jsonParent.type() == json::value_t::object )
1094 addStringContentToJson();
1096 mStringCash.clear();
1099 mAttributeJsonCurrentStack.pop();
1102 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
1104 mParseModeStack.pop();
1106 else if ( parseMode == PosList && isGMLNS &&
1109 mDimension = lastDimension;
1110 mParseModeStack.pop();
1112 else if ( parseMode == AttributeTuple &&
1113 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
1115 mParseModeStack.pop();
1117 setAttribute( mAttributeName, mStringCash );
1119 else if ( parseMode == Attribute && mAttributeDepth == mParseDepth )
1121 mParseModeStack.pop();
1124 if ( mAttributeValIsNested )
1126 mAttributeValIsNested =
false;
1127 auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
1128 if ( iter == mMapFieldNameToJSONContent.end() )
1130 mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
1134 QString &str = iter.value();
1135 if ( str[0] ==
'[' && str.back() ==
']' )
1141 str.insert( 0,
'[' );
1144 str.append( QString::fromStdString( mAttributeJson.dump() ) );
1150 setAttribute( mAttributeName, mStringCash );
1153 else if ( parseMode == Geometry &&
1154 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
1155 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1157 mParseModeStack.pop();
1158 if ( mFoundUnhandledGeometryElement )
1164 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
1165 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
1166 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
1168 g.
fromWkb( pabyBuffer, wkbSize );
1169 if ( mInvertAxisOrientation )
1171 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1173 Q_ASSERT( mCurrentFeature );
1177 mGeometryString.clear();
1179 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
1182 if ( mCurrentExtent.
isNull() &&
1183 !mBoundedByNullFound &&
1184 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
1186 QgsDebugError( QStringLiteral(
"creation of bounding box failed" ) );
1188 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
1189 !mCurrentFeature && mFeatureCount == 0 )
1191 mLayerExtent = mCurrentExtent;
1195 mParseModeStack.pop();
1199 mParseModeStack.pop();
1201 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
1203 mParseModeStack.pop();
1205 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
1207 QList<QgsPointXY> points;
1208 pointsFromPosListString( points, mStringCash, 2 );
1209 if ( points.size() == 1 )
1214 mParseModeStack.pop();
1216 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
1218 QList<QgsPointXY> points;
1219 pointsFromPosListString( points, mStringCash, 2 );
1220 if ( points.size() == 1 )
1225 mParseModeStack.pop();
1227 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
1229 mParseModeStack.pop();
1230 mFeatureTupleDepth = 0;
1232 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
1234 ( parseMode == Feature &&
1235 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
1236 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
1238 Q_ASSERT( mCurrentFeature );
1241 if ( mCurrentWKB.
size() > 0 )
1248 else if ( !mCurrentExtent.
isEmpty() )
1255 for (
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
1257 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
1258 const int attrIndex = att_it.value().first;
1259 mCurrentFeature->
setAttribute( attrIndex, iter.value() );
1261 mMapFieldNameToJSONContent.clear();
1265 mCurrentFeature =
nullptr;
1267 mParseModeStack.pop();
1269 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
1271 QList<QgsPointXY> pointList;
1272 if ( pointsFromString( pointList, mStringCash ) != 0 )
1277 if ( pointList.isEmpty() )
1280 if ( parseMode == QgsGmlStreamingParser::Geometry )
1283 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
1296 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
1300 if ( !mCurrentWKBFragments.isEmpty() )
1302 mCurrentWKBFragments.last().push_back( wkbPtr );
1311 else if ( !mAttributeValIsNested &&
1316 QList<QgsPointXY> pointList;
1317 if ( pointsFromString( pointList, mStringCash ) != 0 )
1321 if ( parseMode == QgsGmlStreamingParser::Geometry )
1323 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
1336 if ( getLineWKB( wkbPtr, pointList ) != 0 )
1340 if ( !mCurrentWKBFragments.isEmpty() )
1342 mCurrentWKBFragments.last().push_back( wkbPtr );
1351 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1354 QList<QgsPointXY> pointList;
1355 if ( pointsFromString( pointList, mStringCash ) != 0 )
1361 if ( getRingWKB( wkbPtr, pointList ) != 0 )
1366 if ( !mCurrentWKBFragments.isEmpty() )
1368 mCurrentWKBFragments.last().push_back( wkbPtr );
1376 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1384 if ( parseMode == Geometry )
1386 createPolygonFromFragments();
1389 else if ( parseMode == MultiPoint && isGMLNS &&
1393 mParseModeStack.pop();
1394 createMultiPointFromFragments();
1396 else if ( parseMode == MultiLine && isGMLNS &&
1400 mParseModeStack.pop();
1401 createMultiLineFromFragments();
1403 else if ( parseMode == MultiPolygon && isGMLNS &&
1407 mParseModeStack.pop();
1408 createMultiPolygonFromFragments();
1412 mParseModeStack.pop();
1414 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1416 mExceptionText = mStringCash;
1417 mParseModeStack.pop();
1420 if ( !mGeometryString.empty() )
1422 mGeometryString.append(
"</", 2 );
1423 mGeometryString.append( pszLocalName, localNameLen );
1424 mGeometryString.append(
">", 1 );
1429void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1432 if ( mParseModeStack.isEmpty() )
1437 if ( !mGeometryString.empty() )
1439 mGeometryString.append( chars, len );
1442 const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1443 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1444 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1445 parseMode == QgsGmlStreamingParser::Coordinate ||
1446 parseMode == QgsGmlStreamingParser::PosList ||
1447 parseMode == QgsGmlStreamingParser::LowerCorner ||
1448 parseMode == QgsGmlStreamingParser::UpperCorner ||
1449 parseMode == QgsGmlStreamingParser::ExceptionText )
1451 mStringCash.append( QString::fromUtf8( chars, len ) );
1455void QgsGmlStreamingParser::addStringContentToJson()
1457 const QString s( mStringCash.trimmed() );
1460 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1461 auto textIter = jsonParent.find(
"_text" );
1462 if ( textIter != jsonParent.end() )
1464 if ( textIter->type() != json::value_t::array )
1466 auto array = json::array();
1467 array.emplace_back( std::move( *textIter ) );
1470 textIter->emplace_back( jsonFromString( s ) );
1474 jsonParent.emplace(
"_text", jsonFromString( s ) );
1477 mStringCash.clear();
1480void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1483 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1484 bool conversionOk =
true;
1485 if ( att_it != mThematicAttributes.constEnd() )
1488 switch ( att_it.value().second.type() )
1490 case QMetaType::Type::Double:
1491 var = QVariant( value.toDouble( &conversionOk ) );
1493 case QMetaType::Type::Int:
1494 var = QVariant( value.toInt( &conversionOk ) );
1496 case QMetaType::Type::LongLong:
1497 var = QVariant( value.toLongLong( &conversionOk ) );
1499 case QMetaType::Type::QDateTime:
1500 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1503 var = QVariant( value );
1506 if ( ! conversionOk )
1510 Q_ASSERT( mCurrentFeature );
1511 mCurrentFeature->
setAttribute( att_it.value().first, var );
1515int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1520 if ( strcmp( attr[i],
"srsName" ) == 0 )
1522 const QString
srsName( attr[i + 1] );
1534 const int eNr = code.toInt( &conversionOk );
1535 if ( !conversionOk )
1548 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1559QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1564 if ( attributeName.compare( attr[i] ) == 0 )
1566 return QString::fromUtf8( attr[i + 1] );
1573bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1575 QList<QgsPointXY> points;
1576 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1581 if ( points.size() < 2 )
1586 r.
set( points[0], points[1] );
1591int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const
1594 const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1595 QStringList tuples_coordinates;
1597 bool conversionSuccess;
1599 QStringList::const_iterator tupleIterator;
1600 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1602 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1603 if ( tuples_coordinates.size() < 2 )
1607 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1608 if ( !conversionSuccess )
1612 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1613 if ( !conversionSuccess )
1622int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const
1625 const QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1627 if ( coordinates.size() % dimension != 0 )
1629 QgsDebugError( QStringLiteral(
"Wrong number of coordinates" ) );
1632 const int ncoor = coordinates.size() / dimension;
1633 for (
int i = 0; i < ncoor; i++ )
1635 bool conversionSuccess;
1636 const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1637 if ( !conversionSuccess )
1641 const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1642 if ( !conversionSuccess )
1651int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const
1653 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1655 return pointsFromCoordinateString( points, coordString );
1657 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1659 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1666 const int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1667 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1675int QgsGmlStreamingParser::getLineWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const
1677 const int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1678 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1684 QList<QgsPointXY>::const_iterator iter;
1685 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1687 fillPtr << iter->x() << iter->y();
1693int QgsGmlStreamingParser::getRingWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const
1695 const int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1696 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1700 fillPtr << ringCoordinates.size();
1702 QList<QgsPointXY>::const_iterator iter;
1703 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1705 fillPtr << iter->x() << iter->y();
1711int QgsGmlStreamingParser::createMultiLineFromFragments()
1713 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1714 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1721 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1722 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1724 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1725 wkbPtr += wkbIt->
size();
1729 mCurrentWKBFragments.clear();
1734int QgsGmlStreamingParser::createMultiPointFromFragments()
1736 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1737 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1742 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1743 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1745 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1746 wkbPtr += wkbIt->
size();
1750 mCurrentWKBFragments.clear();
1756int QgsGmlStreamingParser::createPolygonFromFragments()
1758 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1759 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1764 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1765 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1767 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1768 wkbPtr += wkbIt->
size();
1772 mCurrentWKBFragments.clear();
1777int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1780 size += 1 + 2 *
sizeof( int );
1781 size += totalWKBFragmentSize();
1782 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1784 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1790 QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
1792 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1797 QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
1798 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1800 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1801 wkbPtr += innerWkbIt->
size();
1802 delete[] *innerWkbIt;
1806 mCurrentWKBFragments.clear();
1811int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1814 const auto constMCurrentWKBFragments = mCurrentWKBFragments;
1815 for (
const QList<QgsWkbPtr> &list : constMCurrentWKBFragments )
1817 const auto constList = list;
1826void QgsGmlStreamingParser::createParser(
const QByteArray &encoding )
1828 Q_ASSERT( !mParser );
1830 mParser = XML_ParserCreateNS( encoding.isEmpty() ?
nullptr : encoding.data(), NS_SEPARATOR );
1831 XML_SetUserData( mParser,
this );
1832 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
1833 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...
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)
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 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.
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