35#include <QNetworkReply>
36#include <QNetworkRequest>
37#include <QProgressDialog>
38#include <QRegularExpression>
45#include "moc_qgsgml.cpp"
47using namespace Qt::StringLiterals;
49using namespace nlohmann;
51#ifndef NS_SEPARATOR_DEFINED
52#define NS_SEPARATOR_DEFINED
53static const char NS_SEPARATOR =
'?';
56static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
60 : mParser( typeName, geometryAttribute, fields )
61 , mTypeName( typeName )
63 const int index = mTypeName.indexOf(
':' );
64 if ( index != -1 && index < mTypeName.length() )
66 mTypeName = mTypeName.mid( index + 1 );
75 QNetworkRequest request( uri );
78 if ( !authcfg.isEmpty() )
86 else if ( !userName.isNull() || !password.isNull() )
88 request.setRawHeader(
"Authorization",
"Basic " + u
"%1:%2"_s.arg( userName, password ).toLatin1().toBase64() );
92 if ( !authcfg.isEmpty() )
102 connect( reply, &QNetworkReply::finished,
this, &QgsGml::setFinished );
103 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsGml::handleProgressEvent );
106 QProgressDialog *progressDialog =
nullptr;
107 QWidget *mainWindow =
nullptr;
108 const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
109 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
111 if ( ( *it )->objectName() ==
"QgisApp"_L1 )
119 progressDialog =
new QProgressDialog( tr(
"Loading GML data\n%1" ).arg( mTypeName ), tr(
"Abort" ), 0, 0, mainWindow );
120 progressDialog->setWindowModality( Qt::ApplicationModal );
123 connect( progressDialog, &QProgressDialog::canceled,
this, &QgsGml::setFinished );
124 progressDialog->show();
134 const QByteArray readData = reply->readAll();
135 if ( !readData.isEmpty() )
138 if ( !mParser.processData( readData, atEnd, errorMsg ) )
141 QCoreApplication::processEvents();
144 fillMapsFromParser();
146 const QNetworkReply::NetworkError replyError = reply->error();
147 const QString replyErrorString = reply->errorString();
150 delete progressDialog;
158 *wkbType = mParser.wkbType();
162 if ( mExtent.isEmpty() )
165 calculateExtentFromFeatures();
180 if ( !mParser.processData( data,
true , errorMsg ) )
183 fillMapsFromParser();
185 *wkbType = mParser.wkbType();
193void QgsGml::fillMapsFromParser()
196 const auto constFeatures = features;
200 const QString &gmlId = featPair.second;
201 mFeatures.insert( feat->
id(), feat );
202 if ( !gmlId.isEmpty() )
204 mIdMap.insert( feat->
id(), gmlId );
209void QgsGml::setFinished()
214void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
216 if ( totalSteps < 0 )
226void QgsGml::calculateExtentFromFeatures()
228 if ( mFeatures.empty() )
233 QgsFeature *currentFeature =
nullptr;
234 QgsGeometry currentGeometry;
235 bool bboxInitialized =
false;
237 for (
int i = 0; i < mFeatures.size(); ++i )
239 currentFeature = mFeatures[i];
240 if ( !currentFeature )
244 currentGeometry = currentFeature->
geometry();
245 if ( !currentGeometry.
isNull() )
247 if ( !bboxInitialized )
250 bboxInitialized =
true;
254 mExtent.combineExtentWith( currentGeometry.
boundingBox() );
263 if ( !mParser.srsName().isEmpty() )
272 : mTypeName( typeName )
273 , mTypeNameBA( mTypeName.toUtf8() )
274 , mTypeNamePtr( mTypeNameBA.constData() )
275 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
276 , mWkbType(
Qgis::WkbType::Unknown )
277 , mGeometryAttribute( geometryAttribute )
278 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
279 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
280 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
282 , mIsException( false )
283 , mTruncatedResponse( false )
285 , mFeatureTupleDepth( 0 )
287 , mCurrentWKB( nullptr, 0 )
288 , mBoundedByNullFound( false )
290 , mCoorMode( Coordinate )
291 , mAxisOrientationLogic( axisOrientationLogic )
292 , mInvertAxisOrientationRequest( invertAxisOrientation )
293 , mInvertAxisOrientation( invertAxisOrientation )
294 , mNumberReturned( -1 )
295 , mNumberMatched( -1 )
296 , mFoundUnhandledGeometryElement( false )
298 mThematicAttributes.clear();
299 for (
int i = 0; i < fields.
size(); i++ )
301 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
306 const int index = mTypeName.indexOf(
':' );
307 if ( index != -1 && index < mTypeName.length() )
309 mTypeName = mTypeName.mid( index + 1 );
310 mTypeNameBA = mTypeName.toUtf8();
311 mTypeNamePtr = mTypeNameBA.constData();
312 mTypeNameUTF8Len = strlen( mTypeNamePtr );
318static QString stripNS(
const QString &
string )
320 const int index =
string.indexOf(
':' );
321 if ( index != -1 && index <
string.length() )
323 return string.mid( index + 1 );
329 const QList<LayerProperties> &layerProperties,
331 const QMap< QString, QPair<QString, QString> > &fieldNameToSrcLayerNameFieldNameMap,
333 bool invertAxisOrientation
335 : mLayerProperties( layerProperties )
336 , mTypeNameUTF8Len( 0 )
337 , mWkbType(
Qgis::WkbType::Unknown )
338 , mGeometryAttributeUTF8Len( 0 )
340 , mIsException( false )
341 , mTruncatedResponse( false )
343 , mFeatureTupleDepth( 0 )
345 , mCurrentWKB( nullptr, 0 )
346 , mBoundedByNullFound( false )
348 , mCoorMode( Coordinate )
349 , mAxisOrientationLogic( axisOrientationLogic )
350 , mInvertAxisOrientationRequest( invertAxisOrientation )
351 , mInvertAxisOrientation( invertAxisOrientation )
352 , mNumberReturned( -1 )
353 , mNumberMatched( -1 )
354 , mFoundUnhandledGeometryElement( false )
356 mThematicAttributes.clear();
357 for (
int i = 0; i < fields.
size(); i++ )
359 const QMap< QString, QPair<QString, QString> >::const_iterator att_it = fieldNameToSrcLayerNameFieldNameMap.constFind( fields.
at( i ).
name() );
360 if ( att_it != fieldNameToSrcLayerNameFieldNameMap.constEnd() )
362 if ( mLayerProperties.size() == 1 )
363 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
365 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
368 bool alreadyFoundGeometry =
false;
369 for (
int i = 0; i < mLayerProperties.size(); i++ )
372 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
374 if ( alreadyFoundGeometry )
376 QgsDebugMsgLevel( u
"Will ignore geometry field %1 from typename %2"_s.arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ), 2 );
377 mLayerProperties[i].mGeometryAttribute.clear();
379 alreadyFoundGeometry =
true;
381 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
384 if ( mLayerProperties.size() == 1 )
386 mTypeName = mLayerProperties[0].mName;
387 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
388 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
389 mGeometryAttributePtr = mGeometryAttributeBA.constData();
390 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
391 const int index = mTypeName.indexOf(
':' );
392 if ( index != -1 && index < mTypeName.length() )
394 mTypeName = mTypeName.mid( index + 1 );
396 mTypeNameBA = mTypeName.toUtf8();
397 mTypeNamePtr = mTypeNameBA.constData();
398 mTypeNameUTF8Len = strlen( mTypeNamePtr );
409 for (
auto iter = fieldNameToXPathMapAndIsNestedContent.constBegin(); iter != fieldNameToXPathMapAndIsNestedContent.constEnd(); ++iter )
411 mMapXPathToFieldNameAndIsNestedContent[iter.value().first] = QPair<QString, bool>( iter.key(), iter.value().second );
413 for (
auto iter = mapNamespacePrefixToURI.constBegin(); iter != mapNamespacePrefixToURI.constEnd(); ++iter )
414 mMapNamespaceURIToNamespacePrefix[iter.value()] = iter.key();
420 XML_ParserFree( mParser );
423 const auto constMFeatureList = mFeatureList;
426 delete featPair.first;
429 delete mCurrentFeature;
445 QByteArray data = pdata;
450 QString strData = mCodec->toUnicode( pdata );
451 data = strData.toUtf8();
454 if ( XML_Parse( mParser, data, data.size(), atEnd ) == XML_STATUS_ERROR )
456 const XML_Error errorCode = XML_GetErrorCode( mParser );
457 if ( !mCodec && errorCode == XML_ERROR_UNKNOWN_ENCODING )
461 const thread_local QRegularExpression reEncoding( u
"<?xml.*encoding=['\"]([^'\"]*)['\"].*?>"_s, QRegularExpression::CaseInsensitiveOption );
462 QRegularExpressionMatch match = reEncoding.match( pdata );
463 const QString encoding = match.hasMatch() ? match.captured( 1 ) : QString();
464 mCodec = !encoding.isEmpty() ? QTextCodec::codecForName( encoding.toLatin1() ) :
nullptr;
468 XML_ParserFree( mParser );
470 createParser( QByteArrayLiteral(
"UTF-8" ) );
476 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" ).arg( XML_ErrorString( errorCode ) ).arg( XML_GetCurrentLineNumber( mParser ) ).arg( XML_GetCurrentColumnNumber( mParser ) );
486 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
487 mFeatureList.clear();
495static json jsonFromString(
const QString &s )
500 if ( s.indexOf(
'.' ) >= 0 || s.indexOf(
'e' ) >= 0 )
502 const auto doubleVal = s.toDouble( &conversionOk );
505 return json( doubleVal );
510 else if ( !s.isEmpty() && s[0] !=
'0' )
512 const auto longlongVal = s.toLongLong( &conversionOk );
515 return json( longlongVal );
519 return json( s.toStdString() );
522#define LOCALNAME_EQUALS( string_constant ) ( localNameLen == static_cast<int>( strlen( string_constant ) ) && memcmp( pszLocalName, string_constant, localNameLen ) == 0 )
524void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
526 const int elLen =
static_cast<int>( strlen( el ) );
527 const char *pszSep = strchr( el, NS_SEPARATOR );
528 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
529 const int nsLen = ( pszSep ) ? (
int ) ( pszSep - el ) : 0;
530 const int localNameLen = ( pszSep ) ? (
int ) ( elLen - nsLen ) - 1 : elLen;
531 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
535 if ( !mGMLNameSpaceURIPtr && pszSep )
549 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
552 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList || parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
554 mGeometryString.append(
"<", 1 );
555 mGeometryString.append( pszLocalName, localNameLen );
556 mGeometryString.append(
" ", 1 );
557 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
559 const size_t nAttrLen = strlen( attrIter[0] );
562 if ( nAttrLen > GML32_NAMESPACE_LEN && attrIter[0][GML32_NAMESPACE_LEN] ==
'?' && memcmp( attrIter[0],
GML32_NAMESPACE, GML32_NAMESPACE_LEN ) == 0 )
564 mGeometryString.append(
"gml:" );
565 mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
567 else if ( nAttrLen > GML_NAMESPACE_LEN && attrIter[0][GML_NAMESPACE_LEN] ==
'?' && memcmp( attrIter[0],
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
569 mGeometryString.append(
"gml:" );
570 mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
574 mGeometryString.append( attrIter[0] );
576 mGeometryString.append(
"=\"", 2 );
577 mGeometryString.append( attrIter[1] );
578 mGeometryString.append(
"\" ", 2 );
580 mGeometryString.append(
">", 1 );
583 if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
585 mParseModeStack.push( Coordinate );
586 mCoorMode = QgsGmlStreamingParser::Coordinate;
588 mCoordinateSeparator = readAttribute( u
"cs"_s, attr );
589 if ( mCoordinateSeparator.isEmpty() )
591 mCoordinateSeparator =
',';
593 mTupleSeparator = readAttribute( u
"ts"_s, attr );
594 if ( mTupleSeparator.isEmpty() )
596 mTupleSeparator =
' ';
601 mParseModeStack.push( QgsGmlStreamingParser::PosList );
602 if ( mCoorMode == QgsGmlStreamingParser::PosList )
604 if ( !mStringCash.isEmpty() )
606 mStringCash.append(
' '_L1 );
613 mCoorMode = QgsGmlStreamingParser::PosList;
614 elDimension = readSrsNameAndDimensionAttributes( attr );
616 else if ( ( parseMode == Feature || parseMode == FeatureTuple )
618 && localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len )
619 && memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
621 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
622 mFoundUnhandledGeometryElement =
false;
623 mGeometryString.clear();
627 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
629 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
631 mBoundedByNullFound =
false;
633 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"null" ) )
635 mParseModeStack.push( QgsGmlStreamingParser::Null );
636 mBoundedByNullFound =
true;
638 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
641 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
643 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
645 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
648 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
650 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
653 else if ( parseMode == None && !mTypeNamePtr &&
LOCALNAME_EQUALS(
"Tuple" ) )
655 Q_ASSERT( !mCurrentFeature );
656 mCurrentFeature =
new QgsFeature( mFeatureCount );
658 const QgsAttributes attributes( mThematicAttributes.size() );
660 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
661 mCurrentFeatureId.clear();
663 else if ( parseMode == Tuple )
665 const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
666 const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
667 if ( iter != mMapTypeNameToProperties.constEnd() )
669 mFeatureTupleDepth = mParseDepth;
670 mCurrentTypename = currentTypename;
671 mGeometryAttribute.clear();
672 if ( mCurrentWKB.size() == 0 )
674 mGeometryAttribute = iter.value().mGeometryAttribute;
676 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
677 mGeometryAttributePtr = mGeometryAttributeBA.constData();
678 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
679 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
681 if ( mGMLNameSpaceURI.isEmpty() )
683 id = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
691 id = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
700 id = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
701 if ( !mCurrentFeatureId.isEmpty() )
702 mCurrentFeatureId +=
'|';
703 mCurrentFeatureId += id;
706 else if ( parseMode == None && localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) && mTypeNamePtr && memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
708 Q_ASSERT( !mCurrentFeature );
709 mCurrentFeature =
new QgsFeature( mFeatureCount );
711 const QgsAttributes attributes( mThematicAttributes.size() );
713 mParseModeStack.push( QgsGmlStreamingParser::Feature );
714 mCurrentXPathWithinFeature.clear();
715 mCurrentFeatureId = readAttribute( u
"fid"_s, attr );
716 if ( mCurrentFeatureId.isEmpty() )
721 if ( mGMLNameSpaceURI.isEmpty() )
723 mCurrentFeatureId = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
724 if ( !mCurrentFeatureId.isEmpty() )
731 mCurrentFeatureId = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
732 if ( !mCurrentFeatureId.isEmpty() )
740 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
744 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
748 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
752 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"LineString" ) )
756 else if ( !mAttributeValIsNested && isGMLNS && localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
759 mCurrentWKBFragments.push_back( QList<QByteArray>() );
761 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
764 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
766 mCurrentWKBFragments.push_back( QList<QByteArray>() );
771 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
773 mCurrentWKBFragments.push_back( QList<QByteArray>() );
778 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
780 else if ( parseMode == FeatureTuple )
782 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
783 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
785 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
786 mAttributeName = mCurrentTypename +
'|' + localName;
790 else if ( parseMode == Feature )
792 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
793 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
795 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
796 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
797 if ( !mCurrentXPathWithinFeature.isEmpty() )
798 mCurrentXPathWithinFeature.append(
'/' );
799 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
801 mCurrentXPathWithinFeature.append( *nsIter );
802 mCurrentXPathWithinFeature.append(
':' );
804 mCurrentXPathWithinFeature.append( localName );
805 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( mCurrentXPathWithinFeature );
806 mAttributeValIsNested =
false;
807 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
809 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
810 mAttributeDepth = mParseDepth;
811 mAttributeName = xpathIter->first;
812 mAttributeValIsNested = xpathIter->second;
813 if ( mAttributeValIsNested )
815 mAttributeJson = json::object();
816 mAttributeJsonCurrentStack.clear();
817 mAttributeJsonCurrentStack.push( &mAttributeJson );
822 else if ( mThematicAttributes.contains( localName ) )
824 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
825 mAttributeDepth = mParseDepth;
826 mAttributeName = localName;
833 if ( localName.compare(
"attribute"_L1, Qt::CaseInsensitive ) == 0 )
835 const QString name = readAttribute( u
"name"_s, attr );
836 if ( mThematicAttributes.contains( name ) )
838 const QString value = readAttribute( u
"value"_s, attr );
839 setAttribute( name, value );
844 else if ( parseMode == Attribute && mAttributeValIsNested )
846 const std::string localName( pszLocalName, localNameLen );
847 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
848 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
849 const std::string nodeName = nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() ? ( *nsIter ).toStdString() +
':' + localName : localName;
851 addStringContentToJson();
853 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
854 auto iter = jsonParent.find( nodeName );
855 if ( iter != jsonParent.end() )
857 if ( iter->type() != json::value_t::array )
859 auto array = json::array();
860 array.emplace_back( std::move( *iter ) );
863 iter->push_back( json::object() );
864 mAttributeJsonCurrentStack.push( &( iter->back() ) );
868 auto res = jsonParent.emplace( nodeName, json::object() );
872 nlohmann::json *ptr = &( *( res.first ) );
874 mAttributeJsonCurrentStack.push( ptr );
879 QString
numberReturned = readAttribute( u
"numberReturned"_s, attr );
885 mNumberReturned = -1;
887 const QString
numberMatched = readAttribute( u
"numberMatched"_s, attr );
895 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
900 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
905 mTruncatedResponse =
true;
907 else if ( !mGeometryString.empty()
923 mFoundUnhandledGeometryElement =
true;
927 if ( !mParseModeStack.isEmpty() && ( mParseModeStack.back() == Feature || mParseModeStack.back() == Attribute ) && !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
929 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
931 const char *questionMark = strchr( attrIter[0],
'?' );
935 const QString nsURI( QString::fromUtf8( attrIter[0],
static_cast<int>( questionMark - attrIter[0] ) ) );
936 const QString localName( QString::fromUtf8( questionMark + 1 ) );
937 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
938 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
940 key.append( *nsIter );
943 key.append( localName );
947 const QString localName( QString::fromUtf8( attrIter[0] ) );
948 key.append( localName );
951 if ( mAttributeValIsNested && mParseModeStack.back() == Attribute )
953 mAttributeJsonCurrentStack.top()->emplace( key.toStdString(), jsonFromString( QString::fromUtf8( attrIter[1] ) ) );
957 QString xpath( mCurrentXPathWithinFeature );
958 if ( !xpath.isEmpty() )
961 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( xpath );
962 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
964 setAttribute( xpathIter->first, QString::fromUtf8( attrIter[1] ) );
970 if ( !mGeometryString.empty() )
975 elDimension = readSrsNameAndDimensionAttributes( attr );
978 if ( elDimension != 0 || mDimensionStack.isEmpty() )
980 mDimensionStack.push( elDimension );
984 mDimensionStack.push( mDimensionStack.back() );
990void QgsGmlStreamingParser::endElement(
const XML_Char *el )
994 const int elLen =
static_cast<int>( strlen( el ) );
995 const char *pszSep = strchr( el, NS_SEPARATOR );
996 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
997 const int nsLen = ( pszSep ) ? (
int ) ( pszSep - el ) : 0;
998 const int localNameLen = ( pszSep ) ? (
int ) ( elLen - nsLen ) - 1 : elLen;
999 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
1001 const int lastDimension = mDimensionStack.isEmpty() ? 2 : mDimensionStack.pop();
1003 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
1005 if ( parseMode == Feature || ( parseMode == Attribute && mAttributeDepth == mParseDepth ) )
1007 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
1009 const auto nPos = mCurrentXPathWithinFeature.lastIndexOf(
'/' );
1011 mCurrentXPathWithinFeature.clear();
1013 mCurrentXPathWithinFeature.resize( nPos );
1017 if ( parseMode == Attribute && mAttributeValIsNested )
1019 if ( !mStringCash.isEmpty() )
1021 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1022 if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
1024 jsonParent = jsonFromString( mStringCash );
1026 else if ( jsonParent.type() == json::value_t::object )
1028 addStringContentToJson();
1030 mStringCash.clear();
1033 mAttributeJsonCurrentStack.pop();
1036 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
1038 mParseModeStack.pop();
1042 mDimension = lastDimension;
1043 mParseModeStack.pop();
1045 else if ( parseMode == AttributeTuple && mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
1047 mParseModeStack.pop();
1049 setAttribute( mAttributeName, mStringCash );
1051 else if ( parseMode == Attribute && mAttributeDepth == mParseDepth )
1053 mParseModeStack.pop();
1056 if ( mAttributeValIsNested )
1058 mAttributeValIsNested =
false;
1059 auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
1060 if ( iter == mMapFieldNameToJSONContent.end() )
1062 mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
1066 QString &str = iter.value();
1067 if ( str[0] ==
'[' && str.back() ==
']' )
1073 str.insert( 0,
'[' );
1076 str.append( QString::fromStdString( mAttributeJson.dump() ) );
1082 setAttribute( mAttributeName, mStringCash );
1085 else if ( parseMode == Geometry && localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) && memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1087 mParseModeStack.pop();
1088 if ( mFoundUnhandledGeometryElement )
1094 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
1095 unsigned char *pabyBuffer =
new unsigned char[wkbSize];
1096 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
1098 g.
fromWkb( pabyBuffer, wkbSize );
1099 if ( mInvertAxisOrientation )
1101 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1103 Q_ASSERT( mCurrentFeature );
1104 mCurrentFeature->setGeometry( g );
1107 mGeometryString.clear();
1109 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
1112 if ( mCurrentExtent.isNull() && !mBoundedByNullFound && !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
1116 if ( !mCurrentExtent.isNull() && mLayerExtent.isNull() && !mCurrentFeature && mFeatureCount == 0 )
1118 mLayerExtent = mCurrentExtent;
1119 mCurrentExtent = QgsRectangle();
1122 mParseModeStack.pop();
1126 mParseModeStack.pop();
1128 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
1130 mParseModeStack.pop();
1132 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
1134 QList<QgsPoint> points;
1135 pointsFromPosListString( points, mStringCash, 2 );
1136 if ( points.size() == 1 )
1138 mCurrentExtent.setXMinimum( points[0].x() );
1139 mCurrentExtent.setYMinimum( points[0].y() );
1141 mParseModeStack.pop();
1143 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
1145 QList<QgsPoint> points;
1146 pointsFromPosListString( points, mStringCash, 2 );
1147 if ( points.size() == 1 )
1149 mCurrentExtent.setXMaximum( points[0].x() );
1150 mCurrentExtent.setYMaximum( points[0].y() );
1152 mParseModeStack.pop();
1154 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
1156 mParseModeStack.pop();
1157 mFeatureTupleDepth = 0;
1159 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
LOCALNAME_EQUALS(
"Tuple" ) )
1160 || ( parseMode == Feature && localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) && memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
1162 Q_ASSERT( mCurrentFeature );
1163 if ( !mCurrentFeature->hasGeometry() )
1165 if ( mCurrentWKB.size() > 0 )
1169 mCurrentFeature->setGeometry( g );
1170 mCurrentWKB = QByteArray();
1172 else if ( !mCurrentExtent.isEmpty() )
1177 mCurrentFeature->setValid(
true );
1179 for (
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
1181 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
1182 const int attrIndex = att_it.value().first;
1183 mCurrentFeature->setAttribute( attrIndex, iter.value() );
1185 mMapFieldNameToJSONContent.clear();
1189 mCurrentFeature =
nullptr;
1191 mParseModeStack.pop();
1193 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
1195 QList<QgsPoint> pointList;
1197 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1201 mStringCash.clear();
1202 mDimension = dimension;
1204 if ( pointList.isEmpty() )
1207 if ( parseMode == QgsGmlStreamingParser::Geometry )
1210 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ), dimension ) != 0 )
1223 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ), dimension ) != 0 )
1227 if ( !mCurrentWKBFragments.isEmpty() )
1229 mCurrentWKBFragments.last().push_back( wkbPtr );
1241 QList<QgsPoint> pointList;
1243 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1247 mStringCash.clear();
1248 mDimension = dimension;
1250 if ( parseMode == QgsGmlStreamingParser::Geometry )
1252 if ( getLineWKB( mCurrentWKB, pointList, dimension ) != 0 )
1261 else if ( dimension > 2 )
1265 mDimension = dimension;
1270 if ( getLineWKB( wkbPtr, pointList, dimension ) != 0 )
1274 mDimension = dimension;
1275 if ( !mCurrentWKBFragments.isEmpty() )
1277 mCurrentWKBFragments.last().push_back( wkbPtr );
1285 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
LOCALNAME_EQUALS(
"LinearRing" ) )
1287 QList<QgsPoint> pointList;
1289 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1293 mStringCash.clear();
1294 mDimension = dimension;
1297 if ( getRingWKB( wkbPtr, pointList, dimension ) != 0 )
1302 if ( !mCurrentWKBFragments.isEmpty() )
1304 mCurrentWKBFragments.last().push_back( wkbPtr );
1311 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
LOCALNAME_EQUALS(
"Polygon" ) )
1318 if ( parseMode == Geometry )
1320 createPolygonFromFragments();
1323 else if ( parseMode == MultiPoint && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
1326 mParseModeStack.pop();
1327 createMultiPointFromFragments();
1332 mParseModeStack.pop();
1333 createMultiLineFromFragments();
1338 mParseModeStack.pop();
1339 createMultiPolygonFromFragments();
1343 mParseModeStack.pop();
1345 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1347 mExceptionText = mStringCash;
1348 mParseModeStack.pop();
1351 if ( !mGeometryString.empty() )
1353 mGeometryString.append(
"</", 2 );
1354 mGeometryString.append( pszLocalName, localNameLen );
1355 mGeometryString.append(
">", 1 );
1359void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1362 if ( mParseModeStack.isEmpty() )
1367 if ( !mGeometryString.empty() )
1369 mGeometryString.append( chars, len );
1372 const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1373 if ( parseMode == QgsGmlStreamingParser::Attribute
1374 || parseMode == QgsGmlStreamingParser::AttributeTuple
1375 || parseMode == QgsGmlStreamingParser::Coordinate
1376 || parseMode == QgsGmlStreamingParser::PosList
1377 || parseMode == QgsGmlStreamingParser::LowerCorner
1378 || parseMode == QgsGmlStreamingParser::UpperCorner
1379 || parseMode == QgsGmlStreamingParser::ExceptionText )
1381 mStringCash.append( QString::fromUtf8( chars, len ) );
1385void QgsGmlStreamingParser::addStringContentToJson()
1387 const QString s( mStringCash.trimmed() );
1390 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1391 auto textIter = jsonParent.find(
"_text" );
1392 if ( textIter != jsonParent.end() )
1394 if ( textIter->type() != json::value_t::array )
1396 auto array = json::array();
1397 array.emplace_back( std::move( *textIter ) );
1400 textIter->emplace_back( jsonFromString( s ) );
1404 jsonParent.emplace(
"_text", jsonFromString( s ) );
1407 mStringCash.clear();
1410void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1413 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1414 bool conversionOk =
true;
1415 if ( att_it != mThematicAttributes.constEnd() )
1418 switch ( att_it.value().second.type() )
1420 case QMetaType::Type::Double:
1421 var = QVariant( value.toDouble( &conversionOk ) );
1423 case QMetaType::Type::Int:
1424 var = QVariant( value.toInt( &conversionOk ) );
1426 case QMetaType::Type::LongLong:
1427 var = QVariant( value.toLongLong( &conversionOk ) );
1429 case QMetaType::Type::QDateTime:
1430 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1433 var = QVariant( value );
1436 if ( !conversionOk )
1440 Q_ASSERT( mCurrentFeature );
1441 mCurrentFeature->setAttribute( att_it.value().first, var );
1445int QgsGmlStreamingParser::readSrsNameAndDimensionAttributes(
const XML_Char **attr )
1447 int elDimension = 0;
1448 for (
int i = 0; attr[i] && attr[i + 1]; i += 2 )
1450 if ( strcmp( attr[i],
"srsName" ) == 0 )
1452 const QString
srsName( attr[i + 1] );
1453 if ( mSrsName.isEmpty() )
1467 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1471 if ( elDimension == 0 )
1472 elDimension = mDimensionForCurSrsName;
1476 else if (
srsName == mSrsName && elDimension == 0 )
1478 elDimension = mDimensionForCurSrsName;
1481 else if ( strcmp( attr[i],
"srsDimension" ) == 0 )
1483 const QString srsDimension( attr[i + 1] );
1485 const int dimension = srsDimension.toInt( &ok );
1488 elDimension = dimension;
1496QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1501 if ( attributeName.compare( attr[i] ) == 0 )
1503 return QString::fromUtf8( attr[i + 1] );
1510bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1512 QList<QgsPoint> points;
1513 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1518 if ( points.size() < 2 )
1523 r.
set( points[0], points[1] );
1528int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPoint> &points,
const QString &coordString,
int *dimension )
const
1531 const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1532 QStringList tuples_coordinates;
1534 bool conversionSuccess;
1539 QStringList::const_iterator tupleIterator;
1540 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1542 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1545 *dimension = std::max( *dimension,
static_cast<int>( tuples_coordinates.size() ) );
1547 if ( tuples_coordinates.size() < 2 )
1551 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1552 if ( !conversionSuccess )
1556 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1557 if ( !conversionSuccess )
1561 if ( tuples_coordinates.size() > 2 )
1563 z = tuples_coordinates.at( 2 ).toDouble( &conversionSuccess );
1564 if ( !conversionSuccess )
1571 z = std::numeric_limits<double>::quiet_NaN();
1573 points.push_back( ( mInvertAxisOrientation ) ? QgsPoint( y, x, z ) : QgsPoint( x, y, z ) );
1576 if ( dimension && *dimension == 0 )
1584int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPoint> &points,
const QString &coordString,
int dimension )
const
1587 const QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1589 if ( coordinates.size() % dimension != 0 )
1594 const int ncoor = coordinates.size() / dimension;
1595 for (
int i = 0; i < ncoor; i++ )
1597 bool conversionSuccess;
1598 const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1599 if ( !conversionSuccess )
1603 const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1604 if ( !conversionSuccess )
1608 double z = std::numeric_limits<double>::quiet_NaN();
1609 if ( dimension > 2 )
1611 z = coordinates.value( i * dimension + 2 ).toDouble( &conversionSuccess );
1612 if ( !conversionSuccess )
1617 points.append( mInvertAxisOrientation ? QgsPoint( y, x, z ) : QgsPoint( x, y, z ) );
1622int QgsGmlStreamingParser::pointsFromString( QList<QgsPoint> &points,
const QString &coordString,
int *dimension )
const
1624 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1626 return pointsFromCoordinateString( points, coordString, dimension );
1628 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1632 *dimension = mDimension ? mDimension : 2;
1634 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1639int QgsGmlStreamingParser::getPointWKB( QByteArray &wkbPtr,
const QgsPoint &point,
int dimension )
const
1641 const int wkbSize = 1 +
static_cast<int>(
sizeof( int ) ) + dimension *
static_cast<int>(
sizeof(
double ) );
1642 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1644 QgsWkbPtr fillPtr( wkbPtr );
1646 if ( dimension > 2 )
1648 fillPtr << point.
z();
1654int QgsGmlStreamingParser::getLineWKB( QByteArray &wkbPtr,
const QList<QgsPoint> &lineCoordinates,
int dimension )
const
1656 const int wkbSize = 1 + 2 *
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( lineCoordinates.size() ) * dimension *
static_cast<int>(
sizeof( double ) );
1657 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1659 QgsWkbPtr fillPtr( wkbPtr );
1663 QList<QgsPoint>::const_iterator iter;
1664 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1666 fillPtr << iter->x() << iter->y();
1667 if ( dimension > 2 )
1669 fillPtr << iter->z();
1676int QgsGmlStreamingParser::getRingWKB( QByteArray &wkbPtr,
const QList<QgsPoint> &ringCoordinates,
int dimension )
const
1678 const int wkbSize =
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( ringCoordinates.size() ) * dimension *
static_cast<int>(
sizeof( double ) );
1679 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1681 QgsWkbPtr fillPtr( wkbPtr );
1683 fillPtr << ringCoordinates.size();
1685 QList<QgsPoint>::const_iterator iter;
1686 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1688 fillPtr << iter->x() << iter->y();
1689 if ( dimension > 2 )
1691 fillPtr << iter->z();
1698int QgsGmlStreamingParser::createMultiLineFromFragments()
1700 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1701 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1703 QgsWkbPtr wkbPtr( mCurrentWKB );
1708 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1709 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1711 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1712 wkbPtr += wkbIt->size();
1715 mCurrentWKBFragments.clear();
1720int QgsGmlStreamingParser::createMultiPointFromFragments()
1722 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1723 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1725 QgsWkbPtr wkbPtr( mCurrentWKB );
1728 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1729 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1731 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1732 wkbPtr += wkbIt->size();
1735 mCurrentWKBFragments.clear();
1741int QgsGmlStreamingParser::createPolygonFromFragments()
1743 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1744 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1746 QgsWkbPtr wkbPtr( mCurrentWKB );
1749 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1750 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1752 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1753 wkbPtr += wkbIt->size();
1756 mCurrentWKBFragments.clear();
1761int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1764 size += 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) );
1765 size += totalWKBFragmentSize();
1766 size += mCurrentWKBFragments.size() * ( 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof( int ) ) );
1768 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1770 QgsWkbPtr wkbPtr( mCurrentWKB );
1774 auto outerWkbIt = mCurrentWKBFragments.constBegin();
1776 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1781 auto innerWkbIt = outerWkbIt->constBegin();
1782 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1784 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1785 wkbPtr += innerWkbIt->size();
1789 mCurrentWKBFragments.clear();
1794int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1797 for (
const QList<QByteArray> &list : std::as_const( mCurrentWKBFragments ) )
1799 for (
const QByteArray &i : list )
1807void QgsGmlStreamingParser::createParser(
const QByteArray &encoding )
1809 Q_ASSERT( !mParser );
1811 mParser = XML_ParserCreateNS( encoding.isEmpty() ?
nullptr : encoding.data(), NS_SEPARATOR );
1812 XML_SetUserData( mParser,
this );
1813 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
1814 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 hasVerticalAxis() const
Returns true if the CRS has a vertical axis.
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...
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.
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).
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.
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.
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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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 set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
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)