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()
200 const QString &gmlId = featPair.second;
201 mFeatures.insert( feat->
id(), feat );
202 if ( !gmlId.isEmpty() )
204 mIdMap.insert( feat->
id(), gmlId );
209 void QgsGml::setFinished()
214 void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
216 if ( totalSteps < 0 )
226 void QgsGml::calculateExtentFromFeatures()
228 if ( mFeatures.empty() )
235 bool bboxInitialized =
false;
237 for (
int i = 0; i < mFeatures.size(); ++i )
239 currentFeature = mFeatures[i];
240 if ( !currentFeature )
244 currentGeometry = currentFeature->
geometry();
245 if ( !currentGeometry.
isNull() )
247 if ( !bboxInitialized )
250 bboxInitialized =
true;
275 const QString &geometryAttribute,
278 bool invertAxisOrientation )
279 : mTypeName( typeName )
280 , mTypeNameBA( mTypeName.toUtf8() )
281 , mTypeNamePtr( mTypeNameBA.constData() )
282 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
284 , mGeometryAttribute( geometryAttribute )
285 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
286 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
287 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
289 , mIsException( false )
290 , mTruncatedResponse( false )
292 , mFeatureTupleDepth( 0 )
294 , mCurrentWKB( nullptr, 0 )
295 , mBoundedByNullFound( false )
297 , mCoorMode( Coordinate )
299 , mAxisOrientationLogic( axisOrientationLogic )
300 , mInvertAxisOrientationRequest( invertAxisOrientation )
301 , mInvertAxisOrientation( invertAxisOrientation )
302 , mNumberReturned( -1 )
303 , mNumberMatched( -1 )
304 , mFoundUnhandledGeometryElement( false )
306 mThematicAttributes.clear();
307 for (
int i = 0; i < fields.
size(); i++ )
309 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
314 int index = mTypeName.indexOf(
':' );
315 if ( index != -1 && index < mTypeName.length() )
317 mTypeName = mTypeName.mid( index + 1 );
318 mTypeNameBA = mTypeName.toUtf8();
319 mTypeNamePtr = mTypeNameBA.constData();
320 mTypeNameUTF8Len = strlen( mTypeNamePtr );
324 XML_SetUserData( mParser,
this );
325 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
326 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
329 static QString stripNS(
const QString &
string )
331 int index =
string.indexOf(
':' );
332 if ( index != -1 && index <
string.length() )
334 return string.mid( index + 1 );
341 const QMap< QString, QPair<QString, QString> > &mapFieldNameToSrcLayerNameFieldName,
343 bool invertAxisOrientation )
344 : mLayerProperties( layerProperties )
345 , mTypeNameUTF8Len( 0 )
347 , mGeometryAttributeUTF8Len( 0 )
349 , mIsException( false )
350 , mTruncatedResponse( false )
352 , mFeatureTupleDepth( 0 )
354 , mCurrentWKB( nullptr, 0 )
355 , mBoundedByNullFound( false )
357 , mCoorMode( Coordinate )
359 , mAxisOrientationLogic( axisOrientationLogic )
360 , mInvertAxisOrientationRequest( invertAxisOrientation )
361 , mInvertAxisOrientation( invertAxisOrientation )
362 , mNumberReturned( -1 )
363 , mNumberMatched( -1 )
364 , mFoundUnhandledGeometryElement( false )
366 mThematicAttributes.clear();
367 for (
int i = 0; i < fields.
size(); i++ )
369 QMap< QString, QPair<QString, QString> >::const_iterator att_it = mapFieldNameToSrcLayerNameFieldName.constFind( fields.
at( i ).
name() );
370 if ( att_it != mapFieldNameToSrcLayerNameFieldName.constEnd() )
372 if ( mLayerProperties.size() == 1 )
373 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
375 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
378 bool alreadyFoundGeometry =
false;
379 for (
int i = 0; i < mLayerProperties.size(); i++ )
382 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
384 if ( alreadyFoundGeometry )
386 QgsDebugMsg( QStringLiteral(
"Will ignore geometry field %1 from typename %2" ).
387 arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ) );
388 mLayerProperties[i].mGeometryAttribute.clear();
390 alreadyFoundGeometry =
true;
392 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
395 if ( mLayerProperties.size() == 1 )
397 mTypeName = mLayerProperties[0].mName;
398 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
399 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
400 mGeometryAttributePtr = mGeometryAttributeBA.constData();
401 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
402 int index = mTypeName.indexOf(
':' );
403 if ( index != -1 && index < mTypeName.length() )
405 mTypeName = mTypeName.mid( index + 1 );
407 mTypeNameBA = mTypeName.toUtf8();
408 mTypeNamePtr = mTypeNameBA.constData();
409 mTypeNameUTF8Len = strlen( mTypeNamePtr );
415 XML_SetUserData( mParser,
this );
416 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
417 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
423 XML_ParserFree( mParser );
428 delete featPair.first;
431 delete mCurrentFeature;
447 if ( XML_Parse( mParser, data.data(), data.size(), atEnd ) == 0 )
449 XML_Error errorCode = XML_GetErrorCode( mParser );
450 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" )
451 .arg( XML_ErrorString( errorCode ) )
452 .arg( XML_GetCurrentLineNumber( mParser ) )
453 .arg( XML_GetCurrentColumnNumber( mParser ) );
463 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
464 mFeatureList.clear();
468 #define LOCALNAME_EQUALS(string_constant) \ 469 ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 ) 471 void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
473 const int elLen =
static_cast<int>( strlen( el ) );
475 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
476 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
477 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
478 ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
482 if ( !mGMLNameSpaceURIPtr && pszSep )
489 else if ( nsLen == static_cast<int>( strlen( GML32_NAMESPACE ) ) && memcmp( el, GML32_NAMESPACE, nsLen ) == 0 )
491 mGMLNameSpaceURI = GML32_NAMESPACE;
492 mGMLNameSpaceURIPtr = GML32_NAMESPACE;
496 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
499 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
500 parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
502 mGeometryString.append(
"<", 1 );
503 mGeometryString.append( pszLocalName, localNameLen );
504 mGeometryString.append(
" ", 1 );
505 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
507 mGeometryString.append( attrIter[0] );
508 mGeometryString.append(
"=\"", 2 );
509 mGeometryString.append( attrIter[1] );
510 mGeometryString.append(
"\" ", 2 );
513 mGeometryString.append(
">", 1 );
518 mParseModeStack.push( Coordinate );
519 mCoorMode = QgsGmlStreamingParser::Coordinate;
521 mCoordinateSeparator = readAttribute( QStringLiteral(
"cs" ), attr );
522 if ( mCoordinateSeparator.isEmpty() )
524 mCoordinateSeparator =
',';
526 mTupleSeparator = readAttribute( QStringLiteral(
"ts" ), attr );
527 if ( mTupleSeparator.isEmpty() )
529 mTupleSeparator =
' ';
535 mParseModeStack.push( QgsGmlStreamingParser::PosList );
536 mCoorMode = QgsGmlStreamingParser::PosList;
538 if ( elDimension == 0 )
540 QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
542 int dimension = srsDimension.toInt( &ok );
545 elDimension = dimension;
549 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
551 localNameLen == static_cast<int>( mGeometryAttributeUTF8Len ) &&
552 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
554 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
555 mFoundUnhandledGeometryElement =
false;
556 mGeometryString.clear();
561 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
563 mBoundedByNullFound =
false;
565 else if ( parseMode == BoundingBox &&
568 mParseModeStack.push( QgsGmlStreamingParser::Null );
569 mBoundedByNullFound =
true;
571 else if ( parseMode == BoundingBox &&
575 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
577 else if ( parseMode == Envelope &&
580 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
583 else if ( parseMode == Envelope &&
586 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
589 else if ( parseMode == None && !mTypeNamePtr &&
592 Q_ASSERT( !mCurrentFeature );
593 mCurrentFeature =
new QgsFeature( mFeatureCount );
597 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
598 mCurrentFeatureId.clear();
600 else if ( parseMode == Tuple )
602 QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
603 QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
604 if ( iter != mMapTypeNameToProperties.constEnd() )
606 mFeatureTupleDepth = mParseDepth;
607 mCurrentTypename = currentTypename;
608 mGeometryAttribute.clear();
609 if ( mCurrentWKB.
size() == 0 )
611 mGeometryAttribute = iter.value().mGeometryAttribute;
613 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
614 mGeometryAttributePtr = mGeometryAttributeBA.constData();
615 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
616 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
618 if ( mGMLNameSpaceURI.isEmpty() )
628 id = readAttribute( QString( GML32_NAMESPACE ) +
NS_SEPARATOR +
"id", attr );
631 mGMLNameSpaceURI = GML32_NAMESPACE;
632 mGMLNameSpaceURIPtr = GML32_NAMESPACE;
637 id = readAttribute( mGMLNameSpaceURI +
NS_SEPARATOR +
"id", attr );
638 if ( !mCurrentFeatureId.isEmpty() )
639 mCurrentFeatureId +=
'|';
640 mCurrentFeatureId += id;
643 else if ( parseMode == None &&
644 localNameLen == static_cast<int>( mTypeNameUTF8Len ) &&
645 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
647 Q_ASSERT( !mCurrentFeature );
648 mCurrentFeature =
new QgsFeature( mFeatureCount );
652 mParseModeStack.push( QgsGmlStreamingParser::Feature );
653 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
654 if ( mCurrentFeatureId.isEmpty() )
659 if ( mGMLNameSpaceURI.isEmpty() )
662 if ( !mCurrentFeatureId.isEmpty() )
669 mCurrentFeatureId = readAttribute( QString( GML32_NAMESPACE ) +
NS_SEPARATOR +
"id", attr );
670 if ( !mCurrentFeatureId.isEmpty() )
672 mGMLNameSpaceURI = GML32_NAMESPACE;
673 mGMLNameSpaceURIPtr = GML32_NAMESPACE;
678 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI +
NS_SEPARATOR +
"id", attr );
682 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
695 localNameLen == static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
698 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
703 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
705 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
710 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
712 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
717 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
719 else if ( parseMode == FeatureTuple )
721 QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
722 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
724 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
725 mAttributeName = mCurrentTypename +
'|' + localName;
729 else if ( parseMode == Feature )
731 QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
732 if ( mThematicAttributes.contains( localName ) )
734 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
735 mAttributeName = localName;
742 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
744 QString name = readAttribute( QStringLiteral(
"name" ), attr );
745 if ( mThematicAttributes.contains( name ) )
747 QString value = readAttribute( QStringLiteral(
"value" ), attr );
748 setAttribute( name, value );
755 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
756 if ( numberReturned.isEmpty() )
757 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
759 mNumberReturned = numberReturned.toInt( &conversionOk );
761 mNumberReturned = -1;
763 QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
764 mNumberMatched = numberMatched.toInt( &conversionOk );
771 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
776 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
781 mTruncatedResponse =
true;
783 else if ( !mGeometryString.empty() &&
799 mFoundUnhandledGeometryElement =
true;
802 if ( !mGeometryString.empty() )
805 if ( elDimension == 0 && isGeom )
809 QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
811 int dimension = srsDimension.toInt( &ok );
814 elDimension = dimension;
818 if ( elDimension != 0 || mDimensionStack.isEmpty() )
820 mDimensionStack.push( elDimension );
824 mDimensionStack.push( mDimensionStack.back() );
827 if ( mEpsg == 0 && isGeom )
829 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
831 QgsDebugMsg( QStringLiteral(
"error, could not get epsg id" ) );
835 QgsDebugMsg( QStringLiteral(
"mEpsg = %1" ).arg( mEpsg ) );
842 void QgsGmlStreamingParser::endElement(
const XML_Char *el )
846 const int elLen =
static_cast<int>( strlen( el ) );
848 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
849 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
850 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
851 ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
853 int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
855 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
857 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
859 mParseModeStack.pop();
861 else if ( parseMode == PosList && isGMLNS &&
864 mDimension = lastDimension;
865 mParseModeStack.pop();
867 else if ( parseMode == AttributeTuple &&
868 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
870 mParseModeStack.pop();
872 setAttribute( mAttributeName, mStringCash );
874 else if ( parseMode == Attribute && QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
876 mParseModeStack.pop();
878 setAttribute( mAttributeName, mStringCash );
880 else if ( parseMode == Geometry &&
881 localNameLen == static_cast<int>( mGeometryAttributeUTF8Len ) &&
882 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
884 mParseModeStack.pop();
885 if ( mFoundUnhandledGeometryElement )
890 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
891 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
892 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
894 g.
fromWkb( pabyBuffer, wkbSize );
895 if ( mInvertAxisOrientation )
897 g.transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
899 Q_ASSERT( mCurrentFeature );
903 mGeometryString.clear();
905 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
908 if ( mCurrentExtent.
isNull() &&
909 !mBoundedByNullFound &&
910 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
912 QgsDebugMsg( QStringLiteral(
"creation of bounding box failed" ) );
914 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
915 !mCurrentFeature && mFeatureCount == 0 )
917 mLayerExtent = mCurrentExtent;
921 mParseModeStack.pop();
925 mParseModeStack.pop();
927 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
929 mParseModeStack.pop();
931 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
933 QList<QgsPointXY> points;
934 pointsFromPosListString( points, mStringCash, 2 );
935 if ( points.size() == 1 )
940 mParseModeStack.pop();
942 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
944 QList<QgsPointXY> points;
945 pointsFromPosListString( points, mStringCash, 2 );
946 if ( points.size() == 1 )
951 mParseModeStack.pop();
953 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
955 mParseModeStack.pop();
956 mFeatureTupleDepth = 0;
958 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
960 ( parseMode == Feature &&
961 localNameLen == static_cast<int>( mTypeNameUTF8Len ) &&
962 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
964 Q_ASSERT( mCurrentFeature );
967 if ( mCurrentWKB.
size() > 0 )
974 else if ( !mCurrentExtent.
isEmpty() )
983 mCurrentFeature =
nullptr;
985 mParseModeStack.pop();
989 QList<QgsPointXY> pointList;
990 if ( pointsFromString( pointList, mStringCash ) != 0 )
995 if ( pointList.isEmpty() )
998 if ( parseMode == QgsGmlStreamingParser::Geometry )
1001 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
1014 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
1018 if ( !mCurrentWKBFragments.isEmpty() )
1020 mCurrentWKBFragments.last().push_back( wkbPtr );
1024 QgsDebugMsg( QStringLiteral(
"No wkb fragments" ) );
1033 QList<QgsPointXY> pointList;
1034 if ( pointsFromString( pointList, mStringCash ) != 0 )
1038 if ( parseMode == QgsGmlStreamingParser::Geometry )
1040 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
1053 if ( getLineWKB( wkbPtr, pointList ) != 0 )
1057 if ( !mCurrentWKBFragments.isEmpty() )
1059 mCurrentWKBFragments.last().push_back( wkbPtr );
1063 QgsDebugMsg( QStringLiteral(
"no wkb fragments" ) );
1068 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1071 QList<QgsPointXY> pointList;
1072 if ( pointsFromString( pointList, mStringCash ) != 0 )
1078 if ( getRingWKB( wkbPtr, pointList ) != 0 )
1083 if ( !mCurrentWKBFragments.isEmpty() )
1085 mCurrentWKBFragments.last().push_back( wkbPtr );
1090 QgsDebugMsg( QStringLiteral(
"no wkb fragments" ) );
1093 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1101 if ( parseMode == Geometry )
1103 createPolygonFromFragments();
1106 else if ( parseMode == MultiPoint && isGMLNS &&
1110 mParseModeStack.pop();
1111 createMultiPointFromFragments();
1113 else if ( parseMode == MultiLine && isGMLNS &&
1117 mParseModeStack.pop();
1118 createMultiLineFromFragments();
1120 else if ( parseMode == MultiPolygon && isGMLNS &&
1124 mParseModeStack.pop();
1125 createMultiPolygonFromFragments();
1129 mParseModeStack.pop();
1131 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1133 mExceptionText = mStringCash;
1134 mParseModeStack.pop();
1137 if ( !mGeometryString.empty() )
1139 mGeometryString.append(
"</", 2 );
1140 mGeometryString.append( pszLocalName, localNameLen );
1141 mGeometryString.append(
">", 1 );
1146 void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1149 if ( mParseModeStack.isEmpty() )
1154 if ( !mGeometryString.empty() )
1156 mGeometryString.append( chars, len );
1159 QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1160 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1161 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1162 parseMode == QgsGmlStreamingParser::Coordinate ||
1163 parseMode == QgsGmlStreamingParser::PosList ||
1164 parseMode == QgsGmlStreamingParser::LowerCorner ||
1165 parseMode == QgsGmlStreamingParser::UpperCorner ||
1166 parseMode == QgsGmlStreamingParser::ExceptionText )
1168 mStringCash.append( QString::fromUtf8( chars, len ) );
1172 void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1175 QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1176 bool conversionOk =
true;
1177 if ( att_it != mThematicAttributes.constEnd() )
1180 switch ( att_it.value().second.type() )
1182 case QVariant::Double:
1183 var = QVariant( value.toDouble( &conversionOk ) );
1186 var = QVariant( value.toInt( &conversionOk ) );
1188 case QVariant::LongLong:
1189 var = QVariant( value.toLongLong( &conversionOk ) );
1191 case QVariant::DateTime:
1192 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1195 var = QVariant( value );
1198 if ( ! conversionOk )
1202 Q_ASSERT( mCurrentFeature );
1203 mCurrentFeature->
setAttribute( att_it.value().first, var );
1207 int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1212 if ( strcmp( attr[i],
"srsName" ) == 0 )
1214 QString epsgString( attr[i + 1] );
1215 QString epsgNrString;
1216 bool bIsUrn =
false;
1217 if ( epsgString.startsWith( QLatin1String(
"http" ) ) )
1219 epsgNrString = epsgString.section(
'#', 1, 1 );
1222 else if ( epsgString.startsWith( QLatin1String(
"urn:ogc:def:crs:EPSG:" ) ) ||
1223 epsgString.startsWith( QLatin1String(
"urn:x-ogc:def:crs:EPSG:" ) ) )
1226 epsgNrString = epsgString.split(
':' ).last();
1230 epsgNrString = epsgString.section(
':', 1, 1 );
1233 int eNr = epsgNrString.toInt( &conversionOk );
1234 if ( !conversionOk )
1239 mSrsName = epsgString;
1247 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1258 QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const 1263 if ( attributeName.compare( attr[i] ) == 0 )
1265 return QString::fromUtf8( attr[i + 1] );
1272 bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const 1274 QList<QgsPointXY> points;
1275 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1280 if ( points.size() < 2 )
1285 r.
set( points[0], points[1] );
1290 int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const 1293 QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
1294 QStringList tuples_coordinates;
1296 bool conversionSuccess;
1298 QStringList::const_iterator tupleIterator;
1299 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1301 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
1302 if ( tuples_coordinates.size() < 2 )
1306 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1307 if ( !conversionSuccess )
1311 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1312 if ( !conversionSuccess )
1321 int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const 1324 QStringList coordinates = coordString.split(
' ', QString::SkipEmptyParts );
1326 if ( coordinates.size() % dimension != 0 )
1328 QgsDebugMsg( QStringLiteral(
"Wrong number of coordinates" ) );
1331 int ncoor = coordinates.size() / dimension;
1332 for (
int i = 0; i < ncoor; i++ )
1334 bool conversionSuccess;
1335 double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1336 if ( !conversionSuccess )
1340 double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1341 if ( !conversionSuccess )
1350 int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const 1352 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1354 return pointsFromCoordinateString( points, coordString );
1356 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1358 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1363 int QgsGmlStreamingParser::getPointWKB(
QgsWkbPtr &wkbPtr,
const QgsPointXY &point )
const 1365 int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1366 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1374 int QgsGmlStreamingParser::getLineWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const 1376 int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1377 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1383 QList<QgsPointXY>::const_iterator iter;
1384 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1386 fillPtr << iter->x() << iter->y();
1392 int QgsGmlStreamingParser::getRingWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const 1394 int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1395 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1399 fillPtr << ringCoordinates.
size();
1401 QList<QgsPointXY>::const_iterator iter;
1402 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1404 fillPtr << iter->x() << iter->y();
1410 int QgsGmlStreamingParser::createMultiLineFromFragments()
1412 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1413 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1420 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1421 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1423 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1424 wkbPtr += wkbIt->
size();
1428 mCurrentWKBFragments.clear();
1433 int QgsGmlStreamingParser::createMultiPointFromFragments()
1435 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1436 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1441 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1442 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1444 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1445 wkbPtr += wkbIt->
size();
1449 mCurrentWKBFragments.clear();
1455 int QgsGmlStreamingParser::createPolygonFromFragments()
1457 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1458 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1463 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1464 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1466 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1467 wkbPtr += wkbIt->
size();
1471 mCurrentWKBFragments.clear();
1476 int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1479 size += 1 + 2 *
sizeof( int );
1480 size += totalWKBFragmentSize();
1481 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1483 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1489 QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
1491 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1496 QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
1497 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1499 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->
size() );
1500 wkbPtr += innerWkbIt->
size();
1501 delete[] *innerWkbIt;
1505 mCurrentWKBFragments.clear();
1510 int QgsGmlStreamingParser::totalWKBFragmentSize()
const 1513 Q_FOREACH (
const QList<QgsWkbPtr> &list, mCurrentWKBFragments )
#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.