28 #include <QNetworkRequest>
29 #include <QNetworkReply>
30 #include <QProgressDialog>
40 static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
45 const QString &geometryAttribute,
47 : mParser(
typeName, geometryAttribute, fields )
51 int index = mTypeName.indexOf(
':' );
52 if ( index != -1 && index < mTypeName.length() )
54 mTypeName = mTypeName.mid( index + 1 );
63 QNetworkRequest request( uri );
66 if ( !authcfg.isEmpty() )
71 tr(
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
73 Qgis::MessageLevel::Critical
78 else if ( !userName.isNull() || !password.isNull() )
80 request.setRawHeader(
"Authorization",
"Basic " + QStringLiteral(
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
84 if ( !authcfg.isEmpty() )
90 tr(
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
92 Qgis::MessageLevel::Critical
98 connect( reply, &QNetworkReply::finished,
this, &QgsGml::setFinished );
99 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsGml::handleProgressEvent );
102 QProgressDialog *progressDialog =
nullptr;
103 QWidget *mainWindow =
nullptr;
104 QWidgetList topLevelWidgets = qApp->topLevelWidgets();
105 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
107 if ( ( *it )->objectName() == QLatin1String(
"QgisApp" ) )
115 progressDialog =
new QProgressDialog( tr(
"Loading GML data\n%1" ).arg( mTypeName ), tr(
"Abort" ), 0, 0, mainWindow );
116 progressDialog->setWindowModality( Qt::ApplicationModal );
119 connect( progressDialog, &QProgressDialog::canceled,
this, &QgsGml::setFinished );
120 progressDialog->show();
130 QByteArray readData = reply->readAll();
131 if ( !readData.isEmpty() )
134 if ( !mParser.
processData( readData, atEnd, errorMsg ) )
138 QCoreApplication::processEvents();
141 fillMapsFromParser();
143 QNetworkReply::NetworkError replyError = reply->error();
144 QString replyErrorString = reply->errorString();
147 delete progressDialog;
152 tr(
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
154 Qgis::MessageLevel::Critical
166 calculateExtentFromFeatures();
181 if ( !mParser.
processData( data,
true , errorMsg ) )
184 fillMapsFromParser();
194 void QgsGml::fillMapsFromParser()
197 const auto constFeatures = features;
201 const QString &gmlId = featPair.second;
202 mFeatures.insert( feat->
id(), feat );
203 if ( !gmlId.isEmpty() )
205 mIdMap.insert( feat->
id(), gmlId );
210 void QgsGml::setFinished()
215 void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
217 if ( totalSteps < 0 )
227 void QgsGml::calculateExtentFromFeatures()
229 if ( mFeatures.empty() )
236 bool bboxInitialized =
false;
238 for (
int i = 0; i < mFeatures.size(); ++i )
240 currentFeature = mFeatures[i];
241 if ( !currentFeature )
245 currentGeometry = currentFeature->
geometry();
246 if ( !currentGeometry.
isNull() )
248 if ( !bboxInitialized )
251 bboxInitialized =
true;
276 const QString &geometryAttribute,
279 bool invertAxisOrientation )
281 , mTypeNameBA( mTypeName.toUtf8() )
282 , mTypeNamePtr( mTypeNameBA.constData() )
283 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
285 , mGeometryAttribute( geometryAttribute )
286 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
287 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
288 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
290 , mIsException( false )
291 , mTruncatedResponse( false )
293 , mFeatureTupleDepth( 0 )
295 , mCurrentWKB( nullptr, 0 )
296 , mBoundedByNullFound( false )
298 , mCoorMode( Coordinate )
300 , mAxisOrientationLogic( axisOrientationLogic )
301 , mInvertAxisOrientationRequest( invertAxisOrientation )
302 , mInvertAxisOrientation( invertAxisOrientation )
303 , mNumberReturned( -1 )
304 , mNumberMatched( -1 )
305 , mFoundUnhandledGeometryElement( false )
307 mThematicAttributes.clear();
308 for (
int i = 0; i < fields.
size(); i++ )
310 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
315 int index = mTypeName.indexOf(
':' );
316 if ( index != -1 && index < mTypeName.length() )
318 mTypeName = mTypeName.mid( index + 1 );
319 mTypeNameBA = mTypeName.toUtf8();
320 mTypeNamePtr = mTypeNameBA.constData();
321 mTypeNameUTF8Len = strlen( mTypeNamePtr );
325 XML_SetUserData( mParser,
this );
326 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
327 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
330 static QString stripNS(
const QString &
string )
332 int index =
string.indexOf(
':' );
333 if ( index != -1 && index <
string.length() )
335 return string.mid( index + 1 );
342 const QMap< QString, QPair<QString, QString> > &mapFieldNameToSrcLayerNameFieldName,
344 bool invertAxisOrientation )
345 : mLayerProperties( layerProperties )
346 , mTypeNameUTF8Len( 0 )
348 , mGeometryAttributeUTF8Len( 0 )
350 , mIsException( false )
351 , mTruncatedResponse( false )
353 , mFeatureTupleDepth( 0 )
355 , mCurrentWKB( nullptr, 0 )
356 , mBoundedByNullFound( false )
358 , mCoorMode( Coordinate )
360 , mAxisOrientationLogic( axisOrientationLogic )
361 , mInvertAxisOrientationRequest( invertAxisOrientation )
362 , mInvertAxisOrientation( invertAxisOrientation )
363 , mNumberReturned( -1 )
364 , mNumberMatched( -1 )
365 , mFoundUnhandledGeometryElement( false )
367 mThematicAttributes.clear();
368 for (
int i = 0; i < fields.
size(); i++ )
370 QMap< QString, QPair<QString, QString> >::const_iterator att_it = mapFieldNameToSrcLayerNameFieldName.constFind( fields.
at( i ).
name() );
371 if ( att_it != mapFieldNameToSrcLayerNameFieldName.constEnd() )
373 if ( mLayerProperties.size() == 1 )
374 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
376 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
379 bool alreadyFoundGeometry =
false;
380 for (
int i = 0; i < mLayerProperties.size(); i++ )
383 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
385 if ( alreadyFoundGeometry )
387 QgsDebugMsg( QStringLiteral(
"Will ignore geometry field %1 from typename %2" ).
388 arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ) );
389 mLayerProperties[i].mGeometryAttribute.clear();
391 alreadyFoundGeometry =
true;
393 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
396 if ( mLayerProperties.size() == 1 )
398 mTypeName = mLayerProperties[0].mName;
399 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
400 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
401 mGeometryAttributePtr = mGeometryAttributeBA.constData();
402 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
403 int index = mTypeName.indexOf(
':' );
404 if ( index != -1 && index < mTypeName.length() )
406 mTypeName = mTypeName.mid( index + 1 );
408 mTypeNameBA = mTypeName.toUtf8();
409 mTypeNamePtr = mTypeNameBA.constData();
410 mTypeNameUTF8Len = strlen( mTypeNamePtr );
416 XML_SetUserData( mParser,
this );
417 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
418 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
424 XML_ParserFree( mParser );
427 const auto constMFeatureList = mFeatureList;
430 delete featPair.first;
433 delete mCurrentFeature;
449 if ( XML_Parse( mParser, data.data(), data.size(), atEnd ) == 0 )
451 XML_Error errorCode = XML_GetErrorCode( mParser );
452 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" )
453 .arg( XML_ErrorString( errorCode ) )
454 .arg( XML_GetCurrentLineNumber( mParser ) )
455 .arg( XML_GetCurrentColumnNumber( mParser ) );
465 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
466 mFeatureList.clear();
470 #define LOCALNAME_EQUALS(string_constant) \
471 ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 )
473 void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
475 const int elLen =
static_cast<int>( strlen( el ) );
477 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
478 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
479 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
480 ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
484 if ( !mGMLNameSpaceURIPtr && pszSep )
498 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
501 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
502 parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
504 mGeometryString.append(
"<", 1 );
505 mGeometryString.append( pszLocalName, localNameLen );
506 mGeometryString.append(
" ", 1 );
507 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
509 const size_t nAttrLen = strlen( attrIter[0] );
512 if ( nAttrLen > GML32_NAMESPACE_LEN &&
513 attrIter[0][GML32_NAMESPACE_LEN] ==
'?' &&
516 mGeometryString.append(
"gml:" );
517 mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
519 else if ( nAttrLen > GML_NAMESPACE_LEN &&
520 attrIter[0][GML_NAMESPACE_LEN] ==
'?' &&
521 memcmp( attrIter[0],
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
523 mGeometryString.append(
"gml:" );
524 mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
528 mGeometryString.append( attrIter[0] );
530 mGeometryString.append(
"=\"", 2 );
531 mGeometryString.append( attrIter[1] );
532 mGeometryString.append(
"\" ", 2 );
535 mGeometryString.append(
">", 1 );
540 mParseModeStack.push( Coordinate );
541 mCoorMode = QgsGmlStreamingParser::Coordinate;
543 mCoordinateSeparator = readAttribute( QStringLiteral(
"cs" ), attr );
544 if ( mCoordinateSeparator.isEmpty() )
546 mCoordinateSeparator =
',';
548 mTupleSeparator = readAttribute( QStringLiteral(
"ts" ), attr );
549 if ( mTupleSeparator.isEmpty() )
551 mTupleSeparator =
' ';
557 mParseModeStack.push( QgsGmlStreamingParser::PosList );
558 mCoorMode = QgsGmlStreamingParser::PosList;
560 if ( elDimension == 0 )
562 QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
564 int dimension = srsDimension.toInt( &ok );
567 elDimension = dimension;
571 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
573 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
574 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
576 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
577 mFoundUnhandledGeometryElement =
false;
578 mGeometryString.clear();
583 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
585 mBoundedByNullFound =
false;
587 else if ( parseMode == BoundingBox &&
590 mParseModeStack.push( QgsGmlStreamingParser::Null );
591 mBoundedByNullFound =
true;
593 else if ( parseMode == BoundingBox &&
597 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
599 else if ( parseMode == Envelope &&
602 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
605 else if ( parseMode == Envelope &&
608 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
611 else if ( parseMode == None && !mTypeNamePtr &&
614 Q_ASSERT( !mCurrentFeature );
615 mCurrentFeature =
new QgsFeature( mFeatureCount );
619 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
620 mCurrentFeatureId.clear();
622 else if ( parseMode == Tuple )
624 QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
625 QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
626 if ( iter != mMapTypeNameToProperties.constEnd() )
628 mFeatureTupleDepth = mParseDepth;
629 mCurrentTypename = currentTypename;
630 mGeometryAttribute.clear();
631 if ( mCurrentWKB.
size() == 0 )
633 mGeometryAttribute = iter.value().mGeometryAttribute;
635 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
636 mGeometryAttributePtr = mGeometryAttributeBA.constData();
637 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
638 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
640 if ( mGMLNameSpaceURI.isEmpty() )
659 id = readAttribute( mGMLNameSpaceURI +
NS_SEPARATOR +
"id", attr );
660 if ( !mCurrentFeatureId.isEmpty() )
661 mCurrentFeatureId +=
'|';
662 mCurrentFeatureId += id;
665 else if ( parseMode == None &&
666 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
667 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
669 Q_ASSERT( !mCurrentFeature );
670 mCurrentFeature =
new QgsFeature( mFeatureCount );
674 mParseModeStack.push( QgsGmlStreamingParser::Feature );
675 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
676 if ( mCurrentFeatureId.isEmpty() )
681 if ( mGMLNameSpaceURI.isEmpty() )
684 if ( !mCurrentFeatureId.isEmpty() )
692 if ( !mCurrentFeatureId.isEmpty() )
700 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI +
NS_SEPARATOR +
"id", attr );
704 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
717 localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
720 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
725 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
727 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
732 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
734 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
739 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
741 else if ( parseMode == FeatureTuple )
743 QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
744 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
746 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
747 mAttributeName = mCurrentTypename +
'|' + localName;
751 else if ( parseMode == Feature )
753 QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
754 if ( mThematicAttributes.contains( localName ) )
756 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
757 mAttributeName = localName;
764 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
766 QString name = readAttribute( QStringLiteral(
"name" ), attr );
767 if ( mThematicAttributes.contains( name ) )
769 QString value = readAttribute( QStringLiteral(
"value" ), attr );
770 setAttribute( name, value );
777 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
779 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
783 mNumberReturned = -1;
785 QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
793 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
798 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
803 mTruncatedResponse =
true;
805 else if ( !mGeometryString.empty() &&
821 mFoundUnhandledGeometryElement =
true;
824 if ( !mGeometryString.empty() )
827 if ( elDimension == 0 && isGeom )
831 QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
833 int dimension = srsDimension.toInt( &ok );
836 elDimension = dimension;
840 if ( elDimension != 0 || mDimensionStack.isEmpty() )
842 mDimensionStack.push( elDimension );
846 mDimensionStack.push( mDimensionStack.back() );
849 if ( mEpsg == 0 && isGeom )
851 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
853 QgsDebugMsg( QStringLiteral(
"error, could not get epsg id" ) );
857 QgsDebugMsg( QStringLiteral(
"mEpsg = %1" ).arg( mEpsg ) );
864 void QgsGmlStreamingParser::endElement(
const XML_Char *el )
868 const int elLen =
static_cast<int>( strlen( el ) );
870 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
871 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
872 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
873 ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
875 int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
877 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
879 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
881 mParseModeStack.pop();
883 else if ( parseMode == PosList && isGMLNS &&
886 mDimension = lastDimension;
887 mParseModeStack.pop();
889 else if ( parseMode == AttributeTuple &&
890 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
892 mParseModeStack.pop();
894 setAttribute( mAttributeName, mStringCash );
896 else if ( parseMode == Attribute && QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
898 mParseModeStack.pop();
900 setAttribute( mAttributeName, mStringCash );
902 else if ( parseMode == Geometry &&
903 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
904 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
906 mParseModeStack.pop();
907 if ( mFoundUnhandledGeometryElement )
913 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
914 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
915 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
917 g.
fromWkb( pabyBuffer, wkbSize );
918 if ( mInvertAxisOrientation )
920 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
922 Q_ASSERT( mCurrentFeature );
926 mGeometryString.clear();
928 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
931 if ( mCurrentExtent.
isNull() &&
932 !mBoundedByNullFound &&
933 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
935 QgsDebugMsg( QStringLiteral(
"creation of bounding box failed" ) );
937 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
938 !mCurrentFeature && mFeatureCount == 0 )
940 mLayerExtent = mCurrentExtent;
944 mParseModeStack.pop();
948 mParseModeStack.pop();
950 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
952 mParseModeStack.pop();
954 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
956 QList<QgsPointXY> points;
957 pointsFromPosListString( points, mStringCash, 2 );
958 if ( points.size() == 1 )
963 mParseModeStack.pop();
965 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
967 QList<QgsPointXY> points;
968 pointsFromPosListString( points, mStringCash, 2 );
969 if ( points.size() == 1 )
974 mParseModeStack.pop();
976 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
978 mParseModeStack.pop();
979 mFeatureTupleDepth = 0;
981 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
983 ( parseMode == Feature &&
984 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
985 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
987 Q_ASSERT( mCurrentFeature );
990 if ( mCurrentWKB.
size() > 0 )
997 else if ( !mCurrentExtent.
isEmpty() )
1006 mCurrentFeature =
nullptr;
1008 mParseModeStack.pop();
1012 QList<QgsPointXY> pointList;
1013 if ( pointsFromString( pointList, mStringCash ) != 0 )
1018 if ( pointList.isEmpty() )
1021 if ( parseMode == QgsGmlStreamingParser::Geometry )
1024 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
1037 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
1041 if ( !mCurrentWKBFragments.isEmpty() )
1043 mCurrentWKBFragments.last().push_back( wkbPtr );
1047 QgsDebugMsg( QStringLiteral(
"No wkb fragments" ) );
1056 QList<QgsPointXY> pointList;
1057 if ( pointsFromString( pointList, mStringCash ) != 0 )
1061 if ( parseMode == QgsGmlStreamingParser::Geometry )
1063 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
1076 if ( getLineWKB( wkbPtr, pointList ) != 0 )
1080 if ( !mCurrentWKBFragments.isEmpty() )
1082 mCurrentWKBFragments.last().push_back( wkbPtr );
1086 QgsDebugMsg( QStringLiteral(
"no wkb fragments" ) );
1091 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1094 QList<QgsPointXY> pointList;
1095 if ( pointsFromString( pointList, mStringCash ) != 0 )
1101 if ( getRingWKB( wkbPtr, pointList ) != 0 )
1106 if ( !mCurrentWKBFragments.isEmpty() )
1108 mCurrentWKBFragments.last().push_back( wkbPtr );
1113 QgsDebugMsg( QStringLiteral(
"no wkb fragments" ) );
1116 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1124 if ( parseMode == Geometry )
1126 createPolygonFromFragments();
1129 else if ( parseMode == MultiPoint && isGMLNS &&
1133 mParseModeStack.pop();
1134 createMultiPointFromFragments();
1136 else if ( parseMode == MultiLine && isGMLNS &&
1140 mParseModeStack.pop();
1141 createMultiLineFromFragments();
1143 else if ( parseMode == MultiPolygon && isGMLNS &&
1147 mParseModeStack.pop();
1148 createMultiPolygonFromFragments();
1152 mParseModeStack.pop();
1154 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1156 mExceptionText = mStringCash;
1157 mParseModeStack.pop();
1160 if ( !mGeometryString.empty() )
1162 mGeometryString.append(
"</", 2 );
1163 mGeometryString.append( pszLocalName, localNameLen );
1164 mGeometryString.append(
">", 1 );
1169 void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1172 if ( mParseModeStack.isEmpty() )
1177 if ( !mGeometryString.empty() )
1179 mGeometryString.append( chars, len );
1182 QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1183 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1184 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1185 parseMode == QgsGmlStreamingParser::Coordinate ||
1186 parseMode == QgsGmlStreamingParser::PosList ||
1187 parseMode == QgsGmlStreamingParser::LowerCorner ||
1188 parseMode == QgsGmlStreamingParser::UpperCorner ||
1189 parseMode == QgsGmlStreamingParser::ExceptionText )
1191 mStringCash.append( QString::fromUtf8( chars, len ) );
1195 void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1198 QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1199 bool conversionOk =
true;
1200 if ( att_it != mThematicAttributes.constEnd() )
1203 switch ( att_it.value().second.type() )
1205 case QVariant::Double:
1206 var = QVariant( value.toDouble( &conversionOk ) );
1209 var = QVariant( value.toInt( &conversionOk ) );
1211 case QVariant::LongLong:
1212 var = QVariant( value.toLongLong( &conversionOk ) );
1214 case QVariant::DateTime:
1215 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1218 var = QVariant( value );
1221 if ( ! conversionOk )
1225 Q_ASSERT( mCurrentFeature );
1226 mCurrentFeature->
setAttribute( att_it.value().first, var );
1230 int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1235 if ( strcmp( attr[i],
"srsName" ) == 0 )
1237 QString epsgString( attr[i + 1] );
1238 QString epsgNrString;
1239 bool bIsUrn =
false;
1240 if ( epsgString.startsWith( QLatin1String(
"http://www.opengis.net/gml/srs/" ) ) )
1242 epsgNrString = epsgString.section(
'#', 1, 1 );
1245 else if ( epsgString.startsWith( QLatin1String(
"urn:ogc:def:crs:EPSG:" ) ) ||
1246 epsgString.startsWith( QLatin1String(
"urn:x-ogc:def:crs:EPSG:" ) ) )
1249 epsgNrString = epsgString.split(
':' ).last();
1251 else if ( epsgString.startsWith( QLatin1String(
"http://www.opengis.net/def/crs/EPSG/" ) ) )
1254 epsgNrString = epsgString.split(
'/' ).last();
1258 epsgNrString = epsgString.section(
':', 1, 1 );
1261 int eNr = epsgNrString.toInt( &conversionOk );
1262 if ( !conversionOk )
1267 mSrsName = epsgString;
1275 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1286 QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1291 if ( attributeName.compare( attr[i] ) == 0 )
1293 return QString::fromUtf8( attr[i + 1] );
1300 bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1302 QList<QgsPointXY> points;
1303 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1308 if ( points.size() < 2 )
1313 r.
set( points[0], points[1] );
1318 int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const
1321 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1322 QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
1324 QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1326 QStringList tuples_coordinates;
1328 bool conversionSuccess;
1330 QStringList::const_iterator tupleIterator;
1331 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1333 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1334 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
1336 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1338 if ( tuples_coordinates.size() < 2 )
1342 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1343 if ( !conversionSuccess )
1347 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1348 if ( !conversionSuccess )
1357 int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const
1360 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1361 QStringList coordinates = coordString.split(
' ', QString::SkipEmptyParts );
1363 QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1366 if ( coordinates.size() % dimension != 0 )
1368 QgsDebugMsg( QStringLiteral(
"Wrong number of coordinates" ) );
1371 int ncoor = coordinates.size() / dimension;
1372 for (
int i = 0; i < ncoor; i++ )
1374 bool conversionSuccess;
1375 double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1376 if ( !conversionSuccess )
1380 double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1381 if ( !conversionSuccess )
1390 int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const
1392 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1394 return pointsFromCoordinateString( points, coordString );
1396 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1398 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1403 int QgsGmlStreamingParser::getPointWKB(
QgsWkbPtr &wkbPtr,
const QgsPointXY &point )
const
1405 int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1406 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1414 int QgsGmlStreamingParser::getLineWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const
1416 int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1417 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1423 QList<QgsPointXY>::const_iterator iter;
1424 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1426 fillPtr << iter->x() << iter->y();
1432 int QgsGmlStreamingParser::getRingWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const
1434 int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1435 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1439 fillPtr << ringCoordinates.size();
1441 QList<QgsPointXY>::const_iterator iter;
1442 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1444 fillPtr << iter->x() << iter->y();
1450 int QgsGmlStreamingParser::createMultiLineFromFragments()
1452 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1453 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1460 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1461 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1463 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1464 wkbPtr += wkbIt->
size();
1468 mCurrentWKBFragments.clear();
1473 int QgsGmlStreamingParser::createMultiPointFromFragments()
1475 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1476 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1481 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1482 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1484 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1485 wkbPtr += wkbIt->
size();
1489 mCurrentWKBFragments.clear();
1495 int QgsGmlStreamingParser::createPolygonFromFragments()
1497 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1498 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1503 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1504 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1506 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1507 wkbPtr += wkbIt->
size();
1511 mCurrentWKBFragments.clear();
1516 int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1519 size += 1 + 2 *
sizeof( int );
1520 size += totalWKBFragmentSize();
1521 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1523 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1529 QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
1531 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1536 QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
1537 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1539 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1540 wkbPtr += innerWkbIt->
size();
1541 delete[] *innerWkbIt;
1545 mCurrentWKBFragments.clear();
1550 int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1553 const auto constMCurrentWKBFragments = mCurrentWKBFragments;
1554 for (
const QList<QgsWkbPtr> &list : constMCurrentWKBFragments )
1556 const auto constList = list;
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static endian_t endian()
Returns whether this machine uses big or little endian.
This class 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 axis is inverted (e.g., for WMS 1.3) for the CRS.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
void setValid(bool validity)
Sets the validity of the feature.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Container of fields for a vector layer.
int size() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
A geometry is the spatial representation of a feature.
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
QgsWkbTypes::Type wkbType() const
Returns the geometry type.
QPair< QgsFeature *, QString > QgsGmlFeaturePtrGmlIdPair
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.
int getEPSGCode() const
Returns the EPSG code, or 0 if unknown.
QVector< QgsGmlFeaturePtrGmlIdPair > getAndStealReadyFeatures()
Returns the list of features that have been completely parsed.
int getFeatures(const QString &uri, QgsWkbTypes::Type *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 Supports only UTF-8, UTF-16, ISO-8859-1,...
void totalStepsUpdate(int totalSteps)
void dataReadProgress(int progress)
QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)
QgsCoordinateReferenceSystem crs() const
Returns features spatial reference system.
void dataProgressAndSteps(int progress, int totalSteps)
Also emit signal with progress and totalSteps together (this is better for the status message)
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
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.
A class to represent a 2D point.
A rectangle specified with double values.
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
void setMinimal() SIP_HOLDGIL
Set a rectangle so that min corner is at max and max corner is at min.
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
bool isEmpty() const
Returns true if the rectangle is empty.
Handles storage of information regarding WKB types and their properties.
Type
The WKB type describes the number of dimensions a geometry has.
std::unique_ptr< std::remove_pointer< OGRGeometryH >::type, OGRGeometryDeleter > ogr_geometry_unique_ptr
Scoped OGR geometry.
#define LOCALNAME_EQUALS(string_constant)
#define QgsSetRequestInitiatorClass(request, _class)
const QgsCoordinateReferenceSystem & crs