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" ) ) )
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();
1232 epsgNrString = epsgString.section(
':', 1, 1 );
1235 int eNr = epsgNrString.toInt( &conversionOk );
1236 if ( !conversionOk )
1241 mSrsName = epsgString;
1249 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1260 QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const 1265 if ( attributeName.compare( attr[i] ) == 0 )
1267 return QString::fromUtf8( attr[i + 1] );
1274 bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const 1276 QList<QgsPointXY> points;
1277 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1282 if ( points.size() < 2 )
1287 r.
set( points[0], points[1] );
1292 int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const 1295 QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
1296 QStringList tuples_coordinates;
1298 bool conversionSuccess;
1300 QStringList::const_iterator tupleIterator;
1301 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1303 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
1304 if ( tuples_coordinates.size() < 2 )
1308 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1309 if ( !conversionSuccess )
1313 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1314 if ( !conversionSuccess )
1323 int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const 1326 QStringList coordinates = coordString.split(
' ', QString::SkipEmptyParts );
1328 if ( coordinates.size() % dimension != 0 )
1330 QgsDebugMsg( QStringLiteral(
"Wrong number of coordinates" ) );
1333 int ncoor = coordinates.size() / dimension;
1334 for (
int i = 0; i < ncoor; i++ )
1336 bool conversionSuccess;
1337 double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1338 if ( !conversionSuccess )
1342 double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1343 if ( !conversionSuccess )
1352 int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const 1354 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1356 return pointsFromCoordinateString( points, coordString );
1358 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1360 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1365 int QgsGmlStreamingParser::getPointWKB(
QgsWkbPtr &wkbPtr,
const QgsPointXY &point )
const 1367 int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1368 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1376 int QgsGmlStreamingParser::getLineWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const 1378 int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1379 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1385 QList<QgsPointXY>::const_iterator iter;
1386 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1388 fillPtr << iter->x() << iter->y();
1394 int QgsGmlStreamingParser::getRingWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const 1396 int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1397 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1401 fillPtr << ringCoordinates.
size();
1403 QList<QgsPointXY>::const_iterator iter;
1404 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1406 fillPtr << iter->x() << iter->y();
1412 int QgsGmlStreamingParser::createMultiLineFromFragments()
1414 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1415 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1422 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1423 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1425 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1426 wkbPtr += wkbIt->
size();
1430 mCurrentWKBFragments.clear();
1435 int QgsGmlStreamingParser::createMultiPointFromFragments()
1437 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1438 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1443 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1444 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1446 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1447 wkbPtr += wkbIt->
size();
1451 mCurrentWKBFragments.clear();
1457 int QgsGmlStreamingParser::createPolygonFromFragments()
1459 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1460 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1465 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1466 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1468 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1469 wkbPtr += wkbIt->
size();
1473 mCurrentWKBFragments.clear();
1478 int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1481 size += 1 + 2 *
sizeof( int );
1482 size += totalWKBFragmentSize();
1483 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1485 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1491 QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
1493 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1498 QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
1499 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1501 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->
size() );
1502 wkbPtr += innerWkbIt->
size();
1503 delete[] *innerWkbIt;
1507 mCurrentWKBFragments.clear();
1512 int QgsGmlStreamingParser::totalWKBFragmentSize()
const 1515 const auto constMCurrentWKBFragments = mCurrentWKBFragments;
1516 for (
const QList<QgsWkbPtr> &list : constMCurrentWKBFragments )
1518 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.