30#include <QNetworkRequest>
31#include <QNetworkReply>
32#include <QProgressDialog>
37#include <QRegularExpression>
43using namespace nlohmann;
45static const char NS_SEPARATOR =
'?';
46static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
51 const QString &geometryAttribute,
53 : mParser(
typeName, geometryAttribute, fields )
57 const int index = mTypeName.indexOf(
':' );
58 if ( index != -1 && index < mTypeName.length() )
60 mTypeName = mTypeName.mid( index + 1 );
69 QNetworkRequest request( uri );
72 if ( !authcfg.isEmpty() )
77 tr(
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
84 else if ( !userName.isNull() || !password.isNull() )
86 request.setRawHeader(
"Authorization",
"Basic " + QStringLiteral(
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
90 if ( !authcfg.isEmpty() )
96 tr(
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
104 connect( reply, &QNetworkReply::finished,
this, &QgsGml::setFinished );
105 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsGml::handleProgressEvent );
108 QProgressDialog *progressDialog =
nullptr;
109 QWidget *mainWindow =
nullptr;
110 const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
111 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
113 if ( ( *it )->objectName() == QLatin1String(
"QgisApp" ) )
121 progressDialog =
new QProgressDialog( tr(
"Loading GML data\n%1" ).arg( mTypeName ), tr(
"Abort" ), 0, 0, mainWindow );
122 progressDialog->setWindowModality( Qt::ApplicationModal );
125 connect( progressDialog, &QProgressDialog::canceled,
this, &QgsGml::setFinished );
126 progressDialog->show();
136 const QByteArray readData = reply->readAll();
137 if ( !readData.isEmpty() )
140 if ( !mParser.
processData( readData, atEnd, errorMsg ) )
144 QCoreApplication::processEvents();
147 fillMapsFromParser();
149 const QNetworkReply::NetworkError replyError = reply->error();
150 const QString replyErrorString = reply->errorString();
153 delete progressDialog;
158 tr(
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
172 calculateExtentFromFeatures();
187 if ( !mParser.
processData( data,
true , errorMsg ) )
190 fillMapsFromParser();
200void QgsGml::fillMapsFromParser()
203 const auto constFeatures = features;
207 const QString &gmlId = featPair.second;
208 mFeatures.insert( feat->
id(), feat );
209 if ( !gmlId.isEmpty() )
211 mIdMap.insert( feat->
id(), gmlId );
216void QgsGml::setFinished()
221void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
223 if ( totalSteps < 0 )
233void QgsGml::calculateExtentFromFeatures()
235 if ( mFeatures.empty() )
242 bool bboxInitialized =
false;
244 for (
int i = 0; i < mFeatures.size(); ++i )
246 currentFeature = mFeatures[i];
247 if ( !currentFeature )
251 currentGeometry = currentFeature->
geometry();
252 if ( !currentGeometry.
isNull() )
254 if ( !bboxInitialized )
257 bboxInitialized =
true;
282 const QString &geometryAttribute,
285 bool invertAxisOrientation )
287 , mTypeNameBA( mTypeName.toUtf8() )
288 , mTypeNamePtr( mTypeNameBA.constData() )
289 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
290 , mWkbType(
Qgis::WkbType::Unknown )
291 , mGeometryAttribute( geometryAttribute )
292 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
293 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
294 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
296 , mIsException( false )
297 , mTruncatedResponse( false )
299 , mFeatureTupleDepth( 0 )
301 , mCurrentWKB( nullptr, 0 )
302 , mBoundedByNullFound( false )
304 , mCoorMode( Coordinate )
306 , mAxisOrientationLogic( axisOrientationLogic )
307 , mInvertAxisOrientationRequest( invertAxisOrientation )
308 , mInvertAxisOrientation( invertAxisOrientation )
309 , mNumberReturned( -1 )
310 , mNumberMatched( -1 )
311 , mFoundUnhandledGeometryElement( false )
313 mThematicAttributes.clear();
314 for (
int i = 0; i < fields.
size(); i++ )
316 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
321 const int index = mTypeName.indexOf(
':' );
322 if ( index != -1 && index < mTypeName.length() )
324 mTypeName = mTypeName.mid( index + 1 );
325 mTypeNameBA = mTypeName.toUtf8();
326 mTypeNamePtr = mTypeNameBA.constData();
327 mTypeNameUTF8Len = strlen( mTypeNamePtr );
333static QString stripNS(
const QString &
string )
335 const int index =
string.indexOf(
':' );
336 if ( index != -1 && index <
string.length() )
338 return string.mid( index + 1 );
345 const QMap< QString, QPair<QString, QString> > &fieldNameToSrcLayerNameFieldNameMap,
347 bool invertAxisOrientation )
348 : mLayerProperties( layerProperties )
349 , mTypeNameUTF8Len( 0 )
350 , mWkbType(
Qgis::WkbType::Unknown )
351 , mGeometryAttributeUTF8Len( 0 )
353 , mIsException( false )
354 , mTruncatedResponse( false )
356 , mFeatureTupleDepth( 0 )
358 , mCurrentWKB( nullptr, 0 )
359 , mBoundedByNullFound( false )
361 , mCoorMode( Coordinate )
363 , mAxisOrientationLogic( axisOrientationLogic )
364 , mInvertAxisOrientationRequest( invertAxisOrientation )
365 , mInvertAxisOrientation( invertAxisOrientation )
366 , mNumberReturned( -1 )
367 , mNumberMatched( -1 )
368 , mFoundUnhandledGeometryElement( false )
370 mThematicAttributes.clear();
371 for (
int i = 0; i < fields.
size(); i++ )
373 const QMap< QString, QPair<QString, QString> >::const_iterator att_it = fieldNameToSrcLayerNameFieldNameMap.constFind( fields.
at( i ).
name() );
374 if ( att_it != fieldNameToSrcLayerNameFieldNameMap.constEnd() )
376 if ( mLayerProperties.size() == 1 )
377 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
379 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
382 bool alreadyFoundGeometry =
false;
383 for (
int i = 0; i < mLayerProperties.size(); i++ )
386 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
388 if ( alreadyFoundGeometry )
390 QgsDebugMsgLevel( QStringLiteral(
"Will ignore geometry field %1 from typename %2" ).
391 arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ), 2 );
392 mLayerProperties[i].mGeometryAttribute.clear();
394 alreadyFoundGeometry =
true;
396 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
399 if ( mLayerProperties.size() == 1 )
401 mTypeName = mLayerProperties[0].mName;
402 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
403 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
404 mGeometryAttributePtr = mGeometryAttributeBA.constData();
405 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
406 const int index = mTypeName.indexOf(
':' );
407 if ( index != -1 && index < mTypeName.length() )
409 mTypeName = mTypeName.mid( index + 1 );
411 mTypeNameBA = mTypeName.toUtf8();
412 mTypeNamePtr = mTypeNameBA.constData();
413 mTypeNameUTF8Len = strlen( mTypeNamePtr );
423 const QMap<QString, QPair<QString, bool>> &fieldNameToXPathMapAndIsNestedContent,
424 const QMap<QString, QString> &mapNamespacePrefixToURI )
426 for (
auto iter = fieldNameToXPathMapAndIsNestedContent.constBegin(); iter != fieldNameToXPathMapAndIsNestedContent.constEnd(); ++iter )
428 mMapXPathToFieldNameAndIsNestedContent[iter.value().first] = QPair<QString, bool>( iter.key(), iter.value().second );
430 for (
auto iter = mapNamespacePrefixToURI.constBegin(); iter != mapNamespacePrefixToURI.constEnd(); ++iter )
431 mMapNamespaceURIToNamespacePrefix[iter.value()] = iter.key();
437 XML_ParserFree( mParser );
440 const auto constMFeatureList = mFeatureList;
443 delete featPair.first;
446 delete mCurrentFeature;
462 QByteArray data = pdata;
467 QString strData = mCodec->toUnicode( pdata );
468 data = strData.toUtf8();
471 if ( XML_Parse( mParser, data, data.size(), atEnd ) == XML_STATUS_ERROR )
473 const XML_Error errorCode = XML_GetErrorCode( mParser );
474 if ( !mCodec && errorCode == XML_ERROR_UNKNOWN_ENCODING )
478 const thread_local QRegularExpression reEncoding( QStringLiteral(
"<?xml.*encoding=['\"]([^'\"]*)['\"].*?>" ),
479 QRegularExpression::CaseInsensitiveOption );
480 QRegularExpressionMatch match = reEncoding.match( pdata );
481 const QString encoding = match.hasMatch() ? match.captured( 1 ) : QString();
482 mCodec = !encoding.isEmpty() ? QTextCodec::codecForName( encoding.toLatin1() ) :
nullptr;
486 XML_ParserFree( mParser );
488 createParser( QByteArrayLiteral(
"UTF-8" ) );
494 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" )
495 .arg( XML_ErrorString( errorCode ) )
496 .arg( XML_GetCurrentLineNumber( mParser ) )
497 .arg( XML_GetCurrentColumnNumber( mParser ) );
507 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
508 mFeatureList.clear();
516static json jsonFromString(
const QString &s )
521 if ( s.indexOf(
'.' ) >= 0 || s.indexOf(
'e' ) >= 0 )
523 const auto doubleVal = s.toDouble( &conversionOk );
526 return json( doubleVal );
531 else if ( !s.isEmpty() && s[0] !=
'0' )
533 const auto longlongVal = s.toLongLong( &conversionOk );
536 return json( longlongVal );
540 return json( s.toStdString() );
543#define LOCALNAME_EQUALS(string_constant) \
544 ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 )
546void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
548 const int elLen =
static_cast<int>( strlen( el ) );
549 const char *pszSep = strchr( el, NS_SEPARATOR );
550 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
551 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
552 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
553 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
557 if ( !mGMLNameSpaceURIPtr && pszSep )
571 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
574 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
575 parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
577 mGeometryString.append(
"<", 1 );
578 mGeometryString.append( pszLocalName, localNameLen );
579 mGeometryString.append(
" ", 1 );
580 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
582 const size_t nAttrLen = strlen( attrIter[0] );
585 if ( nAttrLen > GML32_NAMESPACE_LEN &&
586 attrIter[0][GML32_NAMESPACE_LEN] ==
'?' &&
589 mGeometryString.append(
"gml:" );
590 mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
592 else if ( nAttrLen > GML_NAMESPACE_LEN &&
593 attrIter[0][GML_NAMESPACE_LEN] ==
'?' &&
594 memcmp( attrIter[0],
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
596 mGeometryString.append(
"gml:" );
597 mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
601 mGeometryString.append( attrIter[0] );
603 mGeometryString.append(
"=\"", 2 );
604 mGeometryString.append( attrIter[1] );
605 mGeometryString.append(
"\" ", 2 );
608 mGeometryString.append(
">", 1 );
611 if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
613 mParseModeStack.push( Coordinate );
614 mCoorMode = QgsGmlStreamingParser::Coordinate;
616 mCoordinateSeparator = readAttribute( QStringLiteral(
"cs" ), attr );
617 if ( mCoordinateSeparator.isEmpty() )
619 mCoordinateSeparator =
',';
621 mTupleSeparator = readAttribute( QStringLiteral(
"ts" ), attr );
622 if ( mTupleSeparator.isEmpty() )
624 mTupleSeparator =
' ';
627 else if ( !mAttributeValIsNested && isGMLNS &&
630 mParseModeStack.push( QgsGmlStreamingParser::PosList );
631 mCoorMode = QgsGmlStreamingParser::PosList;
633 if ( elDimension == 0 )
635 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
637 const int dimension = srsDimension.toInt( &ok );
640 elDimension = dimension;
644 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
646 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
647 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
649 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
650 mFoundUnhandledGeometryElement =
false;
651 mGeometryString.clear();
654 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
656 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
658 mBoundedByNullFound =
false;
660 else if ( parseMode == BoundingBox &&
663 mParseModeStack.push( QgsGmlStreamingParser::Null );
664 mBoundedByNullFound =
true;
666 else if ( parseMode == BoundingBox &&
670 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
672 else if ( parseMode == Envelope &&
675 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
678 else if ( parseMode == Envelope &&
681 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
684 else if ( parseMode == None && !mTypeNamePtr &&
687 Q_ASSERT( !mCurrentFeature );
688 mCurrentFeature =
new QgsFeature( mFeatureCount );
690 const QgsAttributes attributes( mThematicAttributes.size() );
692 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
693 mCurrentFeatureId.clear();
695 else if ( parseMode == Tuple )
697 const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
698 const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
699 if ( iter != mMapTypeNameToProperties.constEnd() )
701 mFeatureTupleDepth = mParseDepth;
702 mCurrentTypename = currentTypename;
703 mGeometryAttribute.clear();
704 if ( mCurrentWKB.
size() == 0 )
706 mGeometryAttribute = iter.value().mGeometryAttribute;
708 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
709 mGeometryAttributePtr = mGeometryAttributeBA.constData();
710 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
711 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
713 if ( mGMLNameSpaceURI.isEmpty() )
715 id = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
723 id = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
732 id = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
733 if ( !mCurrentFeatureId.isEmpty() )
734 mCurrentFeatureId +=
'|';
735 mCurrentFeatureId += id;
738 else if ( parseMode == None &&
739 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
741 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
743 Q_ASSERT( !mCurrentFeature );
744 mCurrentFeature =
new QgsFeature( mFeatureCount );
746 const QgsAttributes attributes( mThematicAttributes.size() );
748 mParseModeStack.push( QgsGmlStreamingParser::Feature );
749 mCurrentXPathWithinFeature.clear();
750 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
751 if ( mCurrentFeatureId.isEmpty() )
756 if ( mGMLNameSpaceURI.isEmpty() )
758 mCurrentFeatureId = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
759 if ( !mCurrentFeatureId.isEmpty() )
766 mCurrentFeatureId = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
767 if ( !mCurrentFeatureId.isEmpty() )
775 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
779 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
783 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
787 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"LineString" ) )
791 else if ( !mAttributeValIsNested && isGMLNS &&
792 localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
795 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
797 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
800 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
802 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
807 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
809 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
814 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
816 else if ( parseMode == FeatureTuple )
818 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
819 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
821 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
822 mAttributeName = mCurrentTypename +
'|' + localName;
826 else if ( parseMode == Feature )
828 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
829 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
831 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
832 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
833 if ( !mCurrentXPathWithinFeature.isEmpty() )
834 mCurrentXPathWithinFeature.append(
'/' );
835 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
837 mCurrentXPathWithinFeature.append( *nsIter );
838 mCurrentXPathWithinFeature.append(
':' );
840 mCurrentXPathWithinFeature.append( localName );
841 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( mCurrentXPathWithinFeature );
842 mAttributeValIsNested =
false;
843 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
845 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
846 mAttributeDepth = mParseDepth;
847 mAttributeName = xpathIter->first;
848 mAttributeValIsNested = xpathIter->second;
849 if ( mAttributeValIsNested )
851 mAttributeJson = json::object();
852 mAttributeJsonCurrentStack.clear();
853 mAttributeJsonCurrentStack.push( &mAttributeJson );
858 else if ( mThematicAttributes.contains( localName ) )
860 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
861 mAttributeDepth = mParseDepth;
862 mAttributeName = localName;
869 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
871 const QString name = readAttribute( QStringLiteral(
"name" ), attr );
872 if ( mThematicAttributes.contains( name ) )
874 const QString value = readAttribute( QStringLiteral(
"value" ), attr );
875 setAttribute( name, value );
880 else if ( parseMode == Attribute && mAttributeValIsNested )
882 const std::string localName( pszLocalName, localNameLen );
883 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
884 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
885 const std::string nodeName = nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() ? ( *nsIter ).toStdString() +
':' + localName : localName;
887 addStringContentToJson();
889 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
890 auto iter = jsonParent.find( nodeName );
891 if ( iter != jsonParent.end() )
893 if ( iter->type() != json::value_t::array )
895 auto array = json::array();
896 array.emplace_back( std::move( *iter ) );
899 iter->push_back( json::object() );
900 mAttributeJsonCurrentStack.push( &( iter->back() ) );
904 auto res = jsonParent.emplace( nodeName, json::object() );
908 nlohmann::json *ptr = &( *( res.first ) );
910 mAttributeJsonCurrentStack.push( ptr );
915 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
917 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
921 mNumberReturned = -1;
923 const QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
931 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
936 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
941 mTruncatedResponse =
true;
943 else if ( !mGeometryString.empty() &&
959 mFoundUnhandledGeometryElement =
true;
963 if ( !mParseModeStack.isEmpty() &&
964 ( mParseModeStack.back() == Feature ||
965 mParseModeStack.back() == Attribute ) &&
966 !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
968 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
970 const char *questionMark = strchr( attrIter[0],
'?' );
974 const QString nsURI( QString::fromUtf8( attrIter[0],
static_cast<int>( questionMark - attrIter[0] ) ) );
975 const QString localName( QString::fromUtf8( questionMark + 1 ) );
976 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
977 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
979 key.append( *nsIter );
982 key.append( localName );
986 const QString localName( QString::fromUtf8( attrIter[0] ) );
987 key.append( localName );
990 if ( mAttributeValIsNested && mParseModeStack.back() == Attribute )
992 mAttributeJsonCurrentStack.top()->emplace(
994 jsonFromString( QString::fromUtf8( attrIter[1] ) ) );
998 QString xpath( mCurrentXPathWithinFeature );
999 if ( !xpath.isEmpty() )
1000 xpath.append(
'/' );
1001 xpath.append( key );
1002 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( xpath );
1003 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
1005 setAttribute( xpathIter->first, QString::fromUtf8( attrIter[1] ) );
1011 if ( !mGeometryString.empty() )
1014 if ( elDimension == 0 && isGeom )
1018 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
1020 const int dimension = srsDimension.toInt( &ok );
1023 elDimension = dimension;
1027 if ( elDimension != 0 || mDimensionStack.isEmpty() )
1029 mDimensionStack.push( elDimension );
1033 mDimensionStack.push( mDimensionStack.back() );
1036 if ( mEpsg == 0 && isGeom )
1038 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
1040 QgsDebugError( QStringLiteral(
"error, could not get epsg id" ) );
1051void QgsGmlStreamingParser::endElement(
const XML_Char *el )
1055 const int elLen =
static_cast<int>( strlen( el ) );
1056 const char *pszSep = strchr( el, NS_SEPARATOR );
1057 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
1058 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
1059 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
1060 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
1062 const int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
1064 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
1066 if ( parseMode == Feature || ( parseMode == Attribute && mAttributeDepth == mParseDepth ) )
1068 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
1070 const auto nPos = mCurrentXPathWithinFeature.lastIndexOf(
'/' );
1072 mCurrentXPathWithinFeature.clear();
1074 mCurrentXPathWithinFeature.resize( nPos );
1078 if ( parseMode == Attribute && mAttributeValIsNested )
1080 if ( !mStringCash.isEmpty() )
1082 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1083 if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
1085 jsonParent = jsonFromString( mStringCash );
1087 else if ( jsonParent.type() == json::value_t::object )
1089 addStringContentToJson();
1091 mStringCash.clear();
1094 mAttributeJsonCurrentStack.pop();
1097 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
1099 mParseModeStack.pop();
1101 else if ( parseMode == PosList && isGMLNS &&
1104 mDimension = lastDimension;
1105 mParseModeStack.pop();
1107 else if ( parseMode == AttributeTuple &&
1108 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
1110 mParseModeStack.pop();
1112 setAttribute( mAttributeName, mStringCash );
1114 else if ( parseMode == Attribute && mAttributeDepth == mParseDepth )
1116 mParseModeStack.pop();
1119 if ( mAttributeValIsNested )
1121 mAttributeValIsNested =
false;
1122 auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
1123 if ( iter == mMapFieldNameToJSONContent.end() )
1125 mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
1129 QString &
str = iter.value();
1130 if (
str[0] ==
'[' &&
str.back() ==
']' )
1136 str.insert( 0,
'[' );
1139 str.append( QString::fromStdString( mAttributeJson.dump() ) );
1145 setAttribute( mAttributeName, mStringCash );
1148 else if ( parseMode == Geometry &&
1149 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
1150 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1152 mParseModeStack.pop();
1153 if ( mFoundUnhandledGeometryElement )
1159 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
1160 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
1161 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
1163 g.
fromWkb( pabyBuffer, wkbSize );
1164 if ( mInvertAxisOrientation )
1166 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1168 Q_ASSERT( mCurrentFeature );
1172 mGeometryString.clear();
1174 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
1177 if ( mCurrentExtent.
isNull() &&
1178 !mBoundedByNullFound &&
1179 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
1181 QgsDebugError( QStringLiteral(
"creation of bounding box failed" ) );
1183 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
1184 !mCurrentFeature && mFeatureCount == 0 )
1186 mLayerExtent = mCurrentExtent;
1190 mParseModeStack.pop();
1194 mParseModeStack.pop();
1196 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
1198 mParseModeStack.pop();
1200 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
1202 QList<QgsPointXY> points;
1203 pointsFromPosListString( points, mStringCash, 2 );
1204 if ( points.size() == 1 )
1209 mParseModeStack.pop();
1211 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
1213 QList<QgsPointXY> points;
1214 pointsFromPosListString( points, mStringCash, 2 );
1215 if ( points.size() == 1 )
1220 mParseModeStack.pop();
1222 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
1224 mParseModeStack.pop();
1225 mFeatureTupleDepth = 0;
1227 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
1229 ( parseMode == Feature &&
1230 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
1231 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
1233 Q_ASSERT( mCurrentFeature );
1236 if ( mCurrentWKB.
size() > 0 )
1243 else if ( !mCurrentExtent.
isEmpty() )
1250 for (
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
1252 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
1253 const int attrIndex = att_it.value().first;
1254 mCurrentFeature->
setAttribute( attrIndex, iter.value() );
1256 mMapFieldNameToJSONContent.clear();
1260 mCurrentFeature =
nullptr;
1262 mParseModeStack.pop();
1264 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
1266 QList<QgsPointXY> pointList;
1267 if ( pointsFromString( pointList, mStringCash ) != 0 )
1272 if ( pointList.isEmpty() )
1275 if ( parseMode == QgsGmlStreamingParser::Geometry )
1278 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
1291 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
1295 if ( !mCurrentWKBFragments.isEmpty() )
1297 mCurrentWKBFragments.last().push_back( wkbPtr );
1306 else if ( !mAttributeValIsNested &&
1311 QList<QgsPointXY> pointList;
1312 if ( pointsFromString( pointList, mStringCash ) != 0 )
1316 if ( parseMode == QgsGmlStreamingParser::Geometry )
1318 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
1331 if ( getLineWKB( wkbPtr, pointList ) != 0 )
1335 if ( !mCurrentWKBFragments.isEmpty() )
1337 mCurrentWKBFragments.last().push_back( wkbPtr );
1346 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1349 QList<QgsPointXY> pointList;
1350 if ( pointsFromString( pointList, mStringCash ) != 0 )
1356 if ( getRingWKB( wkbPtr, pointList ) != 0 )
1361 if ( !mCurrentWKBFragments.isEmpty() )
1363 mCurrentWKBFragments.last().push_back( wkbPtr );
1371 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1379 if ( parseMode == Geometry )
1381 createPolygonFromFragments();
1384 else if ( parseMode == MultiPoint && isGMLNS &&
1388 mParseModeStack.pop();
1389 createMultiPointFromFragments();
1391 else if ( parseMode == MultiLine && isGMLNS &&
1395 mParseModeStack.pop();
1396 createMultiLineFromFragments();
1398 else if ( parseMode == MultiPolygon && isGMLNS &&
1402 mParseModeStack.pop();
1403 createMultiPolygonFromFragments();
1407 mParseModeStack.pop();
1409 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1411 mExceptionText = mStringCash;
1412 mParseModeStack.pop();
1415 if ( !mGeometryString.empty() )
1417 mGeometryString.append(
"</", 2 );
1418 mGeometryString.append( pszLocalName, localNameLen );
1419 mGeometryString.append(
">", 1 );
1424void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1427 if ( mParseModeStack.isEmpty() )
1432 if ( !mGeometryString.empty() )
1434 mGeometryString.append( chars, len );
1437 const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1438 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1439 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1440 parseMode == QgsGmlStreamingParser::Coordinate ||
1441 parseMode == QgsGmlStreamingParser::PosList ||
1442 parseMode == QgsGmlStreamingParser::LowerCorner ||
1443 parseMode == QgsGmlStreamingParser::UpperCorner ||
1444 parseMode == QgsGmlStreamingParser::ExceptionText )
1446 mStringCash.append( QString::fromUtf8( chars, len ) );
1450void QgsGmlStreamingParser::addStringContentToJson()
1452 const QString s( mStringCash.trimmed() );
1455 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1456 auto textIter = jsonParent.find(
"_text" );
1457 if ( textIter != jsonParent.end() )
1459 if ( textIter->type() != json::value_t::array )
1461 auto array = json::array();
1462 array.emplace_back( std::move( *textIter ) );
1465 textIter->emplace_back( jsonFromString( s ) );
1469 jsonParent.emplace(
"_text", jsonFromString( s ) );
1472 mStringCash.clear();
1475void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1478 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1479 bool conversionOk =
true;
1480 if ( att_it != mThematicAttributes.constEnd() )
1483 switch ( att_it.value().second.type() )
1485 case QMetaType::Type::Double:
1486 var = QVariant( value.toDouble( &conversionOk ) );
1488 case QMetaType::Type::Int:
1489 var = QVariant( value.toInt( &conversionOk ) );
1491 case QMetaType::Type::LongLong:
1492 var = QVariant( value.toLongLong( &conversionOk ) );
1494 case QMetaType::Type::QDateTime:
1495 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1498 var = QVariant( value );
1501 if ( ! conversionOk )
1505 Q_ASSERT( mCurrentFeature );
1506 mCurrentFeature->
setAttribute( att_it.value().first, var );
1510int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1515 if ( strcmp( attr[i],
"srsName" ) == 0 )
1517 const QString
srsName( attr[i + 1] );
1529 const int eNr = code.toInt( &conversionOk );
1530 if ( !conversionOk )
1543 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1554QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1559 if ( attributeName.compare( attr[i] ) == 0 )
1561 return QString::fromUtf8( attr[i + 1] );
1568bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1570 QList<QgsPointXY> points;
1571 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1576 if ( points.size() < 2 )
1581 r.
set( points[0], points[1] );
1586int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const
1589 const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1590 QStringList tuples_coordinates;
1592 bool conversionSuccess;
1594 QStringList::const_iterator tupleIterator;
1595 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1597 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1598 if ( tuples_coordinates.size() < 2 )
1602 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1603 if ( !conversionSuccess )
1607 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1608 if ( !conversionSuccess )
1617int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const
1620 const QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1622 if ( coordinates.size() % dimension != 0 )
1624 QgsDebugError( QStringLiteral(
"Wrong number of coordinates" ) );
1627 const int ncoor = coordinates.size() / dimension;
1628 for (
int i = 0; i < ncoor; i++ )
1630 bool conversionSuccess;
1631 const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1632 if ( !conversionSuccess )
1636 const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1637 if ( !conversionSuccess )
1646int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const
1648 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1650 return pointsFromCoordinateString( points, coordString );
1652 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1654 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1661 const int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1662 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1670int QgsGmlStreamingParser::getLineWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const
1672 const int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1673 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1679 QList<QgsPointXY>::const_iterator iter;
1680 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1682 fillPtr << iter->x() << iter->y();
1688int QgsGmlStreamingParser::getRingWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const
1690 const int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1691 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1695 fillPtr << ringCoordinates.size();
1697 QList<QgsPointXY>::const_iterator iter;
1698 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1700 fillPtr << iter->x() << iter->y();
1706int QgsGmlStreamingParser::createMultiLineFromFragments()
1708 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1709 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1716 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1717 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1719 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1720 wkbPtr += wkbIt->
size();
1724 mCurrentWKBFragments.clear();
1729int QgsGmlStreamingParser::createMultiPointFromFragments()
1731 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1732 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1737 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1738 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1740 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1741 wkbPtr += wkbIt->
size();
1745 mCurrentWKBFragments.clear();
1751int QgsGmlStreamingParser::createPolygonFromFragments()
1753 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1754 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1759 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1760 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1762 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1763 wkbPtr += wkbIt->
size();
1767 mCurrentWKBFragments.clear();
1772int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1775 size += 1 + 2 *
sizeof( int );
1776 size += totalWKBFragmentSize();
1777 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1779 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1785 QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
1787 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1792 QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
1793 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1795 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1796 wkbPtr += innerWkbIt->
size();
1797 delete[] *innerWkbIt;
1801 mCurrentWKBFragments.clear();
1806int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1809 const auto constMCurrentWKBFragments = mCurrentWKBFragments;
1810 for (
const QList<QgsWkbPtr> &list : constMCurrentWKBFragments )
1812 const auto constList = list;
1821void QgsGmlStreamingParser::createParser(
const QByteArray &encoding )
1823 Q_ASSERT( !mParser );
1825 mParser = XML_ParserCreateNS( encoding.isEmpty() ?
nullptr : encoding.data(), NS_SEPARATOR );
1826 XML_SetUserData( mParser,
this );
1827 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
1828 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