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#if ( XML_MAJOR_VERSION > 2 || ( XML_MAJOR_VERSION == 2 && XML_MINOR_VERSION >= 9 ) )
477 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" ).arg( XML_ErrorString( errorCode ) ).arg( XML_GetCurrentLineNumber64( mParser ) ).arg( XML_GetCurrentColumnNumber64( mParser ) );
479 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" ).arg( XML_ErrorString( errorCode ) ).arg( XML_GetCurrentLineNumber( mParser ) ).arg( XML_GetCurrentColumnNumber( mParser ) );
490 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
491 mFeatureList.clear();
499static json jsonFromString(
const QString &s )
504 if ( s.indexOf(
'.' ) >= 0 || s.indexOf(
'e' ) >= 0 )
506 const auto doubleVal = s.toDouble( &conversionOk );
509 return json( doubleVal );
514 else if ( !s.isEmpty() && s[0] !=
'0' )
516 const auto longlongVal = s.toLongLong( &conversionOk );
519 return json( longlongVal );
523 return json( s.toStdString() );
526#define LOCALNAME_EQUALS( string_constant ) ( localNameLen == static_cast<int>( strlen( string_constant ) ) && memcmp( pszLocalName, string_constant, localNameLen ) == 0 )
528void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
530 const int elLen =
static_cast<int>( strlen( el ) );
531 const char *pszSep = strchr( el, NS_SEPARATOR );
532 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
533 const int nsLen = ( pszSep ) ? (
int ) ( pszSep - el ) : 0;
534 const int localNameLen = ( pszSep ) ? (
int ) ( elLen - nsLen ) - 1 : elLen;
535 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
539 if ( !mGMLNameSpaceURIPtr && pszSep )
553 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
556 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList || parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
558 mGeometryString.append(
"<", 1 );
559 mGeometryString.append( pszLocalName, localNameLen );
560 mGeometryString.append(
" ", 1 );
561 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
563 const size_t nAttrLen = strlen( attrIter[0] );
566 if ( nAttrLen > GML32_NAMESPACE_LEN && attrIter[0][GML32_NAMESPACE_LEN] ==
'?' && memcmp( attrIter[0],
GML32_NAMESPACE, GML32_NAMESPACE_LEN ) == 0 )
568 mGeometryString.append(
"gml:" );
569 mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
571 else if ( nAttrLen > GML_NAMESPACE_LEN && attrIter[0][GML_NAMESPACE_LEN] ==
'?' && memcmp( attrIter[0],
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
573 mGeometryString.append(
"gml:" );
574 mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
578 mGeometryString.append( attrIter[0] );
580 mGeometryString.append(
"=\"", 2 );
581 mGeometryString.append( attrIter[1] );
582 mGeometryString.append(
"\" ", 2 );
584 mGeometryString.append(
">", 1 );
587 if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
589 mParseModeStack.push( Coordinate );
590 mCoorMode = QgsGmlStreamingParser::Coordinate;
592 mCoordinateSeparator = readAttribute( u
"cs"_s, attr );
593 if ( mCoordinateSeparator.isEmpty() )
595 mCoordinateSeparator =
',';
597 mTupleSeparator = readAttribute( u
"ts"_s, attr );
598 if ( mTupleSeparator.isEmpty() )
600 mTupleSeparator =
' ';
605 mParseModeStack.push( QgsGmlStreamingParser::PosList );
606 if ( mCoorMode == QgsGmlStreamingParser::PosList )
608 if ( !mStringCash.isEmpty() )
610 mStringCash.append(
' '_L1 );
617 mCoorMode = QgsGmlStreamingParser::PosList;
618 elDimension = readSrsNameAndDimensionAttributes( attr );
620 else if ( ( parseMode == Feature || parseMode == FeatureTuple )
622 && localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len )
623 && memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
625 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
626 mFoundUnhandledGeometryElement =
false;
627 mGeometryString.clear();
631 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
633 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
635 mBoundedByNullFound =
false;
637 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"null" ) )
639 mParseModeStack.push( QgsGmlStreamingParser::Null );
640 mBoundedByNullFound =
true;
642 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
645 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
647 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
649 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
652 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
654 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
657 else if ( parseMode == None && !mTypeNamePtr &&
LOCALNAME_EQUALS(
"Tuple" ) )
659 Q_ASSERT( !mCurrentFeature );
660 mCurrentFeature =
new QgsFeature( mFeatureCount );
662 const QgsAttributes attributes( mThematicAttributes.size() );
664 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
665 mCurrentFeatureId.clear();
667 else if ( parseMode == Tuple )
669 const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
670 const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
671 if ( iter != mMapTypeNameToProperties.constEnd() )
673 mFeatureTupleDepth = mParseDepth;
674 mCurrentTypename = currentTypename;
675 mGeometryAttribute.clear();
676 if ( mCurrentWKB.size() == 0 )
678 mGeometryAttribute = iter.value().mGeometryAttribute;
680 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
681 mGeometryAttributePtr = mGeometryAttributeBA.constData();
682 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
683 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
685 if ( mGMLNameSpaceURI.isEmpty() )
687 id = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
695 id = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
704 id = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
705 if ( !mCurrentFeatureId.isEmpty() )
706 mCurrentFeatureId +=
'|';
707 mCurrentFeatureId += id;
710 else if ( parseMode == None && localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) && mTypeNamePtr && memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
712 Q_ASSERT( !mCurrentFeature );
713 mCurrentFeature =
new QgsFeature( mFeatureCount );
715 const QgsAttributes attributes( mThematicAttributes.size() );
717 mParseModeStack.push( QgsGmlStreamingParser::Feature );
718 mCurrentXPathWithinFeature.clear();
719 mCurrentFeatureId = readAttribute( u
"fid"_s, attr );
720 if ( mCurrentFeatureId.isEmpty() )
725 if ( mGMLNameSpaceURI.isEmpty() )
727 mCurrentFeatureId = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
728 if ( !mCurrentFeatureId.isEmpty() )
735 mCurrentFeatureId = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
736 if ( !mCurrentFeatureId.isEmpty() )
744 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
748 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
752 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
756 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"LineString" ) )
760 else if ( !mAttributeValIsNested && isGMLNS && localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
763 mCurrentWKBFragments.push_back( QList<QByteArray>() );
765 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
768 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
770 mCurrentWKBFragments.push_back( QList<QByteArray>() );
775 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
777 mCurrentWKBFragments.push_back( QList<QByteArray>() );
782 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
784 else if ( parseMode == FeatureTuple )
786 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
787 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
789 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
790 mAttributeName = mCurrentTypename +
'|' + localName;
794 else if ( parseMode == Feature )
796 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
797 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
799 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
800 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
801 if ( !mCurrentXPathWithinFeature.isEmpty() )
802 mCurrentXPathWithinFeature.append(
'/' );
803 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
805 mCurrentXPathWithinFeature.append( *nsIter );
806 mCurrentXPathWithinFeature.append(
':' );
808 mCurrentXPathWithinFeature.append( localName );
809 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( mCurrentXPathWithinFeature );
810 mAttributeValIsNested =
false;
811 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
813 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
814 mAttributeDepth = mParseDepth;
815 mAttributeName = xpathIter->first;
816 mAttributeValIsNested = xpathIter->second;
817 if ( mAttributeValIsNested )
819 mAttributeJson = json::object();
820 mAttributeJsonCurrentStack.clear();
821 mAttributeJsonCurrentStack.push( &mAttributeJson );
826 else if ( mThematicAttributes.contains( localName ) )
828 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
829 mAttributeDepth = mParseDepth;
830 mAttributeName = localName;
837 if ( localName.compare(
"attribute"_L1, Qt::CaseInsensitive ) == 0 )
839 const QString name = readAttribute( u
"name"_s, attr );
840 if ( mThematicAttributes.contains( name ) )
842 const QString value = readAttribute( u
"value"_s, attr );
843 setAttribute( name, value );
848 else if ( parseMode == Attribute && mAttributeValIsNested )
850 const std::string localName( pszLocalName, localNameLen );
851 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
852 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
853 const std::string nodeName = nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() ? ( *nsIter ).toStdString() +
':' + localName : localName;
855 addStringContentToJson();
857 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
858 auto iter = jsonParent.find( nodeName );
859 if ( iter != jsonParent.end() )
861 if ( iter->type() != json::value_t::array )
863 auto array = json::array();
864 array.emplace_back( std::move( *iter ) );
867 iter->push_back( json::object() );
868 mAttributeJsonCurrentStack.push( &( iter->back() ) );
872 auto res = jsonParent.emplace( nodeName, json::object() );
876 nlohmann::json *ptr = &( *( res.first ) );
878 mAttributeJsonCurrentStack.push( ptr );
883 QString
numberReturned = readAttribute( u
"numberReturned"_s, attr );
889 mNumberReturned = -1;
891 const QString
numberMatched = readAttribute( u
"numberMatched"_s, attr );
899 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
904 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
909 mTruncatedResponse =
true;
911 else if ( !mGeometryString.empty()
927 mFoundUnhandledGeometryElement =
true;
931 if ( !mParseModeStack.isEmpty() && ( mParseModeStack.back() == Feature || mParseModeStack.back() == Attribute ) && !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
933 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
935 const char *questionMark = strchr( attrIter[0],
'?' );
939 const QString nsURI( QString::fromUtf8( attrIter[0],
static_cast<int>( questionMark - attrIter[0] ) ) );
940 const QString localName( QString::fromUtf8( questionMark + 1 ) );
941 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
942 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
944 key.append( *nsIter );
947 key.append( localName );
951 const QString localName( QString::fromUtf8( attrIter[0] ) );
952 key.append( localName );
955 if ( mAttributeValIsNested && mParseModeStack.back() == Attribute )
957 mAttributeJsonCurrentStack.top()->emplace( key.toStdString(), jsonFromString( QString::fromUtf8( attrIter[1] ) ) );
961 QString xpath( mCurrentXPathWithinFeature );
962 if ( !xpath.isEmpty() )
965 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( xpath );
966 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
968 setAttribute( xpathIter->first, QString::fromUtf8( attrIter[1] ) );
974 if ( !mGeometryString.empty() )
979 elDimension = readSrsNameAndDimensionAttributes( attr );
982 if ( elDimension != 0 || mDimensionStack.isEmpty() )
984 mDimensionStack.push( elDimension );
988 mDimensionStack.push( mDimensionStack.back() );
994void QgsGmlStreamingParser::endElement(
const XML_Char *el )
998 const int elLen =
static_cast<int>( strlen( el ) );
999 const char *pszSep = strchr( el, NS_SEPARATOR );
1000 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
1001 const int nsLen = ( pszSep ) ? (
int ) ( pszSep - el ) : 0;
1002 const int localNameLen = ( pszSep ) ? (
int ) ( elLen - nsLen ) - 1 : elLen;
1003 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
1005 const int lastDimension = mDimensionStack.isEmpty() ? 2 : mDimensionStack.pop();
1007 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
1009 if ( parseMode == Feature || ( parseMode == Attribute && mAttributeDepth == mParseDepth ) )
1011 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
1013 const auto nPos = mCurrentXPathWithinFeature.lastIndexOf(
'/' );
1015 mCurrentXPathWithinFeature.clear();
1017 mCurrentXPathWithinFeature.resize( nPos );
1021 if ( parseMode == Attribute && mAttributeValIsNested )
1023 if ( !mStringCash.isEmpty() )
1026 if ( localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) && memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1032 if ( mInvertAxisOrientation )
1034 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1036 Q_ASSERT( mCurrentFeature );
1040 QgsGeometry currentGeometry = mCurrentFeature->geometry();
1041 if ( !currentGeometry.
isNull() )
1043 g = g.
combine( currentGeometry );
1045 mCurrentFeature->setGeometry( g );
1050 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1051 if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
1053 jsonParent = jsonFromString( mStringCash );
1055 else if ( jsonParent.type() == json::value_t::object )
1057 addStringContentToJson();
1059 mStringCash.clear();
1061 mAttributeJsonCurrentStack.pop();
1064 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
1066 mParseModeStack.pop();
1070 mDimension = lastDimension;
1071 mParseModeStack.pop();
1073 else if ( parseMode == AttributeTuple && mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
1075 mParseModeStack.pop();
1077 setAttribute( mAttributeName, mStringCash );
1079 else if ( parseMode == Attribute && mAttributeDepth == mParseDepth )
1081 mParseModeStack.pop();
1084 if ( mAttributeValIsNested )
1086 mAttributeValIsNested =
false;
1087 auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
1088 if ( iter == mMapFieldNameToJSONContent.end() )
1090 mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
1094 QString &str = iter.value();
1095 if ( str[0] ==
'[' && str.back() ==
']' )
1101 str.insert( 0,
'[' );
1104 str.append( QString::fromStdString( mAttributeJson.dump() ) );
1110 setAttribute( mAttributeName, mStringCash );
1113 else if ( parseMode == Geometry && localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) && memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1115 mParseModeStack.pop();
1116 if ( mFoundUnhandledGeometryElement )
1122 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
1123 unsigned char *pabyBuffer =
new unsigned char[wkbSize];
1124 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
1126 g.
fromWkb( pabyBuffer, wkbSize );
1127 if ( mInvertAxisOrientation )
1129 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1131 Q_ASSERT( mCurrentFeature );
1132 mCurrentFeature->setGeometry( g );
1135 mGeometryString.clear();
1137 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
1140 if ( mCurrentExtent.isNull() && !mBoundedByNullFound && !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
1144 if ( !mCurrentExtent.isNull() && mLayerExtent.isNull() && !mCurrentFeature && mFeatureCount == 0 )
1146 mLayerExtent = mCurrentExtent;
1147 mCurrentExtent = QgsRectangle();
1150 mParseModeStack.pop();
1154 mParseModeStack.pop();
1156 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
1158 mParseModeStack.pop();
1160 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
1162 QList<QgsPoint> points;
1163 pointsFromPosListString( points, mStringCash, 2 );
1164 if ( points.size() == 1 )
1166 mCurrentExtent.setXMinimum( points[0].x() );
1167 mCurrentExtent.setYMinimum( points[0].y() );
1169 mParseModeStack.pop();
1171 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
1173 QList<QgsPoint> points;
1174 pointsFromPosListString( points, mStringCash, 2 );
1175 if ( points.size() == 1 )
1177 mCurrentExtent.setXMaximum( points[0].x() );
1178 mCurrentExtent.setYMaximum( points[0].y() );
1180 mParseModeStack.pop();
1182 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
1184 mParseModeStack.pop();
1185 mFeatureTupleDepth = 0;
1187 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
LOCALNAME_EQUALS(
"Tuple" ) )
1188 || ( parseMode == Feature && localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) && memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
1190 Q_ASSERT( mCurrentFeature );
1191 if ( !mCurrentFeature->hasGeometry() )
1193 if ( mCurrentWKB.size() > 0 )
1197 mCurrentFeature->setGeometry( g );
1198 mCurrentWKB = QByteArray();
1200 else if ( !mCurrentExtent.isEmpty() )
1205 mCurrentFeature->setValid(
true );
1207 for (
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
1209 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
1210 const int attrIndex = att_it.value().first;
1211 mCurrentFeature->setAttribute( attrIndex, iter.value() );
1213 mMapFieldNameToJSONContent.clear();
1217 mCurrentFeature =
nullptr;
1219 mParseModeStack.pop();
1221 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
1223 QList<QgsPoint> pointList;
1225 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1229 mStringCash.clear();
1230 mDimension = dimension;
1232 if ( pointList.isEmpty() )
1235 if ( parseMode == QgsGmlStreamingParser::Geometry )
1238 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ), dimension ) != 0 )
1251 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ), dimension ) != 0 )
1255 if ( !mCurrentWKBFragments.isEmpty() )
1257 mCurrentWKBFragments.last().push_back( wkbPtr );
1269 QList<QgsPoint> pointList;
1271 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1275 mStringCash.clear();
1276 mDimension = dimension;
1278 if ( parseMode == QgsGmlStreamingParser::Geometry )
1280 if ( getLineWKB( mCurrentWKB, pointList, dimension ) != 0 )
1289 else if ( dimension > 2 )
1293 mDimension = dimension;
1298 if ( getLineWKB( wkbPtr, pointList, dimension ) != 0 )
1302 mDimension = dimension;
1303 if ( !mCurrentWKBFragments.isEmpty() )
1305 mCurrentWKBFragments.last().push_back( wkbPtr );
1313 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
LOCALNAME_EQUALS(
"LinearRing" ) )
1315 QList<QgsPoint> pointList;
1317 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1321 mStringCash.clear();
1322 mDimension = dimension;
1325 if ( getRingWKB( wkbPtr, pointList, dimension ) != 0 )
1330 if ( !mCurrentWKBFragments.isEmpty() )
1332 mCurrentWKBFragments.last().push_back( wkbPtr );
1339 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
LOCALNAME_EQUALS(
"Polygon" ) )
1346 if ( parseMode == Geometry )
1348 createPolygonFromFragments();
1351 else if ( parseMode == MultiPoint && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
1354 mParseModeStack.pop();
1355 createMultiPointFromFragments();
1360 mParseModeStack.pop();
1361 createMultiLineFromFragments();
1366 mParseModeStack.pop();
1367 createMultiPolygonFromFragments();
1371 mParseModeStack.pop();
1373 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1375 mExceptionText = mStringCash;
1376 mParseModeStack.pop();
1379 if ( !mGeometryString.empty() )
1381 mGeometryString.append(
"</", 2 );
1382 mGeometryString.append( pszLocalName, localNameLen );
1383 mGeometryString.append(
">", 1 );
1387void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1390 if ( mParseModeStack.isEmpty() )
1395 if ( !mGeometryString.empty() )
1397 mGeometryString.append( chars, len );
1400 const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1401 if ( parseMode == QgsGmlStreamingParser::Attribute
1402 || parseMode == QgsGmlStreamingParser::AttributeTuple
1403 || parseMode == QgsGmlStreamingParser::Coordinate
1404 || parseMode == QgsGmlStreamingParser::PosList
1405 || parseMode == QgsGmlStreamingParser::LowerCorner
1406 || parseMode == QgsGmlStreamingParser::UpperCorner
1407 || parseMode == QgsGmlStreamingParser::ExceptionText )
1409 mStringCash.append( QString::fromUtf8( chars, len ) );
1413void QgsGmlStreamingParser::addStringContentToJson()
1415 const QString s( mStringCash.trimmed() );
1418 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1419 auto textIter = jsonParent.find(
"_text" );
1420 if ( textIter != jsonParent.end() )
1422 if ( textIter->type() != json::value_t::array )
1424 auto array = json::array();
1425 array.emplace_back( std::move( *textIter ) );
1428 textIter->emplace_back( jsonFromString( s ) );
1432 jsonParent.emplace(
"_text", jsonFromString( s ) );
1435 mStringCash.clear();
1438void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1441 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1442 bool conversionOk =
true;
1443 if ( att_it != mThematicAttributes.constEnd() )
1446 switch ( att_it.value().second.type() )
1448 case QMetaType::Type::Double:
1449 var = QVariant( value.toDouble( &conversionOk ) );
1451 case QMetaType::Type::Int:
1452 var = QVariant( value.toInt( &conversionOk ) );
1454 case QMetaType::Type::LongLong:
1455 var = QVariant( value.toLongLong( &conversionOk ) );
1457 case QMetaType::Type::QDateTime:
1458 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1461 var = QVariant( value );
1464 if ( !conversionOk )
1468 Q_ASSERT( mCurrentFeature );
1469 mCurrentFeature->setAttribute( att_it.value().first, var );
1473int QgsGmlStreamingParser::readSrsNameAndDimensionAttributes(
const XML_Char **attr )
1475 int elDimension = 0;
1476 for (
int i = 0; attr[i] && attr[i + 1]; i += 2 )
1478 if ( strcmp( attr[i],
"srsName" ) == 0 )
1480 const QString
srsName( attr[i + 1] );
1481 if ( mSrsName.isEmpty() )
1495 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1499 if ( elDimension == 0 )
1500 elDimension = mDimensionForCurSrsName;
1504 else if (
srsName == mSrsName && elDimension == 0 )
1506 elDimension = mDimensionForCurSrsName;
1509 else if ( strcmp( attr[i],
"srsDimension" ) == 0 )
1511 const QString srsDimension( attr[i + 1] );
1513 const int dimension = srsDimension.toInt( &ok );
1516 elDimension = dimension;
1524QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1529 if ( attributeName.compare( attr[i] ) == 0 )
1531 return QString::fromUtf8( attr[i + 1] );
1538bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1540 QList<QgsPoint> points;
1541 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1546 if ( points.size() < 2 )
1551 r.
set( points[0], points[1] );
1556int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPoint> &points,
const QString &coordString,
int *dimension )
const
1559 const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1560 QStringList tuples_coordinates;
1562 bool conversionSuccess;
1567 QStringList::const_iterator tupleIterator;
1568 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1570 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1573 *dimension = std::max( *dimension,
static_cast<int>( tuples_coordinates.size() ) );
1575 if ( tuples_coordinates.size() < 2 )
1579 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1580 if ( !conversionSuccess )
1584 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1585 if ( !conversionSuccess )
1589 if ( tuples_coordinates.size() > 2 )
1591 z = tuples_coordinates.at( 2 ).toDouble( &conversionSuccess );
1592 if ( !conversionSuccess )
1599 z = std::numeric_limits<double>::quiet_NaN();
1601 points.push_back( ( mInvertAxisOrientation ) ? QgsPoint( y, x, z ) : QgsPoint( x, y, z ) );
1604 if ( dimension && *dimension == 0 )
1612int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPoint> &points,
const QString &coordString,
int dimension )
const
1615 const QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1617 if ( coordinates.size() % dimension != 0 )
1622 const int ncoor = coordinates.size() / dimension;
1623 for (
int i = 0; i < ncoor; i++ )
1625 bool conversionSuccess;
1626 const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1627 if ( !conversionSuccess )
1631 const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1632 if ( !conversionSuccess )
1636 double z = std::numeric_limits<double>::quiet_NaN();
1637 if ( dimension > 2 )
1639 z = coordinates.value( i * dimension + 2 ).toDouble( &conversionSuccess );
1640 if ( !conversionSuccess )
1645 points.append( mInvertAxisOrientation ? QgsPoint( y, x, z ) : QgsPoint( x, y, z ) );
1650int QgsGmlStreamingParser::pointsFromString( QList<QgsPoint> &points,
const QString &coordString,
int *dimension )
const
1652 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1654 return pointsFromCoordinateString( points, coordString, dimension );
1656 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1660 *dimension = mDimension ? mDimension : 2;
1662 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1667int QgsGmlStreamingParser::getPointWKB( QByteArray &wkbPtr,
const QgsPoint &point,
int dimension )
const
1669 const int wkbSize = 1 +
static_cast<int>(
sizeof( int ) ) + dimension *
static_cast<int>(
sizeof(
double ) );
1670 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1672 QgsWkbPtr fillPtr( wkbPtr );
1674 if ( dimension > 2 )
1676 fillPtr << point.
z();
1682int QgsGmlStreamingParser::getLineWKB( QByteArray &wkbPtr,
const QList<QgsPoint> &lineCoordinates,
int dimension )
const
1684 const int wkbSize = 1 + 2 *
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( lineCoordinates.size() ) * dimension *
static_cast<int>(
sizeof( double ) );
1685 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1687 QgsWkbPtr fillPtr( wkbPtr );
1691 QList<QgsPoint>::const_iterator iter;
1692 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1694 fillPtr << iter->x() << iter->y();
1695 if ( dimension > 2 )
1697 fillPtr << iter->z();
1704int QgsGmlStreamingParser::getRingWKB( QByteArray &wkbPtr,
const QList<QgsPoint> &ringCoordinates,
int dimension )
const
1706 const int wkbSize =
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( ringCoordinates.size() ) * dimension *
static_cast<int>(
sizeof( double ) );
1707 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1709 QgsWkbPtr fillPtr( wkbPtr );
1711 fillPtr << ringCoordinates.size();
1713 QList<QgsPoint>::const_iterator iter;
1714 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1716 fillPtr << iter->x() << iter->y();
1717 if ( dimension > 2 )
1719 fillPtr << iter->z();
1726int QgsGmlStreamingParser::createMultiLineFromFragments()
1728 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1729 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1731 QgsWkbPtr wkbPtr( mCurrentWKB );
1736 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1737 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1739 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1740 wkbPtr += wkbIt->size();
1743 mCurrentWKBFragments.clear();
1748int QgsGmlStreamingParser::createMultiPointFromFragments()
1750 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1751 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1753 QgsWkbPtr wkbPtr( mCurrentWKB );
1756 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1757 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1759 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1760 wkbPtr += wkbIt->size();
1763 mCurrentWKBFragments.clear();
1769int QgsGmlStreamingParser::createPolygonFromFragments()
1771 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1772 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1774 QgsWkbPtr wkbPtr( mCurrentWKB );
1777 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1778 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1780 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1781 wkbPtr += wkbIt->size();
1784 mCurrentWKBFragments.clear();
1789int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1792 size += 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) );
1793 size += totalWKBFragmentSize();
1794 size += mCurrentWKBFragments.size() * ( 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof( int ) ) );
1796 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1798 QgsWkbPtr wkbPtr( mCurrentWKB );
1802 auto outerWkbIt = mCurrentWKBFragments.constBegin();
1804 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1809 auto innerWkbIt = outerWkbIt->constBegin();
1810 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1812 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1813 wkbPtr += innerWkbIt->size();
1817 mCurrentWKBFragments.clear();
1822int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1825 for (
const QList<QByteArray> &list : std::as_const( mCurrentWKBFragments ) )
1827 for (
const QByteArray &i : list )
1835void QgsGmlStreamingParser::createParser(
const QByteArray &encoding )
1837 Q_ASSERT( !mParser );
1839 mParser = XML_ParserCreateNS( encoding.isEmpty() ?
nullptr : encoding.data(), NS_SEPARATOR );
1840 XML_SetUserData( mParser,
this );
1841 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
1842 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)