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() )
1022 if ( localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) && memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1028 if ( mInvertAxisOrientation )
1030 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1032 Q_ASSERT( mCurrentFeature );
1036 QgsGeometry currentGeometry = mCurrentFeature->geometry();
1037 if ( !currentGeometry.
isNull() )
1039 g = g.
combine( currentGeometry );
1041 mCurrentFeature->setGeometry( g );
1046 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1047 if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
1049 jsonParent = jsonFromString( mStringCash );
1051 else if ( jsonParent.type() == json::value_t::object )
1053 addStringContentToJson();
1055 mStringCash.clear();
1057 mAttributeJsonCurrentStack.pop();
1060 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
1062 mParseModeStack.pop();
1066 mDimension = lastDimension;
1067 mParseModeStack.pop();
1069 else if ( parseMode == AttributeTuple && mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
1071 mParseModeStack.pop();
1073 setAttribute( mAttributeName, mStringCash );
1075 else if ( parseMode == Attribute && mAttributeDepth == mParseDepth )
1077 mParseModeStack.pop();
1080 if ( mAttributeValIsNested )
1082 mAttributeValIsNested =
false;
1083 auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
1084 if ( iter == mMapFieldNameToJSONContent.end() )
1086 mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
1090 QString &str = iter.value();
1091 if ( str[0] ==
'[' && str.back() ==
']' )
1097 str.insert( 0,
'[' );
1100 str.append( QString::fromStdString( mAttributeJson.dump() ) );
1106 setAttribute( mAttributeName, mStringCash );
1109 else if ( parseMode == Geometry && localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) && memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1111 mParseModeStack.pop();
1112 if ( mFoundUnhandledGeometryElement )
1118 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
1119 unsigned char *pabyBuffer =
new unsigned char[wkbSize];
1120 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
1122 g.
fromWkb( pabyBuffer, wkbSize );
1123 if ( mInvertAxisOrientation )
1125 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1127 Q_ASSERT( mCurrentFeature );
1128 mCurrentFeature->setGeometry( g );
1131 mGeometryString.clear();
1133 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
1136 if ( mCurrentExtent.isNull() && !mBoundedByNullFound && !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
1140 if ( !mCurrentExtent.isNull() && mLayerExtent.isNull() && !mCurrentFeature && mFeatureCount == 0 )
1142 mLayerExtent = mCurrentExtent;
1143 mCurrentExtent = QgsRectangle();
1146 mParseModeStack.pop();
1150 mParseModeStack.pop();
1152 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
1154 mParseModeStack.pop();
1156 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
1158 QList<QgsPoint> points;
1159 pointsFromPosListString( points, mStringCash, 2 );
1160 if ( points.size() == 1 )
1162 mCurrentExtent.setXMinimum( points[0].x() );
1163 mCurrentExtent.setYMinimum( points[0].y() );
1165 mParseModeStack.pop();
1167 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
1169 QList<QgsPoint> points;
1170 pointsFromPosListString( points, mStringCash, 2 );
1171 if ( points.size() == 1 )
1173 mCurrentExtent.setXMaximum( points[0].x() );
1174 mCurrentExtent.setYMaximum( points[0].y() );
1176 mParseModeStack.pop();
1178 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
1180 mParseModeStack.pop();
1181 mFeatureTupleDepth = 0;
1183 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
LOCALNAME_EQUALS(
"Tuple" ) )
1184 || ( parseMode == Feature && localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) && memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
1186 Q_ASSERT( mCurrentFeature );
1187 if ( !mCurrentFeature->hasGeometry() )
1189 if ( mCurrentWKB.size() > 0 )
1193 mCurrentFeature->setGeometry( g );
1194 mCurrentWKB = QByteArray();
1196 else if ( !mCurrentExtent.isEmpty() )
1201 mCurrentFeature->setValid(
true );
1203 for (
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
1205 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
1206 const int attrIndex = att_it.value().first;
1207 mCurrentFeature->setAttribute( attrIndex, iter.value() );
1209 mMapFieldNameToJSONContent.clear();
1213 mCurrentFeature =
nullptr;
1215 mParseModeStack.pop();
1217 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
1219 QList<QgsPoint> pointList;
1221 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1225 mStringCash.clear();
1226 mDimension = dimension;
1228 if ( pointList.isEmpty() )
1231 if ( parseMode == QgsGmlStreamingParser::Geometry )
1234 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ), dimension ) != 0 )
1247 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ), dimension ) != 0 )
1251 if ( !mCurrentWKBFragments.isEmpty() )
1253 mCurrentWKBFragments.last().push_back( wkbPtr );
1265 QList<QgsPoint> pointList;
1267 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1271 mStringCash.clear();
1272 mDimension = dimension;
1274 if ( parseMode == QgsGmlStreamingParser::Geometry )
1276 if ( getLineWKB( mCurrentWKB, pointList, dimension ) != 0 )
1285 else if ( dimension > 2 )
1289 mDimension = dimension;
1294 if ( getLineWKB( wkbPtr, pointList, dimension ) != 0 )
1298 mDimension = dimension;
1299 if ( !mCurrentWKBFragments.isEmpty() )
1301 mCurrentWKBFragments.last().push_back( wkbPtr );
1309 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
LOCALNAME_EQUALS(
"LinearRing" ) )
1311 QList<QgsPoint> pointList;
1313 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1317 mStringCash.clear();
1318 mDimension = dimension;
1321 if ( getRingWKB( wkbPtr, pointList, dimension ) != 0 )
1326 if ( !mCurrentWKBFragments.isEmpty() )
1328 mCurrentWKBFragments.last().push_back( wkbPtr );
1335 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
LOCALNAME_EQUALS(
"Polygon" ) )
1342 if ( parseMode == Geometry )
1344 createPolygonFromFragments();
1347 else if ( parseMode == MultiPoint && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
1350 mParseModeStack.pop();
1351 createMultiPointFromFragments();
1356 mParseModeStack.pop();
1357 createMultiLineFromFragments();
1362 mParseModeStack.pop();
1363 createMultiPolygonFromFragments();
1367 mParseModeStack.pop();
1369 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1371 mExceptionText = mStringCash;
1372 mParseModeStack.pop();
1375 if ( !mGeometryString.empty() )
1377 mGeometryString.append(
"</", 2 );
1378 mGeometryString.append( pszLocalName, localNameLen );
1379 mGeometryString.append(
">", 1 );
1383void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1386 if ( mParseModeStack.isEmpty() )
1391 if ( !mGeometryString.empty() )
1393 mGeometryString.append( chars, len );
1396 const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1397 if ( parseMode == QgsGmlStreamingParser::Attribute
1398 || parseMode == QgsGmlStreamingParser::AttributeTuple
1399 || parseMode == QgsGmlStreamingParser::Coordinate
1400 || parseMode == QgsGmlStreamingParser::PosList
1401 || parseMode == QgsGmlStreamingParser::LowerCorner
1402 || parseMode == QgsGmlStreamingParser::UpperCorner
1403 || parseMode == QgsGmlStreamingParser::ExceptionText )
1405 mStringCash.append( QString::fromUtf8( chars, len ) );
1409void QgsGmlStreamingParser::addStringContentToJson()
1411 const QString s( mStringCash.trimmed() );
1414 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1415 auto textIter = jsonParent.find(
"_text" );
1416 if ( textIter != jsonParent.end() )
1418 if ( textIter->type() != json::value_t::array )
1420 auto array = json::array();
1421 array.emplace_back( std::move( *textIter ) );
1424 textIter->emplace_back( jsonFromString( s ) );
1428 jsonParent.emplace(
"_text", jsonFromString( s ) );
1431 mStringCash.clear();
1434void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1437 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1438 bool conversionOk =
true;
1439 if ( att_it != mThematicAttributes.constEnd() )
1442 switch ( att_it.value().second.type() )
1444 case QMetaType::Type::Double:
1445 var = QVariant( value.toDouble( &conversionOk ) );
1447 case QMetaType::Type::Int:
1448 var = QVariant( value.toInt( &conversionOk ) );
1450 case QMetaType::Type::LongLong:
1451 var = QVariant( value.toLongLong( &conversionOk ) );
1453 case QMetaType::Type::QDateTime:
1454 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1457 var = QVariant( value );
1460 if ( !conversionOk )
1464 Q_ASSERT( mCurrentFeature );
1465 mCurrentFeature->setAttribute( att_it.value().first, var );
1469int QgsGmlStreamingParser::readSrsNameAndDimensionAttributes(
const XML_Char **attr )
1471 int elDimension = 0;
1472 for (
int i = 0; attr[i] && attr[i + 1]; i += 2 )
1474 if ( strcmp( attr[i],
"srsName" ) == 0 )
1476 const QString
srsName( attr[i + 1] );
1477 if ( mSrsName.isEmpty() )
1491 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1495 if ( elDimension == 0 )
1496 elDimension = mDimensionForCurSrsName;
1500 else if (
srsName == mSrsName && elDimension == 0 )
1502 elDimension = mDimensionForCurSrsName;
1505 else if ( strcmp( attr[i],
"srsDimension" ) == 0 )
1507 const QString srsDimension( attr[i + 1] );
1509 const int dimension = srsDimension.toInt( &ok );
1512 elDimension = dimension;
1520QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1525 if ( attributeName.compare( attr[i] ) == 0 )
1527 return QString::fromUtf8( attr[i + 1] );
1534bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1536 QList<QgsPoint> points;
1537 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1542 if ( points.size() < 2 )
1547 r.
set( points[0], points[1] );
1552int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPoint> &points,
const QString &coordString,
int *dimension )
const
1555 const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1556 QStringList tuples_coordinates;
1558 bool conversionSuccess;
1563 QStringList::const_iterator tupleIterator;
1564 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1566 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1569 *dimension = std::max( *dimension,
static_cast<int>( tuples_coordinates.size() ) );
1571 if ( tuples_coordinates.size() < 2 )
1575 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1576 if ( !conversionSuccess )
1580 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1581 if ( !conversionSuccess )
1585 if ( tuples_coordinates.size() > 2 )
1587 z = tuples_coordinates.at( 2 ).toDouble( &conversionSuccess );
1588 if ( !conversionSuccess )
1595 z = std::numeric_limits<double>::quiet_NaN();
1597 points.push_back( ( mInvertAxisOrientation ) ? QgsPoint( y, x, z ) : QgsPoint( x, y, z ) );
1600 if ( dimension && *dimension == 0 )
1608int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPoint> &points,
const QString &coordString,
int dimension )
const
1611 const QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1613 if ( coordinates.size() % dimension != 0 )
1618 const int ncoor = coordinates.size() / dimension;
1619 for (
int i = 0; i < ncoor; i++ )
1621 bool conversionSuccess;
1622 const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1623 if ( !conversionSuccess )
1627 const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1628 if ( !conversionSuccess )
1632 double z = std::numeric_limits<double>::quiet_NaN();
1633 if ( dimension > 2 )
1635 z = coordinates.value( i * dimension + 2 ).toDouble( &conversionSuccess );
1636 if ( !conversionSuccess )
1641 points.append( mInvertAxisOrientation ? QgsPoint( y, x, z ) : QgsPoint( x, y, z ) );
1646int QgsGmlStreamingParser::pointsFromString( QList<QgsPoint> &points,
const QString &coordString,
int *dimension )
const
1648 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1650 return pointsFromCoordinateString( points, coordString, dimension );
1652 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1656 *dimension = mDimension ? mDimension : 2;
1658 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1663int QgsGmlStreamingParser::getPointWKB( QByteArray &wkbPtr,
const QgsPoint &point,
int dimension )
const
1665 const int wkbSize = 1 +
static_cast<int>(
sizeof( int ) ) + dimension *
static_cast<int>(
sizeof(
double ) );
1666 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1668 QgsWkbPtr fillPtr( wkbPtr );
1670 if ( dimension > 2 )
1672 fillPtr << point.
z();
1678int QgsGmlStreamingParser::getLineWKB( QByteArray &wkbPtr,
const QList<QgsPoint> &lineCoordinates,
int dimension )
const
1680 const int wkbSize = 1 + 2 *
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( lineCoordinates.size() ) * dimension *
static_cast<int>(
sizeof( double ) );
1681 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1683 QgsWkbPtr fillPtr( wkbPtr );
1687 QList<QgsPoint>::const_iterator iter;
1688 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1690 fillPtr << iter->x() << iter->y();
1691 if ( dimension > 2 )
1693 fillPtr << iter->z();
1700int QgsGmlStreamingParser::getRingWKB( QByteArray &wkbPtr,
const QList<QgsPoint> &ringCoordinates,
int dimension )
const
1702 const int wkbSize =
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( ringCoordinates.size() ) * dimension *
static_cast<int>(
sizeof( double ) );
1703 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1705 QgsWkbPtr fillPtr( wkbPtr );
1707 fillPtr << ringCoordinates.size();
1709 QList<QgsPoint>::const_iterator iter;
1710 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1712 fillPtr << iter->x() << iter->y();
1713 if ( dimension > 2 )
1715 fillPtr << iter->z();
1722int QgsGmlStreamingParser::createMultiLineFromFragments()
1724 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1725 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1727 QgsWkbPtr wkbPtr( mCurrentWKB );
1732 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1733 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1735 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1736 wkbPtr += wkbIt->size();
1739 mCurrentWKBFragments.clear();
1744int QgsGmlStreamingParser::createMultiPointFromFragments()
1746 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1747 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1749 QgsWkbPtr wkbPtr( mCurrentWKB );
1752 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1753 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1755 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1756 wkbPtr += wkbIt->size();
1759 mCurrentWKBFragments.clear();
1765int QgsGmlStreamingParser::createPolygonFromFragments()
1767 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1768 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1770 QgsWkbPtr wkbPtr( mCurrentWKB );
1773 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1774 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1776 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1777 wkbPtr += wkbIt->size();
1780 mCurrentWKBFragments.clear();
1785int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1788 size += 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) );
1789 size += totalWKBFragmentSize();
1790 size += mCurrentWKBFragments.size() * ( 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof( int ) ) );
1792 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1794 QgsWkbPtr wkbPtr( mCurrentWKB );
1798 auto outerWkbIt = mCurrentWKBFragments.constBegin();
1800 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1805 auto innerWkbIt = outerWkbIt->constBegin();
1806 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1808 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1809 wkbPtr += innerWkbIt->size();
1813 mCurrentWKBFragments.clear();
1818int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1821 for (
const QList<QByteArray> &list : std::as_const( mCurrentWKBFragments ) )
1823 for (
const QByteArray &i : list )
1831void QgsGmlStreamingParser::createParser(
const QByteArray &encoding )
1833 Q_ASSERT( !mParser );
1835 mParser = XML_ParserCreateNS( encoding.isEmpty() ?
nullptr : encoding.data(), NS_SEPARATOR );
1836 XML_SetUserData( mParser,
this );
1837 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
1838 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.
static Q_INVOKABLE QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
QgsGeometry combine(const QgsGeometry &geometry, const QgsGeometryParameters ¶meters=QgsGeometryParameters(), QgsFeedback *feedback=nullptr) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
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)