16#include "moc_qgsgml.cpp"
31#include <QNetworkRequest>
32#include <QNetworkReply>
33#include <QProgressDialog>
38#include <QRegularExpression>
44using namespace nlohmann;
46static const char NS_SEPARATOR =
'?';
47static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
52 const QString &geometryAttribute,
54 : mParser(
typeName, geometryAttribute, fields )
58 const int index = mTypeName.indexOf(
':' );
59 if ( index != -1 && index < mTypeName.length() )
61 mTypeName = mTypeName.mid( index + 1 );
70 QNetworkRequest request( uri );
73 if ( !authcfg.isEmpty() )
78 tr(
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
85 else if ( !userName.isNull() || !password.isNull() )
87 request.setRawHeader(
"Authorization",
"Basic " + QStringLiteral(
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
91 if ( !authcfg.isEmpty() )
97 tr(
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
105 connect( reply, &QNetworkReply::finished,
this, &QgsGml::setFinished );
106 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsGml::handleProgressEvent );
109 QProgressDialog *progressDialog =
nullptr;
110 QWidget *mainWindow =
nullptr;
111 const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
112 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
114 if ( ( *it )->objectName() == QLatin1String(
"QgisApp" ) )
122 progressDialog =
new QProgressDialog( tr(
"Loading GML data\n%1" ).arg( mTypeName ), tr(
"Abort" ), 0, 0, mainWindow );
123 progressDialog->setWindowModality( Qt::ApplicationModal );
126 connect( progressDialog, &QProgressDialog::canceled,
this, &QgsGml::setFinished );
127 progressDialog->show();
137 const QByteArray readData = reply->readAll();
138 if ( !readData.isEmpty() )
141 if ( !mParser.
processData( readData, atEnd, errorMsg ) )
145 QCoreApplication::processEvents();
148 fillMapsFromParser();
150 const QNetworkReply::NetworkError replyError = reply->error();
151 const QString replyErrorString = reply->errorString();
154 delete progressDialog;
159 tr(
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
173 calculateExtentFromFeatures();
188 if ( !mParser.
processData( data,
true , errorMsg ) )
191 fillMapsFromParser();
201void QgsGml::fillMapsFromParser()
204 const auto constFeatures = features;
208 const QString &gmlId = featPair.second;
209 mFeatures.insert( feat->
id(), feat );
210 if ( !gmlId.isEmpty() )
212 mIdMap.insert( feat->
id(), gmlId );
217void QgsGml::setFinished()
222void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
224 if ( totalSteps < 0 )
234void QgsGml::calculateExtentFromFeatures()
236 if ( mFeatures.empty() )
243 bool bboxInitialized =
false;
245 for (
int i = 0; i < mFeatures.size(); ++i )
247 currentFeature = mFeatures[i];
248 if ( !currentFeature )
252 currentGeometry = currentFeature->
geometry();
253 if ( !currentGeometry.
isNull() )
255 if ( !bboxInitialized )
258 bboxInitialized =
true;
283 const QString &geometryAttribute,
286 bool invertAxisOrientation )
288 , mTypeNameBA( mTypeName.toUtf8() )
289 , mTypeNamePtr( mTypeNameBA.constData() )
290 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
291 , mWkbType(
Qgis::WkbType::Unknown )
292 , mGeometryAttribute( geometryAttribute )
293 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
294 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
295 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
297 , mIsException( false )
298 , mTruncatedResponse( false )
300 , mFeatureTupleDepth( 0 )
302 , mCurrentWKB( nullptr, 0 )
303 , mBoundedByNullFound( false )
305 , mCoorMode( Coordinate )
307 , mAxisOrientationLogic( axisOrientationLogic )
308 , mInvertAxisOrientationRequest( invertAxisOrientation )
309 , mInvertAxisOrientation( invertAxisOrientation )
310 , mNumberReturned( -1 )
311 , mNumberMatched( -1 )
312 , mFoundUnhandledGeometryElement( false )
314 mThematicAttributes.clear();
315 for (
int i = 0; i < fields.
size(); i++ )
317 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
322 const int index = mTypeName.indexOf(
':' );
323 if ( index != -1 && index < mTypeName.length() )
325 mTypeName = mTypeName.mid( index + 1 );
326 mTypeNameBA = mTypeName.toUtf8();
327 mTypeNamePtr = mTypeNameBA.constData();
328 mTypeNameUTF8Len = strlen( mTypeNamePtr );
334static QString stripNS(
const QString &
string )
336 const int index =
string.indexOf(
':' );
337 if ( index != -1 && index <
string.length() )
339 return string.mid( index + 1 );
346 const QMap< QString, QPair<QString, QString> > &fieldNameToSrcLayerNameFieldNameMap,
348 bool invertAxisOrientation )
349 : mLayerProperties( layerProperties )
350 , mTypeNameUTF8Len( 0 )
351 , mWkbType(
Qgis::WkbType::Unknown )
352 , mGeometryAttributeUTF8Len( 0 )
354 , mIsException( false )
355 , mTruncatedResponse( false )
357 , mFeatureTupleDepth( 0 )
359 , mCurrentWKB( nullptr, 0 )
360 , mBoundedByNullFound( false )
362 , mCoorMode( Coordinate )
364 , mAxisOrientationLogic( axisOrientationLogic )
365 , mInvertAxisOrientationRequest( invertAxisOrientation )
366 , mInvertAxisOrientation( invertAxisOrientation )
367 , mNumberReturned( -1 )
368 , mNumberMatched( -1 )
369 , mFoundUnhandledGeometryElement( false )
371 mThematicAttributes.clear();
372 for (
int i = 0; i < fields.
size(); i++ )
374 const QMap< QString, QPair<QString, QString> >::const_iterator att_it = fieldNameToSrcLayerNameFieldNameMap.constFind( fields.
at( i ).
name() );
375 if ( att_it != fieldNameToSrcLayerNameFieldNameMap.constEnd() )
377 if ( mLayerProperties.size() == 1 )
378 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
380 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
383 bool alreadyFoundGeometry =
false;
384 for (
int i = 0; i < mLayerProperties.size(); i++ )
387 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
389 if ( alreadyFoundGeometry )
391 QgsDebugMsgLevel( QStringLiteral(
"Will ignore geometry field %1 from typename %2" ).
392 arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ), 2 );
393 mLayerProperties[i].mGeometryAttribute.clear();
395 alreadyFoundGeometry =
true;
397 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
400 if ( mLayerProperties.size() == 1 )
402 mTypeName = mLayerProperties[0].mName;
403 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
404 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
405 mGeometryAttributePtr = mGeometryAttributeBA.constData();
406 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
407 const int index = mTypeName.indexOf(
':' );
408 if ( index != -1 && index < mTypeName.length() )
410 mTypeName = mTypeName.mid( index + 1 );
412 mTypeNameBA = mTypeName.toUtf8();
413 mTypeNamePtr = mTypeNameBA.constData();
414 mTypeNameUTF8Len = strlen( mTypeNamePtr );
424 const QMap<QString, QPair<QString, bool>> &fieldNameToXPathMapAndIsNestedContent,
425 const QMap<QString, QString> &mapNamespacePrefixToURI )
427 for (
auto iter = fieldNameToXPathMapAndIsNestedContent.constBegin(); iter != fieldNameToXPathMapAndIsNestedContent.constEnd(); ++iter )
429 mMapXPathToFieldNameAndIsNestedContent[iter.value().first] = QPair<QString, bool>( iter.key(), iter.value().second );
431 for (
auto iter = mapNamespacePrefixToURI.constBegin(); iter != mapNamespacePrefixToURI.constEnd(); ++iter )
432 mMapNamespaceURIToNamespacePrefix[iter.value()] = iter.key();
438 XML_ParserFree( mParser );
441 const auto constMFeatureList = mFeatureList;
444 delete featPair.first;
447 delete mCurrentFeature;
463 QByteArray data = pdata;
468 QString strData = mCodec->toUnicode( pdata );
469 data = strData.toUtf8();
472 if ( XML_Parse( mParser, data, data.size(), atEnd ) == XML_STATUS_ERROR )
474 const XML_Error errorCode = XML_GetErrorCode( mParser );
475 if ( !mCodec && errorCode == XML_ERROR_UNKNOWN_ENCODING )
479 const thread_local QRegularExpression reEncoding( QStringLiteral(
"<?xml.*encoding=['\"]([^'\"]*)['\"].*?>" ),
480 QRegularExpression::CaseInsensitiveOption );
481 QRegularExpressionMatch match = reEncoding.match( pdata );
482 const QString encoding = match.hasMatch() ? match.captured( 1 ) : QString();
483 mCodec = !encoding.isEmpty() ? QTextCodec::codecForName( encoding.toLatin1() ) :
nullptr;
487 XML_ParserFree( mParser );
489 createParser( QByteArrayLiteral(
"UTF-8" ) );
495 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" )
496 .arg( XML_ErrorString( errorCode ) )
497 .arg( XML_GetCurrentLineNumber( mParser ) )
498 .arg( XML_GetCurrentColumnNumber( mParser ) );
508 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
509 mFeatureList.clear();
517static json jsonFromString(
const QString &s )
522 if ( s.indexOf(
'.' ) >= 0 || s.indexOf(
'e' ) >= 0 )
524 const auto doubleVal = s.toDouble( &conversionOk );
527 return json( doubleVal );
532 else if ( !s.isEmpty() && s[0] !=
'0' )
534 const auto longlongVal = s.toLongLong( &conversionOk );
537 return json( longlongVal );
541 return json( s.toStdString() );
544#define LOCALNAME_EQUALS(string_constant) \
545 ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 )
547void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
549 const int elLen =
static_cast<int>( strlen( el ) );
550 const char *pszSep = strchr( el, NS_SEPARATOR );
551 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
552 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
553 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
554 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
558 if ( !mGMLNameSpaceURIPtr && pszSep )
572 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
575 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
576 parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
578 mGeometryString.append(
"<", 1 );
579 mGeometryString.append( pszLocalName, localNameLen );
580 mGeometryString.append(
" ", 1 );
581 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
583 const size_t nAttrLen = strlen( attrIter[0] );
586 if ( nAttrLen > GML32_NAMESPACE_LEN &&
587 attrIter[0][GML32_NAMESPACE_LEN] ==
'?' &&
590 mGeometryString.append(
"gml:" );
591 mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
593 else if ( nAttrLen > GML_NAMESPACE_LEN &&
594 attrIter[0][GML_NAMESPACE_LEN] ==
'?' &&
595 memcmp( attrIter[0],
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
597 mGeometryString.append(
"gml:" );
598 mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
602 mGeometryString.append( attrIter[0] );
604 mGeometryString.append(
"=\"", 2 );
605 mGeometryString.append( attrIter[1] );
606 mGeometryString.append(
"\" ", 2 );
609 mGeometryString.append(
">", 1 );
612 if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
614 mParseModeStack.push( Coordinate );
615 mCoorMode = QgsGmlStreamingParser::Coordinate;
617 mCoordinateSeparator = readAttribute( QStringLiteral(
"cs" ), attr );
618 if ( mCoordinateSeparator.isEmpty() )
620 mCoordinateSeparator =
',';
622 mTupleSeparator = readAttribute( QStringLiteral(
"ts" ), attr );
623 if ( mTupleSeparator.isEmpty() )
625 mTupleSeparator =
' ';
628 else if ( !mAttributeValIsNested && isGMLNS &&
631 mParseModeStack.push( QgsGmlStreamingParser::PosList );
632 mCoorMode = QgsGmlStreamingParser::PosList;
634 if ( elDimension == 0 )
636 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
638 const int dimension = srsDimension.toInt( &ok );
641 elDimension = dimension;
645 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
647 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
648 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
650 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
651 mFoundUnhandledGeometryElement =
false;
652 mGeometryString.clear();
655 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
657 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
659 mBoundedByNullFound =
false;
661 else if ( parseMode == BoundingBox &&
664 mParseModeStack.push( QgsGmlStreamingParser::Null );
665 mBoundedByNullFound =
true;
667 else if ( parseMode == BoundingBox &&
671 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
673 else if ( parseMode == Envelope &&
676 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
679 else if ( parseMode == Envelope &&
682 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
685 else if ( parseMode == None && !mTypeNamePtr &&
688 Q_ASSERT( !mCurrentFeature );
689 mCurrentFeature =
new QgsFeature( mFeatureCount );
691 const QgsAttributes attributes( mThematicAttributes.size() );
693 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
694 mCurrentFeatureId.clear();
696 else if ( parseMode == Tuple )
698 const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
699 const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
700 if ( iter != mMapTypeNameToProperties.constEnd() )
702 mFeatureTupleDepth = mParseDepth;
703 mCurrentTypename = currentTypename;
704 mGeometryAttribute.clear();
705 if ( mCurrentWKB.
size() == 0 )
707 mGeometryAttribute = iter.value().mGeometryAttribute;
709 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
710 mGeometryAttributePtr = mGeometryAttributeBA.constData();
711 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
712 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
714 if ( mGMLNameSpaceURI.isEmpty() )
716 id = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
724 id = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
733 id = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
734 if ( !mCurrentFeatureId.isEmpty() )
735 mCurrentFeatureId +=
'|';
736 mCurrentFeatureId += id;
739 else if ( parseMode == None &&
740 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
742 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
744 Q_ASSERT( !mCurrentFeature );
745 mCurrentFeature =
new QgsFeature( mFeatureCount );
747 const QgsAttributes attributes( mThematicAttributes.size() );
749 mParseModeStack.push( QgsGmlStreamingParser::Feature );
750 mCurrentXPathWithinFeature.clear();
751 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
752 if ( mCurrentFeatureId.isEmpty() )
757 if ( mGMLNameSpaceURI.isEmpty() )
759 mCurrentFeatureId = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
760 if ( !mCurrentFeatureId.isEmpty() )
767 mCurrentFeatureId = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
768 if ( !mCurrentFeatureId.isEmpty() )
776 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
780 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
784 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
788 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"LineString" ) )
792 else if ( !mAttributeValIsNested && isGMLNS &&
793 localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
796 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
798 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
801 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
803 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
808 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
810 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
815 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
817 else if ( parseMode == FeatureTuple )
819 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
820 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
822 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
823 mAttributeName = mCurrentTypename +
'|' + localName;
827 else if ( parseMode == Feature )
829 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
830 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
832 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
833 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
834 if ( !mCurrentXPathWithinFeature.isEmpty() )
835 mCurrentXPathWithinFeature.append(
'/' );
836 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
838 mCurrentXPathWithinFeature.append( *nsIter );
839 mCurrentXPathWithinFeature.append(
':' );
841 mCurrentXPathWithinFeature.append( localName );
842 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( mCurrentXPathWithinFeature );
843 mAttributeValIsNested =
false;
844 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
846 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
847 mAttributeDepth = mParseDepth;
848 mAttributeName = xpathIter->first;
849 mAttributeValIsNested = xpathIter->second;
850 if ( mAttributeValIsNested )
852 mAttributeJson = json::object();
853 mAttributeJsonCurrentStack.clear();
854 mAttributeJsonCurrentStack.push( &mAttributeJson );
859 else if ( mThematicAttributes.contains( localName ) )
861 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
862 mAttributeDepth = mParseDepth;
863 mAttributeName = localName;
870 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
872 const QString name = readAttribute( QStringLiteral(
"name" ), attr );
873 if ( mThematicAttributes.contains( name ) )
875 const QString value = readAttribute( QStringLiteral(
"value" ), attr );
876 setAttribute( name, value );
881 else if ( parseMode == Attribute && mAttributeValIsNested )
883 const std::string localName( pszLocalName, localNameLen );
884 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
885 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
886 const std::string nodeName = nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() ? ( *nsIter ).toStdString() +
':' + localName : localName;
888 addStringContentToJson();
890 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
891 auto iter = jsonParent.find( nodeName );
892 if ( iter != jsonParent.end() )
894 if ( iter->type() != json::value_t::array )
896 auto array = json::array();
897 array.emplace_back( std::move( *iter ) );
900 iter->push_back( json::object() );
901 mAttributeJsonCurrentStack.push( &( iter->back() ) );
905 auto res = jsonParent.emplace( nodeName, json::object() );
909 nlohmann::json *ptr = &( *( res.first ) );
911 mAttributeJsonCurrentStack.push( ptr );
916 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
918 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
922 mNumberReturned = -1;
924 const QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
932 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
937 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
942 mTruncatedResponse =
true;
944 else if ( !mGeometryString.empty() &&
960 mFoundUnhandledGeometryElement =
true;
964 if ( !mParseModeStack.isEmpty() &&
965 ( mParseModeStack.back() == Feature ||
966 mParseModeStack.back() == Attribute ) &&
967 !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
969 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
971 const char *questionMark = strchr( attrIter[0],
'?' );
975 const QString nsURI( QString::fromUtf8( attrIter[0],
static_cast<int>( questionMark - attrIter[0] ) ) );
976 const QString localName( QString::fromUtf8( questionMark + 1 ) );
977 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
978 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
980 key.append( *nsIter );
983 key.append( localName );
987 const QString localName( QString::fromUtf8( attrIter[0] ) );
988 key.append( localName );
991 if ( mAttributeValIsNested && mParseModeStack.back() == Attribute )
993 mAttributeJsonCurrentStack.top()->emplace(
995 jsonFromString( QString::fromUtf8( attrIter[1] ) ) );
999 QString xpath( mCurrentXPathWithinFeature );
1000 if ( !xpath.isEmpty() )
1001 xpath.append(
'/' );
1002 xpath.append( key );
1003 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( xpath );
1004 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
1006 setAttribute( xpathIter->first, QString::fromUtf8( attrIter[1] ) );
1012 if ( !mGeometryString.empty() )
1015 if ( elDimension == 0 && isGeom )
1019 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
1021 const int dimension = srsDimension.toInt( &ok );
1024 elDimension = dimension;
1028 if ( elDimension != 0 || mDimensionStack.isEmpty() )
1030 mDimensionStack.push( elDimension );
1034 mDimensionStack.push( mDimensionStack.back() );
1037 if ( mEpsg == 0 && isGeom )
1039 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
1041 QgsDebugError( QStringLiteral(
"error, could not get epsg id" ) );
1052void QgsGmlStreamingParser::endElement(
const XML_Char *el )
1056 const int elLen =
static_cast<int>( strlen( el ) );
1057 const char *pszSep = strchr( el, NS_SEPARATOR );
1058 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
1059 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
1060 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
1061 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
1063 const int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
1065 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
1067 if ( parseMode == Feature || ( parseMode == Attribute && mAttributeDepth == mParseDepth ) )
1069 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
1071 const auto nPos = mCurrentXPathWithinFeature.lastIndexOf(
'/' );
1073 mCurrentXPathWithinFeature.clear();
1075 mCurrentXPathWithinFeature.resize( nPos );
1079 if ( parseMode == Attribute && mAttributeValIsNested )
1081 if ( !mStringCash.isEmpty() )
1083 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1084 if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
1086 jsonParent = jsonFromString( mStringCash );
1088 else if ( jsonParent.type() == json::value_t::object )
1090 addStringContentToJson();
1092 mStringCash.clear();
1095 mAttributeJsonCurrentStack.pop();
1098 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
1100 mParseModeStack.pop();
1102 else if ( parseMode == PosList && isGMLNS &&
1105 mDimension = lastDimension;
1106 mParseModeStack.pop();
1108 else if ( parseMode == AttributeTuple &&
1109 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
1111 mParseModeStack.pop();
1113 setAttribute( mAttributeName, mStringCash );
1115 else if ( parseMode == Attribute && mAttributeDepth == mParseDepth )
1117 mParseModeStack.pop();
1120 if ( mAttributeValIsNested )
1122 mAttributeValIsNested =
false;
1123 auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
1124 if ( iter == mMapFieldNameToJSONContent.end() )
1126 mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
1130 QString &
str = iter.value();
1131 if (
str[0] ==
'[' &&
str.back() ==
']' )
1137 str.insert( 0,
'[' );
1140 str.append( QString::fromStdString( mAttributeJson.dump() ) );
1146 setAttribute( mAttributeName, mStringCash );
1149 else if ( parseMode == Geometry &&
1150 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
1151 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1153 mParseModeStack.pop();
1154 if ( mFoundUnhandledGeometryElement )
1160 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
1161 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
1162 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
1164 g.
fromWkb( pabyBuffer, wkbSize );
1165 if ( mInvertAxisOrientation )
1167 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1169 Q_ASSERT( mCurrentFeature );
1173 mGeometryString.clear();
1175 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
1178 if ( mCurrentExtent.
isNull() &&
1179 !mBoundedByNullFound &&
1180 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
1182 QgsDebugError( QStringLiteral(
"creation of bounding box failed" ) );
1184 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
1185 !mCurrentFeature && mFeatureCount == 0 )
1187 mLayerExtent = mCurrentExtent;
1191 mParseModeStack.pop();
1195 mParseModeStack.pop();
1197 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
1199 mParseModeStack.pop();
1201 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
1203 QList<QgsPointXY> points;
1204 pointsFromPosListString( points, mStringCash, 2 );
1205 if ( points.size() == 1 )
1210 mParseModeStack.pop();
1212 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
1214 QList<QgsPointXY> points;
1215 pointsFromPosListString( points, mStringCash, 2 );
1216 if ( points.size() == 1 )
1221 mParseModeStack.pop();
1223 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
1225 mParseModeStack.pop();
1226 mFeatureTupleDepth = 0;
1228 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
1230 ( parseMode == Feature &&
1231 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
1232 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
1234 Q_ASSERT( mCurrentFeature );
1237 if ( mCurrentWKB.
size() > 0 )
1244 else if ( !mCurrentExtent.
isEmpty() )
1251 for (
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
1253 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
1254 const int attrIndex = att_it.value().first;
1255 mCurrentFeature->
setAttribute( attrIndex, iter.value() );
1257 mMapFieldNameToJSONContent.clear();
1261 mCurrentFeature =
nullptr;
1263 mParseModeStack.pop();
1265 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
1267 QList<QgsPointXY> pointList;
1268 if ( pointsFromString( pointList, mStringCash ) != 0 )
1273 if ( pointList.isEmpty() )
1276 if ( parseMode == QgsGmlStreamingParser::Geometry )
1279 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
1292 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
1296 if ( !mCurrentWKBFragments.isEmpty() )
1298 mCurrentWKBFragments.last().push_back( wkbPtr );
1307 else if ( !mAttributeValIsNested &&
1312 QList<QgsPointXY> pointList;
1313 if ( pointsFromString( pointList, mStringCash ) != 0 )
1317 if ( parseMode == QgsGmlStreamingParser::Geometry )
1319 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
1332 if ( getLineWKB( wkbPtr, pointList ) != 0 )
1336 if ( !mCurrentWKBFragments.isEmpty() )
1338 mCurrentWKBFragments.last().push_back( wkbPtr );
1347 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1350 QList<QgsPointXY> pointList;
1351 if ( pointsFromString( pointList, mStringCash ) != 0 )
1357 if ( getRingWKB( wkbPtr, pointList ) != 0 )
1362 if ( !mCurrentWKBFragments.isEmpty() )
1364 mCurrentWKBFragments.last().push_back( wkbPtr );
1372 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1380 if ( parseMode == Geometry )
1382 createPolygonFromFragments();
1385 else if ( parseMode == MultiPoint && isGMLNS &&
1389 mParseModeStack.pop();
1390 createMultiPointFromFragments();
1392 else if ( parseMode == MultiLine && isGMLNS &&
1396 mParseModeStack.pop();
1397 createMultiLineFromFragments();
1399 else if ( parseMode == MultiPolygon && isGMLNS &&
1403 mParseModeStack.pop();
1404 createMultiPolygonFromFragments();
1408 mParseModeStack.pop();
1410 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1412 mExceptionText = mStringCash;
1413 mParseModeStack.pop();
1416 if ( !mGeometryString.empty() )
1418 mGeometryString.append(
"</", 2 );
1419 mGeometryString.append( pszLocalName, localNameLen );
1420 mGeometryString.append(
">", 1 );
1425void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1428 if ( mParseModeStack.isEmpty() )
1433 if ( !mGeometryString.empty() )
1435 mGeometryString.append( chars, len );
1438 const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1439 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1440 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1441 parseMode == QgsGmlStreamingParser::Coordinate ||
1442 parseMode == QgsGmlStreamingParser::PosList ||
1443 parseMode == QgsGmlStreamingParser::LowerCorner ||
1444 parseMode == QgsGmlStreamingParser::UpperCorner ||
1445 parseMode == QgsGmlStreamingParser::ExceptionText )
1447 mStringCash.append( QString::fromUtf8( chars, len ) );
1451void QgsGmlStreamingParser::addStringContentToJson()
1453 const QString s( mStringCash.trimmed() );
1456 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1457 auto textIter = jsonParent.find(
"_text" );
1458 if ( textIter != jsonParent.end() )
1460 if ( textIter->type() != json::value_t::array )
1462 auto array = json::array();
1463 array.emplace_back( std::move( *textIter ) );
1466 textIter->emplace_back( jsonFromString( s ) );
1470 jsonParent.emplace(
"_text", jsonFromString( s ) );
1473 mStringCash.clear();
1476void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1479 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1480 bool conversionOk =
true;
1481 if ( att_it != mThematicAttributes.constEnd() )
1484 switch ( att_it.value().second.type() )
1486 case QMetaType::Type::Double:
1487 var = QVariant( value.toDouble( &conversionOk ) );
1489 case QMetaType::Type::Int:
1490 var = QVariant( value.toInt( &conversionOk ) );
1492 case QMetaType::Type::LongLong:
1493 var = QVariant( value.toLongLong( &conversionOk ) );
1495 case QMetaType::Type::QDateTime:
1496 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1499 var = QVariant( value );
1502 if ( ! conversionOk )
1506 Q_ASSERT( mCurrentFeature );
1507 mCurrentFeature->
setAttribute( att_it.value().first, var );
1511int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1516 if ( strcmp( attr[i],
"srsName" ) == 0 )
1518 const QString
srsName( attr[i + 1] );
1530 const int eNr = code.toInt( &conversionOk );
1531 if ( !conversionOk )
1544 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1555QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1560 if ( attributeName.compare( attr[i] ) == 0 )
1562 return QString::fromUtf8( attr[i + 1] );
1569bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1571 QList<QgsPointXY> points;
1572 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1577 if ( points.size() < 2 )
1582 r.
set( points[0], points[1] );
1587int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const
1590 const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1591 QStringList tuples_coordinates;
1593 bool conversionSuccess;
1595 QStringList::const_iterator tupleIterator;
1596 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1598 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1599 if ( tuples_coordinates.size() < 2 )
1603 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1604 if ( !conversionSuccess )
1608 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1609 if ( !conversionSuccess )
1618int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const
1621 const QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1623 if ( coordinates.size() % dimension != 0 )
1625 QgsDebugError( QStringLiteral(
"Wrong number of coordinates" ) );
1628 const int ncoor = coordinates.size() / dimension;
1629 for (
int i = 0; i < ncoor; i++ )
1631 bool conversionSuccess;
1632 const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1633 if ( !conversionSuccess )
1637 const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1638 if ( !conversionSuccess )
1647int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const
1649 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1651 return pointsFromCoordinateString( points, coordString );
1653 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1655 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1662 const int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1663 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1671int QgsGmlStreamingParser::getLineWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const
1673 const int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1674 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1680 QList<QgsPointXY>::const_iterator iter;
1681 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1683 fillPtr << iter->x() << iter->y();
1689int QgsGmlStreamingParser::getRingWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const
1691 const int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1692 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1696 fillPtr << ringCoordinates.size();
1698 QList<QgsPointXY>::const_iterator iter;
1699 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1701 fillPtr << iter->x() << iter->y();
1707int QgsGmlStreamingParser::createMultiLineFromFragments()
1709 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1710 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1717 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1718 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1720 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1721 wkbPtr += wkbIt->
size();
1725 mCurrentWKBFragments.clear();
1730int QgsGmlStreamingParser::createMultiPointFromFragments()
1732 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1733 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1738 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1739 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1741 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1742 wkbPtr += wkbIt->
size();
1746 mCurrentWKBFragments.clear();
1752int QgsGmlStreamingParser::createPolygonFromFragments()
1754 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1755 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1760 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1761 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1763 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1764 wkbPtr += wkbIt->
size();
1768 mCurrentWKBFragments.clear();
1773int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1776 size += 1 + 2 *
sizeof( int );
1777 size += totalWKBFragmentSize();
1778 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1780 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1786 QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
1788 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1793 QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
1794 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1796 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1797 wkbPtr += innerWkbIt->
size();
1798 delete[] *innerWkbIt;
1802 mCurrentWKBFragments.clear();
1807int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1810 const auto constMCurrentWKBFragments = mCurrentWKBFragments;
1811 for (
const QList<QgsWkbPtr> &list : constMCurrentWKBFragments )
1813 const auto constList = list;
1822void QgsGmlStreamingParser::createParser(
const QByteArray &encoding )
1824 Q_ASSERT( !mParser );
1826 mParser = XML_ParserCreateNS( encoding.isEmpty() ?
nullptr : encoding.data(), NS_SEPARATOR );
1827 XML_SetUserData( mParser,
this );
1828 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
1829 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.
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