16#include "moc_qgsgml.cpp"
31#include <QNetworkRequest>
32#include <QNetworkReply>
33#include <QProgressDialog>
38#include <QRegularExpression>
44using namespace nlohmann;
46#ifndef NS_SEPARATOR_DEFINED
47#define NS_SEPARATOR_DEFINED
48static const char NS_SEPARATOR =
'?';
51static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
56 const QString &geometryAttribute,
58 : mParser(
typeName, geometryAttribute, fields )
62 const int index = mTypeName.indexOf(
':' );
63 if ( index != -1 && index < mTypeName.length() )
65 mTypeName = mTypeName.mid( index + 1 );
74 QNetworkRequest request( uri );
77 if ( !authcfg.isEmpty() )
82 tr(
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
89 else if ( !userName.isNull() || !password.isNull() )
91 request.setRawHeader(
"Authorization",
"Basic " + QStringLiteral(
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
95 if ( !authcfg.isEmpty() )
101 tr(
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
109 connect( reply, &QNetworkReply::finished,
this, &QgsGml::setFinished );
110 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsGml::handleProgressEvent );
113 QProgressDialog *progressDialog =
nullptr;
114 QWidget *mainWindow =
nullptr;
115 const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
116 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
118 if ( ( *it )->objectName() == QLatin1String(
"QgisApp" ) )
126 progressDialog =
new QProgressDialog( tr(
"Loading GML data\n%1" ).arg( mTypeName ), tr(
"Abort" ), 0, 0, mainWindow );
127 progressDialog->setWindowModality( Qt::ApplicationModal );
130 connect( progressDialog, &QProgressDialog::canceled,
this, &QgsGml::setFinished );
131 progressDialog->show();
141 const QByteArray readData = reply->readAll();
142 if ( !readData.isEmpty() )
145 if ( !mParser.
processData( readData, atEnd, errorMsg ) )
149 QCoreApplication::processEvents();
152 fillMapsFromParser();
154 const QNetworkReply::NetworkError replyError = reply->error();
155 const QString replyErrorString = reply->errorString();
158 delete progressDialog;
163 tr(
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
177 calculateExtentFromFeatures();
192 if ( !mParser.
processData( data,
true , errorMsg ) )
195 fillMapsFromParser();
205void QgsGml::fillMapsFromParser()
208 const auto constFeatures = features;
212 const QString &gmlId = featPair.second;
213 mFeatures.insert( feat->
id(), feat );
214 if ( !gmlId.isEmpty() )
216 mIdMap.insert( feat->
id(), gmlId );
221void QgsGml::setFinished()
226void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
228 if ( totalSteps < 0 )
238void QgsGml::calculateExtentFromFeatures()
240 if ( mFeatures.empty() )
247 bool bboxInitialized =
false;
249 for (
int i = 0; i < mFeatures.size(); ++i )
251 currentFeature = mFeatures[i];
252 if ( !currentFeature )
256 currentGeometry = currentFeature->
geometry();
257 if ( !currentGeometry.
isNull() )
259 if ( !bboxInitialized )
262 bboxInitialized =
true;
287 const QString &geometryAttribute,
290 bool invertAxisOrientation )
292 , mTypeNameBA( mTypeName.toUtf8() )
293 , mTypeNamePtr( mTypeNameBA.constData() )
294 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
295 , mWkbType(
Qgis::WkbType::Unknown )
296 , mGeometryAttribute( geometryAttribute )
297 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
298 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
299 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
301 , mIsException( false )
302 , mTruncatedResponse( false )
304 , mFeatureTupleDepth( 0 )
306 , mCurrentWKB( nullptr, 0 )
307 , mBoundedByNullFound( false )
309 , mCoorMode( Coordinate )
311 , mAxisOrientationLogic( axisOrientationLogic )
312 , mInvertAxisOrientationRequest( invertAxisOrientation )
313 , mInvertAxisOrientation( invertAxisOrientation )
314 , mNumberReturned( -1 )
315 , mNumberMatched( -1 )
316 , mFoundUnhandledGeometryElement( false )
318 mThematicAttributes.clear();
319 for (
int i = 0; i < fields.
size(); i++ )
321 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
326 const int index = mTypeName.indexOf(
':' );
327 if ( index != -1 && index < mTypeName.length() )
329 mTypeName = mTypeName.mid( index + 1 );
330 mTypeNameBA = mTypeName.toUtf8();
331 mTypeNamePtr = mTypeNameBA.constData();
332 mTypeNameUTF8Len = strlen( mTypeNamePtr );
338static QString stripNS(
const QString &
string )
340 const int index =
string.indexOf(
':' );
341 if ( index != -1 && index <
string.length() )
343 return string.mid( index + 1 );
350 const QMap< QString, QPair<QString, QString> > &fieldNameToSrcLayerNameFieldNameMap,
352 bool invertAxisOrientation )
353 : mLayerProperties( layerProperties )
354 , mTypeNameUTF8Len( 0 )
355 , mWkbType(
Qgis::WkbType::Unknown )
356 , mGeometryAttributeUTF8Len( 0 )
358 , mIsException( false )
359 , mTruncatedResponse( false )
361 , mFeatureTupleDepth( 0 )
363 , mCurrentWKB( nullptr, 0 )
364 , mBoundedByNullFound( false )
366 , mCoorMode( Coordinate )
368 , mAxisOrientationLogic( axisOrientationLogic )
369 , mInvertAxisOrientationRequest( invertAxisOrientation )
370 , mInvertAxisOrientation( invertAxisOrientation )
371 , mNumberReturned( -1 )
372 , mNumberMatched( -1 )
373 , mFoundUnhandledGeometryElement( false )
375 mThematicAttributes.clear();
376 for (
int i = 0; i < fields.
size(); i++ )
378 const QMap< QString, QPair<QString, QString> >::const_iterator att_it = fieldNameToSrcLayerNameFieldNameMap.constFind( fields.
at( i ).
name() );
379 if ( att_it != fieldNameToSrcLayerNameFieldNameMap.constEnd() )
381 if ( mLayerProperties.size() == 1 )
382 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
384 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
387 bool alreadyFoundGeometry =
false;
388 for (
int i = 0; i < mLayerProperties.size(); i++ )
391 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
393 if ( alreadyFoundGeometry )
395 QgsDebugMsgLevel( QStringLiteral(
"Will ignore geometry field %1 from typename %2" ).
396 arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ), 2 );
397 mLayerProperties[i].mGeometryAttribute.clear();
399 alreadyFoundGeometry =
true;
401 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
404 if ( mLayerProperties.size() == 1 )
406 mTypeName = mLayerProperties[0].mName;
407 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
408 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
409 mGeometryAttributePtr = mGeometryAttributeBA.constData();
410 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
411 const int index = mTypeName.indexOf(
':' );
412 if ( index != -1 && index < mTypeName.length() )
414 mTypeName = mTypeName.mid( index + 1 );
416 mTypeNameBA = mTypeName.toUtf8();
417 mTypeNamePtr = mTypeNameBA.constData();
418 mTypeNameUTF8Len = strlen( mTypeNamePtr );
428 const QMap<QString, QPair<QString, bool>> &fieldNameToXPathMapAndIsNestedContent,
429 const QMap<QString, QString> &mapNamespacePrefixToURI )
431 for (
auto iter = fieldNameToXPathMapAndIsNestedContent.constBegin(); iter != fieldNameToXPathMapAndIsNestedContent.constEnd(); ++iter )
433 mMapXPathToFieldNameAndIsNestedContent[iter.value().first] = QPair<QString, bool>( iter.key(), iter.value().second );
435 for (
auto iter = mapNamespacePrefixToURI.constBegin(); iter != mapNamespacePrefixToURI.constEnd(); ++iter )
436 mMapNamespaceURIToNamespacePrefix[iter.value()] = iter.key();
442 XML_ParserFree( mParser );
445 const auto constMFeatureList = mFeatureList;
448 delete featPair.first;
451 delete mCurrentFeature;
467 QByteArray data = pdata;
472 QString strData = mCodec->toUnicode( pdata );
473 data = strData.toUtf8();
476 if ( XML_Parse( mParser, data, data.size(), atEnd ) == XML_STATUS_ERROR )
478 const XML_Error errorCode = XML_GetErrorCode( mParser );
479 if ( !mCodec && errorCode == XML_ERROR_UNKNOWN_ENCODING )
483 const thread_local QRegularExpression reEncoding( QStringLiteral(
"<?xml.*encoding=['\"]([^'\"]*)['\"].*?>" ),
484 QRegularExpression::CaseInsensitiveOption );
485 QRegularExpressionMatch match = reEncoding.match( pdata );
486 const QString encoding = match.hasMatch() ? match.captured( 1 ) : QString();
487 mCodec = !encoding.isEmpty() ? QTextCodec::codecForName( encoding.toLatin1() ) :
nullptr;
491 XML_ParserFree( mParser );
493 createParser( QByteArrayLiteral(
"UTF-8" ) );
499 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" )
500 .arg( XML_ErrorString( errorCode ) )
501 .arg( XML_GetCurrentLineNumber( mParser ) )
502 .arg( XML_GetCurrentColumnNumber( mParser ) );
512 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
513 mFeatureList.clear();
521static json jsonFromString(
const QString &s )
526 if ( s.indexOf(
'.' ) >= 0 || s.indexOf(
'e' ) >= 0 )
528 const auto doubleVal = s.toDouble( &conversionOk );
531 return json( doubleVal );
536 else if ( !s.isEmpty() && s[0] !=
'0' )
538 const auto longlongVal = s.toLongLong( &conversionOk );
541 return json( longlongVal );
545 return json( s.toStdString() );
548#define LOCALNAME_EQUALS(string_constant) \
549 ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 )
548#define LOCALNAME_EQUALS(string_constant) \ …
551void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
553 const int elLen =
static_cast<int>( strlen( el ) );
554 const char *pszSep = strchr( el, NS_SEPARATOR );
555 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
556 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
557 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
558 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
562 if ( !mGMLNameSpaceURIPtr && pszSep )
576 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
579 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
580 parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
582 mGeometryString.append(
"<", 1 );
583 mGeometryString.append( pszLocalName, localNameLen );
584 mGeometryString.append(
" ", 1 );
585 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
587 const size_t nAttrLen = strlen( attrIter[0] );
590 if ( nAttrLen > GML32_NAMESPACE_LEN &&
591 attrIter[0][GML32_NAMESPACE_LEN] ==
'?' &&
594 mGeometryString.append(
"gml:" );
595 mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
597 else if ( nAttrLen > GML_NAMESPACE_LEN &&
598 attrIter[0][GML_NAMESPACE_LEN] ==
'?' &&
599 memcmp( attrIter[0],
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
601 mGeometryString.append(
"gml:" );
602 mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
606 mGeometryString.append( attrIter[0] );
608 mGeometryString.append(
"=\"", 2 );
609 mGeometryString.append( attrIter[1] );
610 mGeometryString.append(
"\" ", 2 );
613 mGeometryString.append(
">", 1 );
616 if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
618 mParseModeStack.push( Coordinate );
619 mCoorMode = QgsGmlStreamingParser::Coordinate;
621 mCoordinateSeparator = readAttribute( QStringLiteral(
"cs" ), attr );
622 if ( mCoordinateSeparator.isEmpty() )
624 mCoordinateSeparator =
',';
626 mTupleSeparator = readAttribute( QStringLiteral(
"ts" ), attr );
627 if ( mTupleSeparator.isEmpty() )
629 mTupleSeparator =
' ';
632 else if ( !mAttributeValIsNested && isGMLNS &&
635 mParseModeStack.push( QgsGmlStreamingParser::PosList );
636 if ( mCoorMode == QgsGmlStreamingParser::PosList )
638 if ( !mStringCash.isEmpty() )
640 mStringCash.append( QLatin1Char(
' ' ) );
647 mCoorMode = QgsGmlStreamingParser::PosList;
648 if ( elDimension == 0 )
650 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
652 const int dimension = srsDimension.toInt( &ok );
655 elDimension = dimension;
659 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
661 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
662 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
664 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
665 mFoundUnhandledGeometryElement =
false;
666 mGeometryString.clear();
670 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
672 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
674 mBoundedByNullFound =
false;
676 else if ( parseMode == BoundingBox &&
679 mParseModeStack.push( QgsGmlStreamingParser::Null );
680 mBoundedByNullFound =
true;
682 else if ( parseMode == BoundingBox &&
686 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
688 else if ( parseMode == Envelope &&
691 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
694 else if ( parseMode == Envelope &&
697 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
700 else if ( parseMode == None && !mTypeNamePtr &&
703 Q_ASSERT( !mCurrentFeature );
704 mCurrentFeature =
new QgsFeature( mFeatureCount );
706 const QgsAttributes attributes( mThematicAttributes.size() );
708 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
709 mCurrentFeatureId.clear();
711 else if ( parseMode == Tuple )
713 const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
714 const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
715 if ( iter != mMapTypeNameToProperties.constEnd() )
717 mFeatureTupleDepth = mParseDepth;
718 mCurrentTypename = currentTypename;
719 mGeometryAttribute.clear();
720 if ( mCurrentWKB.size() == 0 )
722 mGeometryAttribute = iter.value().mGeometryAttribute;
724 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
725 mGeometryAttributePtr = mGeometryAttributeBA.constData();
726 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
727 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
729 if ( mGMLNameSpaceURI.isEmpty() )
731 id = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
739 id = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
748 id = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
749 if ( !mCurrentFeatureId.isEmpty() )
750 mCurrentFeatureId +=
'|';
751 mCurrentFeatureId += id;
754 else if ( parseMode == None &&
755 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
757 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
759 Q_ASSERT( !mCurrentFeature );
760 mCurrentFeature =
new QgsFeature( mFeatureCount );
762 const QgsAttributes attributes( mThematicAttributes.size() );
764 mParseModeStack.push( QgsGmlStreamingParser::Feature );
765 mCurrentXPathWithinFeature.clear();
766 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
767 if ( mCurrentFeatureId.isEmpty() )
772 if ( mGMLNameSpaceURI.isEmpty() )
774 mCurrentFeatureId = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
775 if ( !mCurrentFeatureId.isEmpty() )
782 mCurrentFeatureId = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
783 if ( !mCurrentFeatureId.isEmpty() )
791 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
795 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
799 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
803 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"LineString" ) )
807 else if ( !mAttributeValIsNested && isGMLNS &&
808 localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
811 mCurrentWKBFragments.push_back( QList<QByteArray>() );
813 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
816 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
818 mCurrentWKBFragments.push_back( QList<QByteArray>() );
823 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
825 mCurrentWKBFragments.push_back( QList<QByteArray>() );
830 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
832 else if ( parseMode == FeatureTuple )
834 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
835 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
837 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
838 mAttributeName = mCurrentTypename +
'|' + localName;
842 else if ( parseMode == Feature )
844 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
845 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
847 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
848 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
849 if ( !mCurrentXPathWithinFeature.isEmpty() )
850 mCurrentXPathWithinFeature.append(
'/' );
851 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
853 mCurrentXPathWithinFeature.append( *nsIter );
854 mCurrentXPathWithinFeature.append(
':' );
856 mCurrentXPathWithinFeature.append( localName );
857 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( mCurrentXPathWithinFeature );
858 mAttributeValIsNested =
false;
859 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
861 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
862 mAttributeDepth = mParseDepth;
863 mAttributeName = xpathIter->first;
864 mAttributeValIsNested = xpathIter->second;
865 if ( mAttributeValIsNested )
867 mAttributeJson = json::object();
868 mAttributeJsonCurrentStack.clear();
869 mAttributeJsonCurrentStack.push( &mAttributeJson );
874 else if ( mThematicAttributes.contains( localName ) )
876 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
877 mAttributeDepth = mParseDepth;
878 mAttributeName = localName;
885 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
887 const QString name = readAttribute( QStringLiteral(
"name" ), attr );
888 if ( mThematicAttributes.contains( name ) )
890 const QString value = readAttribute( QStringLiteral(
"value" ), attr );
891 setAttribute( name, value );
896 else if ( parseMode == Attribute && mAttributeValIsNested )
898 const std::string localName( pszLocalName, localNameLen );
899 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
900 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
901 const std::string nodeName = nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() ? ( *nsIter ).toStdString() +
':' + localName : localName;
903 addStringContentToJson();
905 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
906 auto iter = jsonParent.find( nodeName );
907 if ( iter != jsonParent.end() )
909 if ( iter->type() != json::value_t::array )
911 auto array = json::array();
912 array.emplace_back( std::move( *iter ) );
915 iter->push_back( json::object() );
916 mAttributeJsonCurrentStack.push( &( iter->back() ) );
920 auto res = jsonParent.emplace( nodeName, json::object() );
924 nlohmann::json *ptr = &( *( res.first ) );
926 mAttributeJsonCurrentStack.push( ptr );
931 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
933 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
937 mNumberReturned = -1;
939 const QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
947 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
952 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
957 mTruncatedResponse =
true;
959 else if ( !mGeometryString.empty() &&
975 mFoundUnhandledGeometryElement =
true;
979 if ( !mParseModeStack.isEmpty() &&
980 ( mParseModeStack.back() == Feature ||
981 mParseModeStack.back() == Attribute ) &&
982 !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
984 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
986 const char *questionMark = strchr( attrIter[0],
'?' );
990 const QString nsURI( QString::fromUtf8( attrIter[0],
static_cast<int>( questionMark - attrIter[0] ) ) );
991 const QString localName( QString::fromUtf8( questionMark + 1 ) );
992 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
993 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
995 key.append( *nsIter );
998 key.append( localName );
1002 const QString localName( QString::fromUtf8( attrIter[0] ) );
1003 key.append( localName );
1006 if ( mAttributeValIsNested && mParseModeStack.back() == Attribute )
1008 mAttributeJsonCurrentStack.top()->emplace(
1010 jsonFromString( QString::fromUtf8( attrIter[1] ) ) );
1014 QString xpath( mCurrentXPathWithinFeature );
1015 if ( !xpath.isEmpty() )
1016 xpath.append(
'/' );
1017 xpath.append( key );
1018 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( xpath );
1019 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
1021 setAttribute( xpathIter->first, QString::fromUtf8( attrIter[1] ) );
1027 if ( !mGeometryString.empty() )
1030 if ( elDimension == 0 && isGeom )
1034 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
1036 const int dimension = srsDimension.toInt( &ok );
1039 elDimension = dimension;
1043 if ( elDimension != 0 || mDimensionStack.isEmpty() )
1045 mDimensionStack.push( elDimension );
1049 mDimensionStack.push( mDimensionStack.back() );
1052 if ( mEpsg == 0 && isGeom )
1054 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
1056 QgsDebugError( QStringLiteral(
"error, could not get epsg id" ) );
1067void QgsGmlStreamingParser::endElement(
const XML_Char *el )
1071 const int elLen =
static_cast<int>( strlen( el ) );
1072 const char *pszSep = strchr( el, NS_SEPARATOR );
1073 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
1074 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
1075 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
1076 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
1078 const int lastDimension = mDimensionStack.isEmpty() ? 2 : mDimensionStack.pop();
1080 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
1082 if ( parseMode == Feature || ( parseMode == Attribute && mAttributeDepth == mParseDepth ) )
1084 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
1086 const auto nPos = mCurrentXPathWithinFeature.lastIndexOf(
'/' );
1088 mCurrentXPathWithinFeature.clear();
1090 mCurrentXPathWithinFeature.resize( nPos );
1094 if ( parseMode == Attribute && mAttributeValIsNested )
1096 if ( !mStringCash.isEmpty() )
1098 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1099 if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
1101 jsonParent = jsonFromString( mStringCash );
1103 else if ( jsonParent.type() == json::value_t::object )
1105 addStringContentToJson();
1107 mStringCash.clear();
1110 mAttributeJsonCurrentStack.pop();
1113 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
1115 mParseModeStack.pop();
1117 else if ( parseMode == PosList && isGMLNS &&
1120 mDimension = lastDimension;
1121 mParseModeStack.pop();
1123 else if ( parseMode == AttributeTuple &&
1124 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
1126 mParseModeStack.pop();
1128 setAttribute( mAttributeName, mStringCash );
1130 else if ( parseMode == Attribute && mAttributeDepth == mParseDepth )
1132 mParseModeStack.pop();
1135 if ( mAttributeValIsNested )
1137 mAttributeValIsNested =
false;
1138 auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
1139 if ( iter == mMapFieldNameToJSONContent.end() )
1141 mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
1145 QString &str = iter.value();
1146 if ( str[0] ==
'[' && str.back() ==
']' )
1152 str.insert( 0,
'[' );
1155 str.append( QString::fromStdString( mAttributeJson.dump() ) );
1161 setAttribute( mAttributeName, mStringCash );
1164 else if ( parseMode == Geometry &&
1165 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
1166 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1168 mParseModeStack.pop();
1169 if ( mFoundUnhandledGeometryElement )
1175 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
1176 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
1177 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
1179 g.
fromWkb( pabyBuffer, wkbSize );
1180 if ( mInvertAxisOrientation )
1182 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1184 Q_ASSERT( mCurrentFeature );
1188 mGeometryString.clear();
1190 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
1193 if ( mCurrentExtent.
isNull() &&
1194 !mBoundedByNullFound &&
1195 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
1197 QgsDebugError( QStringLiteral(
"creation of bounding box failed" ) );
1199 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
1200 !mCurrentFeature && mFeatureCount == 0 )
1202 mLayerExtent = mCurrentExtent;
1206 mParseModeStack.pop();
1210 mParseModeStack.pop();
1212 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
1214 mParseModeStack.pop();
1216 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
1218 QList<QgsPoint> points;
1219 pointsFromPosListString( points, mStringCash, 2 );
1220 if ( points.size() == 1 )
1225 mParseModeStack.pop();
1227 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
1229 QList<QgsPoint> points;
1230 pointsFromPosListString( points, mStringCash, 2 );
1231 if ( points.size() == 1 )
1236 mParseModeStack.pop();
1238 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
1240 mParseModeStack.pop();
1241 mFeatureTupleDepth = 0;
1243 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
1245 ( parseMode == Feature &&
1246 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
1247 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
1249 Q_ASSERT( mCurrentFeature );
1252 if ( mCurrentWKB.size() > 0 )
1257 mCurrentWKB = QByteArray();
1259 else if ( !mCurrentExtent.
isEmpty() )
1266 for (
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
1268 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
1269 const int attrIndex = att_it.value().first;
1270 mCurrentFeature->
setAttribute( attrIndex, iter.value() );
1272 mMapFieldNameToJSONContent.clear();
1276 mCurrentFeature =
nullptr;
1278 mParseModeStack.pop();
1280 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
1282 QList<QgsPoint> pointList;
1284 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1288 mStringCash.clear();
1289 mDimension = dimension;
1291 if ( pointList.isEmpty() )
1294 if ( parseMode == QgsGmlStreamingParser::Geometry )
1297 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ), dimension ) != 0 )
1311 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ), dimension ) != 0 )
1315 if ( !mCurrentWKBFragments.isEmpty() )
1317 mCurrentWKBFragments.last().push_back( wkbPtr );
1325 else if ( !mAttributeValIsNested &&
1330 QList<QgsPoint> pointList;
1332 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1336 mStringCash.clear();
1337 mDimension = dimension;
1339 if ( parseMode == QgsGmlStreamingParser::Geometry )
1341 if ( getLineWKB( mCurrentWKB, pointList, dimension ) != 0 )
1350 else if ( dimension > 2 )
1354 mDimension = dimension;
1359 if ( getLineWKB( wkbPtr, pointList, dimension ) != 0 )
1363 mDimension = dimension;
1364 if ( !mCurrentWKBFragments.isEmpty() )
1366 mCurrentWKBFragments.last().push_back( wkbPtr );
1374 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1377 QList<QgsPoint> pointList;
1379 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1383 mStringCash.clear();
1384 mDimension = dimension;
1387 if ( getRingWKB( wkbPtr, pointList, dimension ) != 0 )
1392 if ( !mCurrentWKBFragments.isEmpty() )
1394 mCurrentWKBFragments.last().push_back( wkbPtr );
1401 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1409 if ( parseMode == Geometry )
1411 createPolygonFromFragments();
1414 else if ( parseMode == MultiPoint && isGMLNS &&
1418 mParseModeStack.pop();
1419 createMultiPointFromFragments();
1421 else if ( parseMode == MultiLine && isGMLNS &&
1425 mParseModeStack.pop();
1426 createMultiLineFromFragments();
1428 else if ( parseMode == MultiPolygon && isGMLNS &&
1432 mParseModeStack.pop();
1433 createMultiPolygonFromFragments();
1437 mParseModeStack.pop();
1439 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1441 mExceptionText = mStringCash;
1442 mParseModeStack.pop();
1445 if ( !mGeometryString.empty() )
1447 mGeometryString.append(
"</", 2 );
1448 mGeometryString.append( pszLocalName, localNameLen );
1449 mGeometryString.append(
">", 1 );
1454void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1457 if ( mParseModeStack.isEmpty() )
1462 if ( !mGeometryString.empty() )
1464 mGeometryString.append( chars, len );
1467 const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1468 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1469 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1470 parseMode == QgsGmlStreamingParser::Coordinate ||
1471 parseMode == QgsGmlStreamingParser::PosList ||
1472 parseMode == QgsGmlStreamingParser::LowerCorner ||
1473 parseMode == QgsGmlStreamingParser::UpperCorner ||
1474 parseMode == QgsGmlStreamingParser::ExceptionText )
1476 mStringCash.append( QString::fromUtf8( chars, len ) );
1480void QgsGmlStreamingParser::addStringContentToJson()
1482 const QString s( mStringCash.trimmed() );
1485 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1486 auto textIter = jsonParent.find(
"_text" );
1487 if ( textIter != jsonParent.end() )
1489 if ( textIter->type() != json::value_t::array )
1491 auto array = json::array();
1492 array.emplace_back( std::move( *textIter ) );
1495 textIter->emplace_back( jsonFromString( s ) );
1499 jsonParent.emplace(
"_text", jsonFromString( s ) );
1502 mStringCash.clear();
1505void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1508 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1509 bool conversionOk =
true;
1510 if ( att_it != mThematicAttributes.constEnd() )
1513 switch ( att_it.value().second.type() )
1515 case QMetaType::Type::Double:
1516 var = QVariant( value.toDouble( &conversionOk ) );
1518 case QMetaType::Type::Int:
1519 var = QVariant( value.toInt( &conversionOk ) );
1521 case QMetaType::Type::LongLong:
1522 var = QVariant( value.toLongLong( &conversionOk ) );
1524 case QMetaType::Type::QDateTime:
1525 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1528 var = QVariant( value );
1531 if ( ! conversionOk )
1535 Q_ASSERT( mCurrentFeature );
1536 mCurrentFeature->
setAttribute( att_it.value().first, var );
1540int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1545 if ( strcmp( attr[i],
"srsName" ) == 0 )
1547 const QString
srsName( attr[i + 1] );
1559 const int eNr = code.toInt( &conversionOk );
1560 if ( !conversionOk )
1573 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1584QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1589 if ( attributeName.compare( attr[i] ) == 0 )
1591 return QString::fromUtf8( attr[i + 1] );
1598bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1600 QList<QgsPoint> points;
1601 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1606 if ( points.size() < 2 )
1611 r.
set( points[0], points[1] );
1616int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPoint> &points,
const QString &coordString,
int *dimension )
const
1619 const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1620 QStringList tuples_coordinates;
1622 bool conversionSuccess;
1627 QStringList::const_iterator tupleIterator;
1628 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1630 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1633 *dimension = std::max( *dimension,
static_cast<int>( tuples_coordinates.size() ) );
1635 if ( tuples_coordinates.size() < 2 )
1639 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1640 if ( !conversionSuccess )
1644 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1645 if ( !conversionSuccess )
1649 if ( tuples_coordinates.size() > 2 )
1651 z = tuples_coordinates.at( 2 ).toDouble( &conversionSuccess );
1652 if ( !conversionSuccess )
1659 z = std::numeric_limits<double>::quiet_NaN();
1661 points.push_back( ( mInvertAxisOrientation ) ?
QgsPoint( y, x, z ) :
QgsPoint( x, y, z ) );
1664 if ( dimension && *dimension == 0 )
1672int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPoint> &points,
const QString &coordString,
int dimension )
const
1675 const QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1677 if ( coordinates.size() % dimension != 0 )
1679 QgsDebugError( QStringLiteral(
"Wrong number of coordinates" ) );
1682 const int ncoor = coordinates.size() / dimension;
1683 for (
int i = 0; i < ncoor; i++ )
1685 bool conversionSuccess;
1686 const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1687 if ( !conversionSuccess )
1691 const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1692 if ( !conversionSuccess )
1696 double z = std::numeric_limits<double>::quiet_NaN();
1697 if ( dimension > 2 )
1699 z = coordinates.value( i * dimension + 2 ).toDouble( &conversionSuccess );
1700 if ( !conversionSuccess )
1705 points.append( mInvertAxisOrientation ?
QgsPoint( y, x, z ) :
QgsPoint( x, y, z ) );
1710int QgsGmlStreamingParser::pointsFromString( QList<QgsPoint> &points,
const QString &coordString,
int *dimension )
const
1712 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1714 return pointsFromCoordinateString( points, coordString, dimension );
1716 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1720 *dimension = mDimension ? mDimension : 2;
1722 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1727int QgsGmlStreamingParser::getPointWKB( QByteArray &wkbPtr,
const QgsPoint &point,
int dimension )
const
1729 const int wkbSize = 1 +
static_cast<int>(
sizeof( int ) ) + dimension *
static_cast<int>(
sizeof( double ) );
1730 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1734 if ( dimension > 2 )
1736 fillPtr << point.z();
1742int QgsGmlStreamingParser::getLineWKB( QByteArray &wkbPtr,
const QList<QgsPoint> &lineCoordinates,
int dimension )
const
1744 const int wkbSize = 1 + 2 *
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( lineCoordinates.size() ) * dimension *
static_cast<int>(
sizeof(
double ) );
1745 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1751 QList<QgsPoint>::const_iterator iter;
1752 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1754 fillPtr << iter->x() << iter->y();
1755 if ( dimension > 2 )
1757 fillPtr << iter->z();
1764int QgsGmlStreamingParser::getRingWKB( QByteArray &wkbPtr,
const QList<QgsPoint> &ringCoordinates,
int dimension )
const
1766 const int wkbSize =
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( ringCoordinates.size() ) * dimension *
static_cast<int>(
sizeof(
double ) );
1767 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1771 fillPtr << ringCoordinates.size();
1773 QList<QgsPoint>::const_iterator iter;
1774 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1776 fillPtr << iter->x() << iter->y();
1777 if ( dimension > 2 )
1779 fillPtr << iter->z();
1786int QgsGmlStreamingParser::createMultiLineFromFragments()
1788 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1789 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1796 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1797 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1799 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1800 wkbPtr += wkbIt->size();
1803 mCurrentWKBFragments.clear();
1808int QgsGmlStreamingParser::createMultiPointFromFragments()
1810 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1811 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1816 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1817 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1819 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1820 wkbPtr += wkbIt->size();
1823 mCurrentWKBFragments.clear();
1829int QgsGmlStreamingParser::createPolygonFromFragments()
1831 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1832 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1837 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1838 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1840 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1841 wkbPtr += wkbIt->size();
1844 mCurrentWKBFragments.clear();
1849int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1852 size += 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) );
1853 size += totalWKBFragmentSize();
1854 size += mCurrentWKBFragments.size() * ( 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) );
1856 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1862 auto outerWkbIt = mCurrentWKBFragments.constBegin();
1864 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1869 auto innerWkbIt = outerWkbIt->constBegin();
1870 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1872 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1873 wkbPtr += innerWkbIt->size();
1877 mCurrentWKBFragments.clear();
1882int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1885 for (
const QList<QByteArray> &list : std::as_const( mCurrentWKBFragments ) )
1887 for (
const QByteArray &i : list )
1895void QgsGmlStreamingParser::createParser(
const QByteArray &encoding )
1897 Q_ASSERT( !mParser );
1899 mParser = XML_ParserCreateNS( encoding.isEmpty() ?
nullptr : encoding.data(), NS_SEPARATOR );
1900 XML_SetUserData( mParser,
this );
1901 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
1902 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
Provides global constants and enumerations for use throughout the application.
@ Critical
Critical/error message.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ MultiPointZ
MultiPointZ.
@ MultiPolygon
MultiPolygon.
@ MultiLineString
MultiLineString.
@ MultiLineStringZ
MultiLineStringZ.
@ MultiPolygonZ
MultiPolygonZ.
@ LineStringZ
LineStringZ.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static endian_t endian()
Returns whether this machine uses big or little endian.
Represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool hasAxisInverted() const
Returns whether the axis order is inverted for the CRS compared to the order east/north (longitude/la...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Q_INVOKABLE bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
void setValid(bool validity)
Sets the validity of the feature.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Container of fields for a vector layer.
int size() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
A geometry is the spatial representation of a feature.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
QPair< QgsFeature *, QString > QgsGmlFeaturePtrGmlIdPair
void setFieldsXPath(const QMap< QString, QPair< QString, bool > > &fieldNameToSrcLayerNameFieldNameMap, const QMap< QString, QString > &namespacePrefixToURIMap)
Define the XPath of the attributes and whether they are made of nested content.
int numberReturned() const
Returns WFS 2.0 "numberReturned" or WFS 1.1 "numberOfFeatures" attribute, or -1 if invalid/not found.
Qgis::WkbType wkbType() const
Returns the geometry type.
AxisOrientationLogic
Axis orientation logic.
@ Honour_EPSG
Honour EPSG axis order.
@ Honour_EPSG_if_urn
Honour EPSG axis order only if srsName is of the form urn:ogc:def:crs:EPSG:
int numberMatched() const
Returns WFS 2.0 "numberMatched" attribute, or -1 if invalid/not found.
QgsGmlStreamingParser(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields, AxisOrientationLogic axisOrientationLogic=Honour_EPSG_if_urn, bool invertAxisOrientation=false)
Constructor.
bool processData(const QByteArray &data, bool atEnd, QString &errorMsg)
Process a new chunk of data.
int getEPSGCode() const
Returns the EPSG code, or 0 if unknown.
QVector< QgsGmlFeaturePtrGmlIdPair > getAndStealReadyFeatures()
Returns the list of features that have been completely parsed.
QString srsName() const
Returns the value of the srsName attribute.
void totalStepsUpdate(int totalSteps)
Emitted when the total number of bytes to read changes.
void dataReadProgress(int progress)
Emitted when data reading progresses.
QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)
QgsCoordinateReferenceSystem crs() const
Returns the spatial reference system for features.
int getFeatures(const QString &uri, Qgis::WkbType *wkbType, QgsRectangle *extent=nullptr, const QString &userName=QString(), const QString &password=QString(), const QString &authcfg=QString())
Does the HTTP GET request to the WFS server.
void dataProgressAndSteps(int progress, int totalSteps)
Emitted when data reading progresses or the total number of bytes to read changes.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
@ OGC_HTTP_URI
E.g. http://www.opengis.net/def/crs/EPSG/0/4326.
@ X_OGC_URN
E.g. urn:x-ogc:def:crs:EPSG::4326.
@ UNKNOWN
Unknown/unhandled flavor.
@ OGC_URN
E.g. urn:ogc:def:crs:EPSG::4326.
static CRSFlavor parseCrsName(const QString &crsName, QString &authority, QString &code)
Parse a CRS name in one of the flavors of OGC services, and decompose it as authority and code.
Point geometry type, with support for z-dimension and m-values.
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).
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
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