35#include <QNetworkReply>
36#include <QNetworkRequest>
37#include <QProgressDialog>
38#include <QRegularExpression>
44#include "moc_qgsgml.cpp"
46using namespace nlohmann;
48#ifndef NS_SEPARATOR_DEFINED
49#define NS_SEPARATOR_DEFINED
50static const char NS_SEPARATOR =
'?';
53static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
57 const QString &typeName,
58 const QString &geometryAttribute,
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() )
83 tr(
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
90 else if ( !userName.isNull() || !password.isNull() )
92 request.setRawHeader(
"Authorization",
"Basic " + QStringLiteral(
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
96 if ( !authcfg.isEmpty() )
100 reply->deleteLater();
102 tr(
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
110 connect( reply, &QNetworkReply::finished,
this, &QgsGml::setFinished );
111 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsGml::handleProgressEvent );
114 QProgressDialog *progressDialog =
nullptr;
115 QWidget *mainWindow =
nullptr;
116 const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
117 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
119 if ( ( *it )->objectName() == QLatin1String(
"QgisApp" ) )
127 progressDialog =
new QProgressDialog( tr(
"Loading GML data\n%1" ).arg( mTypeName ), tr(
"Abort" ), 0, 0, mainWindow );
128 progressDialog->setWindowModality( Qt::ApplicationModal );
131 connect( progressDialog, &QProgressDialog::canceled,
this, &QgsGml::setFinished );
132 progressDialog->show();
142 const QByteArray readData = reply->readAll();
143 if ( !readData.isEmpty() )
146 if ( !mParser.processData( readData, atEnd, errorMsg ) )
150 QCoreApplication::processEvents();
153 fillMapsFromParser();
155 const QNetworkReply::NetworkError replyError = reply->error();
156 const QString replyErrorString = reply->errorString();
159 delete progressDialog;
164 tr(
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
171 *wkbType = mParser.wkbType();
175 if ( mExtent.isEmpty() )
178 calculateExtentFromFeatures();
193 if ( !mParser.processData( data,
true , errorMsg ) )
196 fillMapsFromParser();
198 *wkbType = mParser.wkbType();
206void QgsGml::fillMapsFromParser()
209 const auto constFeatures = features;
213 const QString &gmlId = featPair.second;
214 mFeatures.insert( feat->
id(), feat );
215 if ( !gmlId.isEmpty() )
217 mIdMap.insert( feat->
id(), gmlId );
222void QgsGml::setFinished()
227void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
229 if ( totalSteps < 0 )
239void QgsGml::calculateExtentFromFeatures()
241 if ( mFeatures.empty() )
246 QgsFeature *currentFeature =
nullptr;
247 QgsGeometry currentGeometry;
248 bool bboxInitialized =
false;
250 for (
int i = 0; i < mFeatures.size(); ++i )
252 currentFeature = mFeatures[i];
253 if ( !currentFeature )
257 currentGeometry = currentFeature->
geometry();
258 if ( !currentGeometry.
isNull() )
260 if ( !bboxInitialized )
263 bboxInitialized =
true;
267 mExtent.combineExtentWith( currentGeometry.
boundingBox() );
276 if ( mParser.getEPSGCode() != 0 )
288 const QString &geometryAttribute,
291 bool invertAxisOrientation )
292 : mTypeName( typeName )
293 , mTypeNameBA( mTypeName.toUtf8() )
294 , mTypeNamePtr( mTypeNameBA.constData() )
295 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
296 , mWkbType(
Qgis::WkbType::Unknown )
297 , mGeometryAttribute( geometryAttribute )
298 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
299 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
300 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
302 , mIsException( false )
303 , mTruncatedResponse( false )
305 , mFeatureTupleDepth( 0 )
307 , mCurrentWKB( nullptr, 0 )
308 , mBoundedByNullFound( false )
310 , mCoorMode( Coordinate )
312 , mAxisOrientationLogic( axisOrientationLogic )
313 , mInvertAxisOrientationRequest( invertAxisOrientation )
314 , mInvertAxisOrientation( invertAxisOrientation )
315 , mNumberReturned( -1 )
316 , mNumberMatched( -1 )
317 , mFoundUnhandledGeometryElement( false )
319 mThematicAttributes.clear();
320 for (
int i = 0; i < fields.
size(); i++ )
322 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
327 const int index = mTypeName.indexOf(
':' );
328 if ( index != -1 && index < mTypeName.length() )
330 mTypeName = mTypeName.mid( index + 1 );
331 mTypeNameBA = mTypeName.toUtf8();
332 mTypeNamePtr = mTypeNameBA.constData();
333 mTypeNameUTF8Len = strlen( mTypeNamePtr );
339static QString stripNS(
const QString &
string )
341 const int index =
string.indexOf(
':' );
342 if ( index != -1 && index <
string.length() )
344 return string.mid( index + 1 );
351 const QMap< QString, QPair<QString, QString> > &fieldNameToSrcLayerNameFieldNameMap,
353 bool invertAxisOrientation )
354 : mLayerProperties( layerProperties )
355 , mTypeNameUTF8Len( 0 )
356 , mWkbType(
Qgis::WkbType::Unknown )
357 , mGeometryAttributeUTF8Len( 0 )
359 , mIsException( false )
360 , mTruncatedResponse( false )
362 , mFeatureTupleDepth( 0 )
364 , mCurrentWKB( nullptr, 0 )
365 , mBoundedByNullFound( false )
367 , mCoorMode( Coordinate )
369 , mAxisOrientationLogic( axisOrientationLogic )
370 , mInvertAxisOrientationRequest( invertAxisOrientation )
371 , mInvertAxisOrientation( invertAxisOrientation )
372 , mNumberReturned( -1 )
373 , mNumberMatched( -1 )
374 , mFoundUnhandledGeometryElement( false )
376 mThematicAttributes.clear();
377 for (
int i = 0; i < fields.
size(); i++ )
379 const QMap< QString, QPair<QString, QString> >::const_iterator att_it = fieldNameToSrcLayerNameFieldNameMap.constFind( fields.
at( i ).
name() );
380 if ( att_it != fieldNameToSrcLayerNameFieldNameMap.constEnd() )
382 if ( mLayerProperties.size() == 1 )
383 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
385 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
388 bool alreadyFoundGeometry =
false;
389 for (
int i = 0; i < mLayerProperties.size(); i++ )
392 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
394 if ( alreadyFoundGeometry )
396 QgsDebugMsgLevel( QStringLiteral(
"Will ignore geometry field %1 from typename %2" ).
397 arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ), 2 );
398 mLayerProperties[i].mGeometryAttribute.clear();
400 alreadyFoundGeometry =
true;
402 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
405 if ( mLayerProperties.size() == 1 )
407 mTypeName = mLayerProperties[0].mName;
408 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
409 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
410 mGeometryAttributePtr = mGeometryAttributeBA.constData();
411 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
412 const int index = mTypeName.indexOf(
':' );
413 if ( index != -1 && index < mTypeName.length() )
415 mTypeName = mTypeName.mid( index + 1 );
417 mTypeNameBA = mTypeName.toUtf8();
418 mTypeNamePtr = mTypeNameBA.constData();
419 mTypeNameUTF8Len = strlen( mTypeNamePtr );
429 const QMap<QString, QPair<QString, bool>> &fieldNameToXPathMapAndIsNestedContent,
430 const QMap<QString, QString> &mapNamespacePrefixToURI )
432 for (
auto iter = fieldNameToXPathMapAndIsNestedContent.constBegin(); iter != fieldNameToXPathMapAndIsNestedContent.constEnd(); ++iter )
434 mMapXPathToFieldNameAndIsNestedContent[iter.value().first] = QPair<QString, bool>( iter.key(), iter.value().second );
436 for (
auto iter = mapNamespacePrefixToURI.constBegin(); iter != mapNamespacePrefixToURI.constEnd(); ++iter )
437 mMapNamespaceURIToNamespacePrefix[iter.value()] = iter.key();
443 XML_ParserFree( mParser );
446 const auto constMFeatureList = mFeatureList;
449 delete featPair.first;
452 delete mCurrentFeature;
468 QByteArray data = pdata;
473 QString strData = mCodec->toUnicode( pdata );
474 data = strData.toUtf8();
477 if ( XML_Parse( mParser, data, data.size(), atEnd ) == XML_STATUS_ERROR )
479 const XML_Error errorCode = XML_GetErrorCode( mParser );
480 if ( !mCodec && errorCode == XML_ERROR_UNKNOWN_ENCODING )
484 const thread_local QRegularExpression reEncoding( QStringLiteral(
"<?xml.*encoding=['\"]([^'\"]*)['\"].*?>" ),
485 QRegularExpression::CaseInsensitiveOption );
486 QRegularExpressionMatch match = reEncoding.match( pdata );
487 const QString encoding = match.hasMatch() ? match.captured( 1 ) : QString();
488 mCodec = !encoding.isEmpty() ? QTextCodec::codecForName( encoding.toLatin1() ) :
nullptr;
492 XML_ParserFree( mParser );
494 createParser( QByteArrayLiteral(
"UTF-8" ) );
500 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" )
501 .arg( XML_ErrorString( errorCode ) )
502 .arg( XML_GetCurrentLineNumber( mParser ) )
503 .arg( XML_GetCurrentColumnNumber( mParser ) );
513 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
514 mFeatureList.clear();
522static json jsonFromString(
const QString &s )
527 if ( s.indexOf(
'.' ) >= 0 || s.indexOf(
'e' ) >= 0 )
529 const auto doubleVal = s.toDouble( &conversionOk );
532 return json( doubleVal );
537 else if ( !s.isEmpty() && s[0] !=
'0' )
539 const auto longlongVal = s.toLongLong( &conversionOk );
542 return json( longlongVal );
546 return json( s.toStdString() );
549#define LOCALNAME_EQUALS(string_constant) \
550 ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 )
552void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
554 const int elLen =
static_cast<int>( strlen( el ) );
555 const char *pszSep = strchr( el, NS_SEPARATOR );
556 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
557 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
558 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
559 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
563 if ( !mGMLNameSpaceURIPtr && pszSep )
577 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
580 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
581 parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
583 mGeometryString.append(
"<", 1 );
584 mGeometryString.append( pszLocalName, localNameLen );
585 mGeometryString.append(
" ", 1 );
586 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
588 const size_t nAttrLen = strlen( attrIter[0] );
591 if ( nAttrLen > GML32_NAMESPACE_LEN &&
592 attrIter[0][GML32_NAMESPACE_LEN] ==
'?' &&
595 mGeometryString.append(
"gml:" );
596 mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
598 else if ( nAttrLen > GML_NAMESPACE_LEN &&
599 attrIter[0][GML_NAMESPACE_LEN] ==
'?' &&
600 memcmp( attrIter[0],
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
602 mGeometryString.append(
"gml:" );
603 mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
607 mGeometryString.append( attrIter[0] );
609 mGeometryString.append(
"=\"", 2 );
610 mGeometryString.append( attrIter[1] );
611 mGeometryString.append(
"\" ", 2 );
614 mGeometryString.append(
">", 1 );
617 if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
619 mParseModeStack.push( Coordinate );
620 mCoorMode = QgsGmlStreamingParser::Coordinate;
622 mCoordinateSeparator = readAttribute( QStringLiteral(
"cs" ), attr );
623 if ( mCoordinateSeparator.isEmpty() )
625 mCoordinateSeparator =
',';
627 mTupleSeparator = readAttribute( QStringLiteral(
"ts" ), attr );
628 if ( mTupleSeparator.isEmpty() )
630 mTupleSeparator =
' ';
633 else if ( !mAttributeValIsNested && isGMLNS &&
636 mParseModeStack.push( QgsGmlStreamingParser::PosList );
637 if ( mCoorMode == QgsGmlStreamingParser::PosList )
639 if ( !mStringCash.isEmpty() )
641 mStringCash.append( QLatin1Char(
' ' ) );
648 mCoorMode = QgsGmlStreamingParser::PosList;
649 if ( elDimension == 0 )
651 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
653 const int dimension = srsDimension.toInt( &ok );
656 elDimension = dimension;
660 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
662 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
663 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
665 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
666 mFoundUnhandledGeometryElement =
false;
667 mGeometryString.clear();
671 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
673 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
675 mBoundedByNullFound =
false;
677 else if ( parseMode == BoundingBox &&
680 mParseModeStack.push( QgsGmlStreamingParser::Null );
681 mBoundedByNullFound =
true;
683 else if ( parseMode == BoundingBox &&
687 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
689 else if ( parseMode == Envelope &&
692 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
695 else if ( parseMode == Envelope &&
698 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
701 else if ( parseMode == None && !mTypeNamePtr &&
704 Q_ASSERT( !mCurrentFeature );
705 mCurrentFeature =
new QgsFeature( mFeatureCount );
707 const QgsAttributes attributes( mThematicAttributes.size() );
709 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
710 mCurrentFeatureId.clear();
712 else if ( parseMode == Tuple )
714 const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
715 const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
716 if ( iter != mMapTypeNameToProperties.constEnd() )
718 mFeatureTupleDepth = mParseDepth;
719 mCurrentTypename = currentTypename;
720 mGeometryAttribute.clear();
721 if ( mCurrentWKB.size() == 0 )
723 mGeometryAttribute = iter.value().mGeometryAttribute;
725 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
726 mGeometryAttributePtr = mGeometryAttributeBA.constData();
727 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
728 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
730 if ( mGMLNameSpaceURI.isEmpty() )
732 id = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
740 id = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
749 id = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
750 if ( !mCurrentFeatureId.isEmpty() )
751 mCurrentFeatureId +=
'|';
752 mCurrentFeatureId += id;
755 else if ( parseMode == None &&
756 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
758 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
760 Q_ASSERT( !mCurrentFeature );
761 mCurrentFeature =
new QgsFeature( mFeatureCount );
763 const QgsAttributes attributes( mThematicAttributes.size() );
765 mParseModeStack.push( QgsGmlStreamingParser::Feature );
766 mCurrentXPathWithinFeature.clear();
767 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
768 if ( mCurrentFeatureId.isEmpty() )
773 if ( mGMLNameSpaceURI.isEmpty() )
775 mCurrentFeatureId = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
776 if ( !mCurrentFeatureId.isEmpty() )
783 mCurrentFeatureId = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
784 if ( !mCurrentFeatureId.isEmpty() )
792 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
796 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
800 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
804 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"LineString" ) )
808 else if ( !mAttributeValIsNested && isGMLNS &&
809 localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
812 mCurrentWKBFragments.push_back( QList<QByteArray>() );
814 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
817 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
819 mCurrentWKBFragments.push_back( QList<QByteArray>() );
824 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
826 mCurrentWKBFragments.push_back( QList<QByteArray>() );
831 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
833 else if ( parseMode == FeatureTuple )
835 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
836 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
838 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
839 mAttributeName = mCurrentTypename +
'|' + localName;
843 else if ( parseMode == Feature )
845 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
846 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
848 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
849 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
850 if ( !mCurrentXPathWithinFeature.isEmpty() )
851 mCurrentXPathWithinFeature.append(
'/' );
852 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
854 mCurrentXPathWithinFeature.append( *nsIter );
855 mCurrentXPathWithinFeature.append(
':' );
857 mCurrentXPathWithinFeature.append( localName );
858 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( mCurrentXPathWithinFeature );
859 mAttributeValIsNested =
false;
860 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
862 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
863 mAttributeDepth = mParseDepth;
864 mAttributeName = xpathIter->first;
865 mAttributeValIsNested = xpathIter->second;
866 if ( mAttributeValIsNested )
868 mAttributeJson = json::object();
869 mAttributeJsonCurrentStack.clear();
870 mAttributeJsonCurrentStack.push( &mAttributeJson );
875 else if ( mThematicAttributes.contains( localName ) )
877 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
878 mAttributeDepth = mParseDepth;
879 mAttributeName = localName;
886 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
888 const QString name = readAttribute( QStringLiteral(
"name" ), attr );
889 if ( mThematicAttributes.contains( name ) )
891 const QString value = readAttribute( QStringLiteral(
"value" ), attr );
892 setAttribute( name, value );
897 else if ( parseMode == Attribute && mAttributeValIsNested )
899 const std::string localName( pszLocalName, localNameLen );
900 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
901 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
902 const std::string nodeName = nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() ? ( *nsIter ).toStdString() +
':' + localName : localName;
904 addStringContentToJson();
906 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
907 auto iter = jsonParent.find( nodeName );
908 if ( iter != jsonParent.end() )
910 if ( iter->type() != json::value_t::array )
912 auto array = json::array();
913 array.emplace_back( std::move( *iter ) );
916 iter->push_back( json::object() );
917 mAttributeJsonCurrentStack.push( &( iter->back() ) );
921 auto res = jsonParent.emplace( nodeName, json::object() );
925 nlohmann::json *ptr = &( *( res.first ) );
927 mAttributeJsonCurrentStack.push( ptr );
932 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
934 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
938 mNumberReturned = -1;
940 const QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
948 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
953 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
958 mTruncatedResponse =
true;
960 else if ( !mGeometryString.empty() &&
976 mFoundUnhandledGeometryElement =
true;
980 if ( !mParseModeStack.isEmpty() &&
981 ( mParseModeStack.back() == Feature ||
982 mParseModeStack.back() == Attribute ) &&
983 !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
985 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
987 const char *questionMark = strchr( attrIter[0],
'?' );
991 const QString nsURI( QString::fromUtf8( attrIter[0],
static_cast<int>( questionMark - attrIter[0] ) ) );
992 const QString localName( QString::fromUtf8( questionMark + 1 ) );
993 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
994 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
996 key.append( *nsIter );
999 key.append( localName );
1003 const QString localName( QString::fromUtf8( attrIter[0] ) );
1004 key.append( localName );
1007 if ( mAttributeValIsNested && mParseModeStack.back() == Attribute )
1009 mAttributeJsonCurrentStack.top()->emplace(
1011 jsonFromString( QString::fromUtf8( attrIter[1] ) ) );
1015 QString xpath( mCurrentXPathWithinFeature );
1016 if ( !xpath.isEmpty() )
1017 xpath.append(
'/' );
1018 xpath.append( key );
1019 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( xpath );
1020 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
1022 setAttribute( xpathIter->first, QString::fromUtf8( attrIter[1] ) );
1028 if ( !mGeometryString.empty() )
1031 if ( elDimension == 0 && isGeom )
1035 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
1037 const int dimension = srsDimension.toInt( &ok );
1040 elDimension = dimension;
1044 if ( elDimension != 0 || mDimensionStack.isEmpty() )
1046 mDimensionStack.push( elDimension );
1050 mDimensionStack.push( mDimensionStack.back() );
1053 if ( mEpsg == 0 && isGeom )
1055 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
1057 QgsDebugError( QStringLiteral(
"error, could not get epsg id" ) );
1068void QgsGmlStreamingParser::endElement(
const XML_Char *el )
1072 const int elLen =
static_cast<int>( strlen( el ) );
1073 const char *pszSep = strchr( el, NS_SEPARATOR );
1074 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
1075 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
1076 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
1077 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
1079 const int lastDimension = mDimensionStack.isEmpty() ? 2 : mDimensionStack.pop();
1081 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
1083 if ( parseMode == Feature || ( parseMode == Attribute && mAttributeDepth == mParseDepth ) )
1085 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
1087 const auto nPos = mCurrentXPathWithinFeature.lastIndexOf(
'/' );
1089 mCurrentXPathWithinFeature.clear();
1091 mCurrentXPathWithinFeature.resize( nPos );
1095 if ( parseMode == Attribute && mAttributeValIsNested )
1097 if ( !mStringCash.isEmpty() )
1099 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1100 if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
1102 jsonParent = jsonFromString( mStringCash );
1104 else if ( jsonParent.type() == json::value_t::object )
1106 addStringContentToJson();
1108 mStringCash.clear();
1111 mAttributeJsonCurrentStack.pop();
1114 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
1116 mParseModeStack.pop();
1118 else if ( parseMode == PosList && isGMLNS &&
1121 mDimension = lastDimension;
1122 mParseModeStack.pop();
1124 else if ( parseMode == AttributeTuple &&
1125 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
1127 mParseModeStack.pop();
1129 setAttribute( mAttributeName, mStringCash );
1131 else if ( parseMode == Attribute && mAttributeDepth == mParseDepth )
1133 mParseModeStack.pop();
1136 if ( mAttributeValIsNested )
1138 mAttributeValIsNested =
false;
1139 auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
1140 if ( iter == mMapFieldNameToJSONContent.end() )
1142 mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
1146 QString &str = iter.value();
1147 if ( str[0] ==
'[' && str.back() ==
']' )
1153 str.insert( 0,
'[' );
1156 str.append( QString::fromStdString( mAttributeJson.dump() ) );
1162 setAttribute( mAttributeName, mStringCash );
1165 else if ( parseMode == Geometry &&
1166 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
1167 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1169 mParseModeStack.pop();
1170 if ( mFoundUnhandledGeometryElement )
1176 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
1177 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
1178 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
1180 g.
fromWkb( pabyBuffer, wkbSize );
1181 if ( mInvertAxisOrientation )
1183 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1185 Q_ASSERT( mCurrentFeature );
1186 mCurrentFeature->setGeometry( g );
1189 mGeometryString.clear();
1191 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
1194 if ( mCurrentExtent.isNull() &&
1195 !mBoundedByNullFound &&
1196 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
1198 QgsDebugError( QStringLiteral(
"creation of bounding box failed" ) );
1200 if ( !mCurrentExtent.isNull() && mLayerExtent.isNull() &&
1201 !mCurrentFeature && mFeatureCount == 0 )
1203 mLayerExtent = mCurrentExtent;
1204 mCurrentExtent = QgsRectangle();
1207 mParseModeStack.pop();
1211 mParseModeStack.pop();
1213 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
1215 mParseModeStack.pop();
1217 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
1219 QList<QgsPoint> points;
1220 pointsFromPosListString( points, mStringCash, 2 );
1221 if ( points.size() == 1 )
1223 mCurrentExtent.setXMinimum( points[0].x() );
1224 mCurrentExtent.setYMinimum( points[0].y() );
1226 mParseModeStack.pop();
1228 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
1230 QList<QgsPoint> points;
1231 pointsFromPosListString( points, mStringCash, 2 );
1232 if ( points.size() == 1 )
1234 mCurrentExtent.setXMaximum( points[0].x() );
1235 mCurrentExtent.setYMaximum( points[0].y() );
1237 mParseModeStack.pop();
1239 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
1241 mParseModeStack.pop();
1242 mFeatureTupleDepth = 0;
1244 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
1246 ( parseMode == Feature &&
1247 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
1248 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
1250 Q_ASSERT( mCurrentFeature );
1251 if ( !mCurrentFeature->hasGeometry() )
1253 if ( mCurrentWKB.size() > 0 )
1257 mCurrentFeature->setGeometry( g );
1258 mCurrentWKB = QByteArray();
1260 else if ( !mCurrentExtent.isEmpty() )
1265 mCurrentFeature->setValid(
true );
1267 for (
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
1269 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
1270 const int attrIndex = att_it.value().first;
1271 mCurrentFeature->setAttribute( attrIndex, iter.value() );
1273 mMapFieldNameToJSONContent.clear();
1277 mCurrentFeature =
nullptr;
1279 mParseModeStack.pop();
1281 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
1283 QList<QgsPoint> pointList;
1285 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1289 mStringCash.clear();
1290 mDimension = dimension;
1292 if ( pointList.isEmpty() )
1295 if ( parseMode == QgsGmlStreamingParser::Geometry )
1298 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ), dimension ) != 0 )
1312 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ), dimension ) != 0 )
1316 if ( !mCurrentWKBFragments.isEmpty() )
1318 mCurrentWKBFragments.last().push_back( wkbPtr );
1326 else if ( !mAttributeValIsNested &&
1331 QList<QgsPoint> pointList;
1333 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1337 mStringCash.clear();
1338 mDimension = dimension;
1340 if ( parseMode == QgsGmlStreamingParser::Geometry )
1342 if ( getLineWKB( mCurrentWKB, pointList, dimension ) != 0 )
1351 else if ( dimension > 2 )
1355 mDimension = dimension;
1360 if ( getLineWKB( wkbPtr, pointList, dimension ) != 0 )
1364 mDimension = dimension;
1365 if ( !mCurrentWKBFragments.isEmpty() )
1367 mCurrentWKBFragments.last().push_back( wkbPtr );
1375 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1378 QList<QgsPoint> pointList;
1380 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1384 mStringCash.clear();
1385 mDimension = dimension;
1388 if ( getRingWKB( wkbPtr, pointList, dimension ) != 0 )
1393 if ( !mCurrentWKBFragments.isEmpty() )
1395 mCurrentWKBFragments.last().push_back( wkbPtr );
1402 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1410 if ( parseMode == Geometry )
1412 createPolygonFromFragments();
1415 else if ( parseMode == MultiPoint && isGMLNS &&
1419 mParseModeStack.pop();
1420 createMultiPointFromFragments();
1422 else if ( parseMode == MultiLine && isGMLNS &&
1426 mParseModeStack.pop();
1427 createMultiLineFromFragments();
1429 else if ( parseMode == MultiPolygon && isGMLNS &&
1433 mParseModeStack.pop();
1434 createMultiPolygonFromFragments();
1438 mParseModeStack.pop();
1440 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1442 mExceptionText = mStringCash;
1443 mParseModeStack.pop();
1446 if ( !mGeometryString.empty() )
1448 mGeometryString.append(
"</", 2 );
1449 mGeometryString.append( pszLocalName, localNameLen );
1450 mGeometryString.append(
">", 1 );
1455void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1458 if ( mParseModeStack.isEmpty() )
1463 if ( !mGeometryString.empty() )
1465 mGeometryString.append( chars, len );
1468 const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1469 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1470 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1471 parseMode == QgsGmlStreamingParser::Coordinate ||
1472 parseMode == QgsGmlStreamingParser::PosList ||
1473 parseMode == QgsGmlStreamingParser::LowerCorner ||
1474 parseMode == QgsGmlStreamingParser::UpperCorner ||
1475 parseMode == QgsGmlStreamingParser::ExceptionText )
1477 mStringCash.append( QString::fromUtf8( chars, len ) );
1481void QgsGmlStreamingParser::addStringContentToJson()
1483 const QString s( mStringCash.trimmed() );
1486 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1487 auto textIter = jsonParent.find(
"_text" );
1488 if ( textIter != jsonParent.end() )
1490 if ( textIter->type() != json::value_t::array )
1492 auto array = json::array();
1493 array.emplace_back( std::move( *textIter ) );
1496 textIter->emplace_back( jsonFromString( s ) );
1500 jsonParent.emplace(
"_text", jsonFromString( s ) );
1503 mStringCash.clear();
1506void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1509 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1510 bool conversionOk =
true;
1511 if ( att_it != mThematicAttributes.constEnd() )
1514 switch ( att_it.value().second.type() )
1516 case QMetaType::Type::Double:
1517 var = QVariant( value.toDouble( &conversionOk ) );
1519 case QMetaType::Type::Int:
1520 var = QVariant( value.toInt( &conversionOk ) );
1522 case QMetaType::Type::LongLong:
1523 var = QVariant( value.toLongLong( &conversionOk ) );
1525 case QMetaType::Type::QDateTime:
1526 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1529 var = QVariant( value );
1532 if ( ! conversionOk )
1536 Q_ASSERT( mCurrentFeature );
1537 mCurrentFeature->setAttribute( att_it.value().first, var );
1541int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1546 if ( strcmp( attr[i],
"srsName" ) == 0 )
1548 const QString
srsName( attr[i + 1] );
1560 const int eNr = code.toInt( &conversionOk );
1561 if ( !conversionOk )
1574 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1585QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1590 if ( attributeName.compare( attr[i] ) == 0 )
1592 return QString::fromUtf8( attr[i + 1] );
1599bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1601 QList<QgsPoint> points;
1602 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1607 if ( points.size() < 2 )
1612 r.
set( points[0], points[1] );
1617int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPoint> &points,
const QString &coordString,
int *dimension )
const
1620 const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1621 QStringList tuples_coordinates;
1623 bool conversionSuccess;
1628 QStringList::const_iterator tupleIterator;
1629 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1631 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1634 *dimension = std::max( *dimension,
static_cast<int>( tuples_coordinates.size() ) );
1636 if ( tuples_coordinates.size() < 2 )
1640 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1641 if ( !conversionSuccess )
1645 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1646 if ( !conversionSuccess )
1650 if ( tuples_coordinates.size() > 2 )
1652 z = tuples_coordinates.at( 2 ).toDouble( &conversionSuccess );
1653 if ( !conversionSuccess )
1660 z = std::numeric_limits<double>::quiet_NaN();
1662 points.push_back( ( mInvertAxisOrientation ) ? QgsPoint( y, x, z ) : QgsPoint( x, y, z ) );
1665 if ( dimension && *dimension == 0 )
1673int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPoint> &points,
const QString &coordString,
int dimension )
const
1676 const QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1678 if ( coordinates.size() % dimension != 0 )
1680 QgsDebugError( QStringLiteral(
"Wrong number of coordinates" ) );
1683 const int ncoor = coordinates.size() / dimension;
1684 for (
int i = 0; i < ncoor; i++ )
1686 bool conversionSuccess;
1687 const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1688 if ( !conversionSuccess )
1692 const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1693 if ( !conversionSuccess )
1697 double z = std::numeric_limits<double>::quiet_NaN();
1698 if ( dimension > 2 )
1700 z = coordinates.value( i * dimension + 2 ).toDouble( &conversionSuccess );
1701 if ( !conversionSuccess )
1706 points.append( mInvertAxisOrientation ? QgsPoint( y, x, z ) : QgsPoint( x, y, z ) );
1711int QgsGmlStreamingParser::pointsFromString( QList<QgsPoint> &points,
const QString &coordString,
int *dimension )
const
1713 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1715 return pointsFromCoordinateString( points, coordString, dimension );
1717 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1721 *dimension = mDimension ? mDimension : 2;
1723 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1728int QgsGmlStreamingParser::getPointWKB( QByteArray &wkbPtr,
const QgsPoint &point,
int dimension )
const
1730 const int wkbSize = 1 +
static_cast<int>(
sizeof( int ) ) + dimension *
static_cast<int>(
sizeof(
double ) );
1731 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1733 QgsWkbPtr fillPtr( wkbPtr );
1735 if ( dimension > 2 )
1737 fillPtr << point.
z();
1743int QgsGmlStreamingParser::getLineWKB( QByteArray &wkbPtr,
const QList<QgsPoint> &lineCoordinates,
int dimension )
const
1745 const int wkbSize = 1 + 2 *
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( lineCoordinates.size() ) * dimension *
static_cast<int>(
sizeof( double ) );
1746 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1748 QgsWkbPtr fillPtr( wkbPtr );
1752 QList<QgsPoint>::const_iterator iter;
1753 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1755 fillPtr << iter->x() << iter->y();
1756 if ( dimension > 2 )
1758 fillPtr << iter->z();
1765int QgsGmlStreamingParser::getRingWKB( QByteArray &wkbPtr,
const QList<QgsPoint> &ringCoordinates,
int dimension )
const
1767 const int wkbSize =
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( ringCoordinates.size() ) * dimension *
static_cast<int>(
sizeof( double ) );
1768 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1770 QgsWkbPtr fillPtr( wkbPtr );
1772 fillPtr << ringCoordinates.size();
1774 QList<QgsPoint>::const_iterator iter;
1775 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1777 fillPtr << iter->x() << iter->y();
1778 if ( dimension > 2 )
1780 fillPtr << iter->z();
1787int QgsGmlStreamingParser::createMultiLineFromFragments()
1789 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1790 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1792 QgsWkbPtr wkbPtr( mCurrentWKB );
1797 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1798 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1800 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1801 wkbPtr += wkbIt->size();
1804 mCurrentWKBFragments.clear();
1809int QgsGmlStreamingParser::createMultiPointFromFragments()
1811 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1812 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1814 QgsWkbPtr wkbPtr( mCurrentWKB );
1817 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1818 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1820 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1821 wkbPtr += wkbIt->size();
1824 mCurrentWKBFragments.clear();
1830int QgsGmlStreamingParser::createPolygonFromFragments()
1832 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1833 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1835 QgsWkbPtr wkbPtr( mCurrentWKB );
1838 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1839 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1841 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1842 wkbPtr += wkbIt->size();
1845 mCurrentWKBFragments.clear();
1850int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1853 size += 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) );
1854 size += totalWKBFragmentSize();
1855 size += mCurrentWKBFragments.size() * ( 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof( int ) ) );
1857 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1859 QgsWkbPtr wkbPtr( mCurrentWKB );
1863 auto outerWkbIt = mCurrentWKBFragments.constBegin();
1865 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1870 auto innerWkbIt = outerWkbIt->constBegin();
1871 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1873 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1874 wkbPtr += innerWkbIt->size();
1878 mCurrentWKBFragments.clear();
1883int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1886 for (
const QList<QByteArray> &list : std::as_const( mCurrentWKBFragments ) )
1888 for (
const QByteArray &i : list )
1896void QgsGmlStreamingParser::createParser(
const QByteArray &encoding )
1898 Q_ASSERT( !mParser );
1900 mParser = XML_ParserCreateNS( encoding.isEmpty() ?
nullptr : encoding.data(), NS_SEPARATOR );
1901 XML_SetUserData( mParser,
this );
1902 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
1903 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
Provides global constants and enumerations for use throughout the application.
@ Critical
Critical/error message.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ MultiPointZ
MultiPointZ.
@ MultiPolygon
MultiPolygon.
@ MultiLineString
MultiLineString.
@ MultiLineStringZ
MultiLineStringZ.
@ MultiPolygonZ
MultiPolygonZ.
@ LineStringZ
LineStringZ.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static endian_t endian()
Returns whether this machine uses big or little endian.
Represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool hasAxisInverted() const
Returns whether the axis order is inverted for the CRS compared to the order east/north (longitude/la...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
Container of fields for a vector layer.
int size() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
QPair< QgsFeature *, QString > QgsGmlFeaturePtrGmlIdPair
void setFieldsXPath(const QMap< QString, QPair< QString, bool > > &fieldNameToSrcLayerNameFieldNameMap, const QMap< QString, QString > &namespacePrefixToURIMap)
Define the XPath of the attributes and whether they are made of nested content.
int numberReturned() const
Returns WFS 2.0 "numberReturned" or WFS 1.1 "numberOfFeatures" attribute, or -1 if invalid/not found.
AxisOrientationLogic
Axis orientation logic.
@ Honour_EPSG
Honour EPSG axis order.
@ Honour_EPSG_if_urn
Honour EPSG axis order only if srsName is of the form urn:ogc:def:crs:EPSG:
int numberMatched() const
Returns WFS 2.0 "numberMatched" attribute, or -1 if invalid/not found.
QgsGmlStreamingParser(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields, AxisOrientationLogic axisOrientationLogic=Honour_EPSG_if_urn, bool invertAxisOrientation=false)
Constructor.
bool processData(const QByteArray &data, bool atEnd, QString &errorMsg)
Process a new chunk of data.
QVector< QgsGmlFeaturePtrGmlIdPair > getAndStealReadyFeatures()
Returns the list of features that have been completely parsed.
QString srsName() const
Returns the value of the srsName attribute.
void totalStepsUpdate(int totalSteps)
Emitted when the total number of bytes to read changes.
void dataReadProgress(int progress)
Emitted when data reading progresses.
QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)
QgsCoordinateReferenceSystem crs() const
Returns the spatial reference system for features.
int getFeatures(const QString &uri, Qgis::WkbType *wkbType, QgsRectangle *extent=nullptr, const QString &userName=QString(), const QString &password=QString(), const QString &authcfg=QString())
Does the HTTP GET request to the WFS server.
void dataProgressAndSteps(int progress, int totalSteps)
Emitted when data reading progresses or the total number of bytes to read changes.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
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)