28 #include <QNetworkRequest> 29 #include <QNetworkReply> 30 #include <QProgressDialog> 40 static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
41 static const char *GML32_NAMESPACE =
"http://www.opengis.net/gml/3.2";
45 const QString &geometryAttribute,
47 : mParser( typeName, geometryAttribute, fields )
48 , mTypeName( typeName )
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 ),
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 ),
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 ),
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 )
280 : mTypeName( typeName )
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 )
491 else if ( nsLen == static_cast<int>( strlen( GML32_NAMESPACE ) ) && memcmp( el, GML32_NAMESPACE, nsLen ) == 0 )
493 mGMLNameSpaceURI = GML32_NAMESPACE;
494 mGMLNameSpaceURIPtr = GML32_NAMESPACE;
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 mGeometryString.append( attrIter[0] );
510 mGeometryString.append(
"=\"", 2 );
511 mGeometryString.append( attrIter[1] );
512 mGeometryString.append(
"\" ", 2 );
515 mGeometryString.append(
">", 1 );
520 mParseModeStack.push( Coordinate );
521 mCoorMode = QgsGmlStreamingParser::Coordinate;
523 mCoordinateSeparator = readAttribute( QStringLiteral(
"cs" ), attr );
524 if ( mCoordinateSeparator.isEmpty() )
526 mCoordinateSeparator =
',';
528 mTupleSeparator = readAttribute( QStringLiteral(
"ts" ), attr );
529 if ( mTupleSeparator.isEmpty() )
531 mTupleSeparator =
' ';
537 mParseModeStack.push( QgsGmlStreamingParser::PosList );
538 mCoorMode = QgsGmlStreamingParser::PosList;
540 if ( elDimension == 0 )
542 QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
544 int dimension = srsDimension.toInt( &ok );
547 elDimension = dimension;
551 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
553 localNameLen == static_cast<int>( mGeometryAttributeUTF8Len ) &&
554 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
556 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
557 mFoundUnhandledGeometryElement =
false;
558 mGeometryString.clear();
563 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
565 mBoundedByNullFound =
false;
567 else if ( parseMode == BoundingBox &&
570 mParseModeStack.push( QgsGmlStreamingParser::Null );
571 mBoundedByNullFound =
true;
573 else if ( parseMode == BoundingBox &&
577 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
579 else if ( parseMode == Envelope &&
582 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
585 else if ( parseMode == Envelope &&
588 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
591 else if ( parseMode == None && !mTypeNamePtr &&
594 Q_ASSERT( !mCurrentFeature );
595 mCurrentFeature =
new QgsFeature( mFeatureCount );
599 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
600 mCurrentFeatureId.clear();
602 else if ( parseMode == Tuple )
604 QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
605 QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
606 if ( iter != mMapTypeNameToProperties.constEnd() )
608 mFeatureTupleDepth = mParseDepth;
609 mCurrentTypename = currentTypename;
610 mGeometryAttribute.clear();
611 if ( mCurrentWKB.
size() == 0 )
613 mGeometryAttribute = iter.value().mGeometryAttribute;
615 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
616 mGeometryAttributePtr = mGeometryAttributeBA.constData();
617 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
618 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
620 if ( mGMLNameSpaceURI.isEmpty() )
630 id = readAttribute( QString( GML32_NAMESPACE ) +
NS_SEPARATOR +
"id", attr );
633 mGMLNameSpaceURI = GML32_NAMESPACE;
634 mGMLNameSpaceURIPtr = GML32_NAMESPACE;
639 id = readAttribute( mGMLNameSpaceURI +
NS_SEPARATOR +
"id", attr );
640 if ( !mCurrentFeatureId.isEmpty() )
641 mCurrentFeatureId +=
'|';
642 mCurrentFeatureId += id;
645 else if ( parseMode == None &&
646 localNameLen == static_cast<int>( mTypeNameUTF8Len ) &&
647 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
649 Q_ASSERT( !mCurrentFeature );
650 mCurrentFeature =
new QgsFeature( mFeatureCount );
654 mParseModeStack.push( QgsGmlStreamingParser::Feature );
655 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
656 if ( mCurrentFeatureId.isEmpty() )
661 if ( mGMLNameSpaceURI.isEmpty() )
664 if ( !mCurrentFeatureId.isEmpty() )
671 mCurrentFeatureId = readAttribute( QString( GML32_NAMESPACE ) +
NS_SEPARATOR +
"id", attr );
672 if ( !mCurrentFeatureId.isEmpty() )
674 mGMLNameSpaceURI = GML32_NAMESPACE;
675 mGMLNameSpaceURIPtr = GML32_NAMESPACE;
680 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI +
NS_SEPARATOR +
"id", attr );
684 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
697 localNameLen == static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
700 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
705 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
707 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
712 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
714 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
719 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
721 else if ( parseMode == FeatureTuple )
723 QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
724 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
726 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
727 mAttributeName = mCurrentTypename +
'|' + localName;
731 else if ( parseMode == Feature )
733 QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
734 if ( mThematicAttributes.contains( localName ) )
736 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
737 mAttributeName = localName;
744 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
746 QString name = readAttribute( QStringLiteral(
"name" ), attr );
747 if ( mThematicAttributes.contains( name ) )
749 QString value = readAttribute( QStringLiteral(
"value" ), attr );
750 setAttribute( name, value );
757 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
758 if ( numberReturned.isEmpty() )
759 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
761 mNumberReturned = numberReturned.toInt( &conversionOk );
763 mNumberReturned = -1;
765 QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
766 mNumberMatched = numberMatched.toInt( &conversionOk );
773 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
778 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
783 mTruncatedResponse =
true;
785 else if ( !mGeometryString.empty() &&
801 mFoundUnhandledGeometryElement =
true;
804 if ( !mGeometryString.empty() )
807 if ( elDimension == 0 && isGeom )
811 QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
813 int dimension = srsDimension.toInt( &ok );
816 elDimension = dimension;
820 if ( elDimension != 0 || mDimensionStack.isEmpty() )
822 mDimensionStack.push( elDimension );
826 mDimensionStack.push( mDimensionStack.back() );
829 if ( mEpsg == 0 && isGeom )
831 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
833 QgsDebugMsg( QStringLiteral(
"error, could not get epsg id" ) );
837 QgsDebugMsg( QStringLiteral(
"mEpsg = %1" ).arg( mEpsg ) );
844 void QgsGmlStreamingParser::endElement(
const XML_Char *el )
848 const int elLen =
static_cast<int>( strlen( el ) );
850 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
851 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
852 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
853 ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
855 int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
857 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
859 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
861 mParseModeStack.pop();
863 else if ( parseMode == PosList && isGMLNS &&
866 mDimension = lastDimension;
867 mParseModeStack.pop();
869 else if ( parseMode == AttributeTuple &&
870 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
872 mParseModeStack.pop();
874 setAttribute( mAttributeName, mStringCash );
876 else if ( parseMode == Attribute && QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
878 mParseModeStack.pop();
880 setAttribute( mAttributeName, mStringCash );
882 else if ( parseMode == Geometry &&
883 localNameLen == static_cast<int>( mGeometryAttributeUTF8Len ) &&
884 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
886 mParseModeStack.pop();
887 if ( mFoundUnhandledGeometryElement )
892 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
893 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
894 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
896 g.
fromWkb( pabyBuffer, wkbSize );
897 if ( mInvertAxisOrientation )
899 g.transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
901 Q_ASSERT( mCurrentFeature );
905 mGeometryString.clear();
907 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
910 if ( mCurrentExtent.
isNull() &&
911 !mBoundedByNullFound &&
912 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
914 QgsDebugMsg( QStringLiteral(
"creation of bounding box failed" ) );
916 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
917 !mCurrentFeature && mFeatureCount == 0 )
919 mLayerExtent = mCurrentExtent;
923 mParseModeStack.pop();
927 mParseModeStack.pop();
929 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
931 mParseModeStack.pop();
933 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
935 QList<QgsPointXY> points;
936 pointsFromPosListString( points, mStringCash, 2 );
937 if ( points.size() == 1 )
942 mParseModeStack.pop();
944 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
946 QList<QgsPointXY> points;
947 pointsFromPosListString( points, mStringCash, 2 );
948 if ( points.size() == 1 )
953 mParseModeStack.pop();
955 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
957 mParseModeStack.pop();
958 mFeatureTupleDepth = 0;
960 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
962 ( parseMode == Feature &&
963 localNameLen == static_cast<int>( mTypeNameUTF8Len ) &&
964 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
966 Q_ASSERT( mCurrentFeature );
969 if ( mCurrentWKB.
size() > 0 )
976 else if ( !mCurrentExtent.
isEmpty() )
985 mCurrentFeature =
nullptr;
987 mParseModeStack.pop();
991 QList<QgsPointXY> pointList;
992 if ( pointsFromString( pointList, mStringCash ) != 0 )
997 if ( pointList.isEmpty() )
1000 if ( parseMode == QgsGmlStreamingParser::Geometry )
1003 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
1016 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
1020 if ( !mCurrentWKBFragments.isEmpty() )
1022 mCurrentWKBFragments.last().push_back( wkbPtr );
1026 QgsDebugMsg( QStringLiteral(
"No wkb fragments" ) );
1035 QList<QgsPointXY> pointList;
1036 if ( pointsFromString( pointList, mStringCash ) != 0 )
1040 if ( parseMode == QgsGmlStreamingParser::Geometry )
1042 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
1055 if ( getLineWKB( wkbPtr, pointList ) != 0 )
1059 if ( !mCurrentWKBFragments.isEmpty() )
1061 mCurrentWKBFragments.last().push_back( wkbPtr );
1065 QgsDebugMsg( QStringLiteral(
"no wkb fragments" ) );
1070 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1073 QList<QgsPointXY> pointList;
1074 if ( pointsFromString( pointList, mStringCash ) != 0 )
1080 if ( getRingWKB( wkbPtr, pointList ) != 0 )
1085 if ( !mCurrentWKBFragments.isEmpty() )
1087 mCurrentWKBFragments.last().push_back( wkbPtr );
1092 QgsDebugMsg( QStringLiteral(
"no wkb fragments" ) );
1095 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1103 if ( parseMode == Geometry )
1105 createPolygonFromFragments();
1108 else if ( parseMode == MultiPoint && isGMLNS &&
1112 mParseModeStack.pop();
1113 createMultiPointFromFragments();
1115 else if ( parseMode == MultiLine && isGMLNS &&
1119 mParseModeStack.pop();
1120 createMultiLineFromFragments();
1122 else if ( parseMode == MultiPolygon && isGMLNS &&
1126 mParseModeStack.pop();
1127 createMultiPolygonFromFragments();
1131 mParseModeStack.pop();
1133 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1135 mExceptionText = mStringCash;
1136 mParseModeStack.pop();
1139 if ( !mGeometryString.empty() )
1141 mGeometryString.append(
"</", 2 );
1142 mGeometryString.append( pszLocalName, localNameLen );
1143 mGeometryString.append(
">", 1 );
1148 void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1151 if ( mParseModeStack.isEmpty() )
1156 if ( !mGeometryString.empty() )
1158 mGeometryString.append( chars, len );
1161 QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1162 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1163 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1164 parseMode == QgsGmlStreamingParser::Coordinate ||
1165 parseMode == QgsGmlStreamingParser::PosList ||
1166 parseMode == QgsGmlStreamingParser::LowerCorner ||
1167 parseMode == QgsGmlStreamingParser::UpperCorner ||
1168 parseMode == QgsGmlStreamingParser::ExceptionText )
1170 mStringCash.append( QString::fromUtf8( chars, len ) );
1174 void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1177 QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1178 bool conversionOk =
true;
1179 if ( att_it != mThematicAttributes.constEnd() )
1182 switch ( att_it.value().second.type() )
1184 case QVariant::Double:
1185 var = QVariant( value.toDouble( &conversionOk ) );
1188 var = QVariant( value.toInt( &conversionOk ) );
1190 case QVariant::LongLong:
1191 var = QVariant( value.toLongLong( &conversionOk ) );
1193 case QVariant::DateTime:
1194 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1197 var = QVariant( value );
1200 if ( ! conversionOk )
1204 Q_ASSERT( mCurrentFeature );
1205 mCurrentFeature->
setAttribute( att_it.value().first, var );
1209 int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1214 if ( strcmp( attr[i],
"srsName" ) == 0 )
1216 QString epsgString( attr[i + 1] );
1217 QString epsgNrString;
1218 bool bIsUrn =
false;
1219 if ( epsgString.startsWith( QLatin1String(
"http://www.opengis.net/gml/srs/" ) ) )
1221 epsgNrString = epsgString.section(
'#', 1, 1 );
1224 else if ( epsgString.startsWith( QLatin1String(
"urn:ogc:def:crs:EPSG:" ) ) ||
1225 epsgString.startsWith( QLatin1String(
"urn:x-ogc:def:crs:EPSG:" ) ) )
1228 epsgNrString = epsgString.split(
':' ).last();
1230 else if ( epsgString.startsWith( QLatin1String(
"http://www.opengis.net/def/crs/EPSG/" ) ) )
1233 epsgNrString = epsgString.split(
'/' ).last();
1237 epsgNrString = epsgString.section(
':', 1, 1 );
1240 int eNr = epsgNrString.toInt( &conversionOk );
1241 if ( !conversionOk )
1246 mSrsName = epsgString;
1254 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1265 QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const 1270 if ( attributeName.compare( attr[i] ) == 0 )
1272 return QString::fromUtf8( attr[i + 1] );
1279 bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const 1281 QList<QgsPointXY> points;
1282 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1287 if ( points.size() < 2 )
1292 r.
set( points[0], points[1] );
1297 int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const 1300 QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
1301 QStringList tuples_coordinates;
1303 bool conversionSuccess;
1305 QStringList::const_iterator tupleIterator;
1306 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1308 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
1309 if ( tuples_coordinates.size() < 2 )
1313 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1314 if ( !conversionSuccess )
1318 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1319 if ( !conversionSuccess )
1328 int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const 1331 QStringList coordinates = coordString.split(
' ', QString::SkipEmptyParts );
1333 if ( coordinates.size() % dimension != 0 )
1335 QgsDebugMsg( QStringLiteral(
"Wrong number of coordinates" ) );
1338 int ncoor = coordinates.size() / dimension;
1339 for (
int i = 0; i < ncoor; i++ )
1341 bool conversionSuccess;
1342 double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1343 if ( !conversionSuccess )
1347 double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1348 if ( !conversionSuccess )
1357 int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const 1359 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1361 return pointsFromCoordinateString( points, coordString );
1363 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1365 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1370 int QgsGmlStreamingParser::getPointWKB(
QgsWkbPtr &wkbPtr,
const QgsPointXY &point )
const 1372 int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1373 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1381 int QgsGmlStreamingParser::getLineWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const 1383 int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1384 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1390 QList<QgsPointXY>::const_iterator iter;
1391 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1393 fillPtr << iter->x() << iter->y();
1399 int QgsGmlStreamingParser::getRingWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const 1401 int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1402 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1406 fillPtr << ringCoordinates.
size();
1408 QList<QgsPointXY>::const_iterator iter;
1409 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1411 fillPtr << iter->x() << iter->y();
1417 int QgsGmlStreamingParser::createMultiLineFromFragments()
1419 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1420 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1427 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1428 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1430 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1431 wkbPtr += wkbIt->
size();
1435 mCurrentWKBFragments.clear();
1440 int QgsGmlStreamingParser::createMultiPointFromFragments()
1442 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1443 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1448 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1449 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1451 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1452 wkbPtr += wkbIt->
size();
1456 mCurrentWKBFragments.clear();
1462 int QgsGmlStreamingParser::createPolygonFromFragments()
1464 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1465 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1470 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1471 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1473 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1474 wkbPtr += wkbIt->
size();
1478 mCurrentWKBFragments.clear();
1483 int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1486 size += 1 + 2 *
sizeof( int );
1487 size += totalWKBFragmentSize();
1488 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1490 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1496 QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
1498 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1503 QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
1504 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1506 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->
size() );
1507 wkbPtr += innerWkbIt->
size();
1508 delete[] *innerWkbIt;
1512 mCurrentWKBFragments.clear();
1517 int QgsGmlStreamingParser::totalWKBFragmentSize()
const 1520 const auto constMCurrentWKBFragments = mCurrentWKBFragments;
1521 for (
const QList<QgsWkbPtr> &list : constMCurrentWKBFragments )
1523 const auto constList = list;
#define QgsSetRequestInitiatorClass(request, _class)
int getEPSGCode() const
Returns the EPSG code, or 0 if unknown.
A rectangle specified with double values.
int size() const
Returns number of items.
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
AxisOrientationLogic
Axis orientation logic.
void setXMaximum(double x)
Set the maximum x value.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length...
int numberReturned() const
Returns WFS 2.0 "numberReturned" or WFS 1.1 "numberOfFeatures" attribute, or -1 if invalid/not found...
Handles storage of information regarding WKB types and their properties.
A class to represent a 2D point.
std::unique_ptr< std::remove_pointer< OGRGeometryH >::type, OGRGeometryDeleter > ogr_geometry_unique_ptr
Scoped OGR geometry.
int numberMatched() const
Returns WFS 2.0 "numberMatched" attribute, or -1 if invalid/not found.
Container of fields for a vector layer.
A geometry is the spatial representation of a feature.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
bool setAttribute(int field, const QVariant &attr)
Set an attribute's value by field index.
void dataReadProgress(int progress)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
const QgsCoordinateReferenceSystem & crs
bool hasGeometry() const
Returns true if the feature has an associated geometry.
static endian_t endian()
Returns whether this machine uses big or little endian.
#define LOCALNAME_EQUALS(string_constant)
void totalStepsUpdate(int totalSteps)
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
const QString GML_NAMESPACE
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Type
The WKB type describes the number of dimensions a geometry has.
void dataProgressAndSteps(int progress, int totalSteps)
Also emit signal with progress and totalSteps together (this is better for the status message) ...
bool isEmpty() const
Returns true if the rectangle is empty.
QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)
void setYMinimum(double y)
Set the minimum y value.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Honour EPSG axis order only if srsName is of the form urn:ogc:def:crs:EPSG: *.
QVector< QgsGmlFeaturePtrGmlIdPair > getAndStealReadyFeatures()
Returns the list of features that have been completely parsed.
QPair< QgsFeature *, QString > QgsGmlFeaturePtrGmlIdPair
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, ISO-8859-1 XML encodings.
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle...
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
void setValid(bool validity)
Sets the validity of the feature.
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkRequest with an authentication config.
void setYMaximum(double y)
Set the maximum y value.
bool processData(const QByteArray &data, bool atEnd, QString &errorMsg)
Process a new chunk of data.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
bool hasAxisInverted() const
Returns whether axis is inverted (e.g., for WMS 1.3) for the CRS.
This class represents a coordinate reference system (CRS).
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
QgsGmlStreamingParser(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields, AxisOrientationLogic axisOrientationLogic=Honour_EPSG_if_urn, bool invertAxisOrientation=false)
Constructor.
QgsCoordinateReferenceSystem crs() const
Returns features spatial reference system.
bool updateNetworkReply(QNetworkReply *reply, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkReply with an authentication config (used to skip known SSL errors...
void set(const QgsPointXY &p1, const QgsPointXY &p2)
Sets the rectangle from two QgsPoints.
void setXMinimum(double x)
Set the minimum x value.
QgsWkbTypes::Type wkbType() const
Returns the geometry type.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.