27 #include <QNetworkRequest> 28 #include <QNetworkReply> 29 #include <QProgressDialog> 39 static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
40 static const char *GML32_NAMESPACE =
"http://www.opengis.net/gml/3.2";
43 const QString &typeName,
44 const QString &geometryAttribute,
46 : mParser( typeName, geometryAttribute, fields )
47 , mTypeName( typeName )
50 int index = mTypeName.indexOf(
':' );
51 if ( index != -1 && index < mTypeName.length() )
53 mTypeName = mTypeName.mid( index + 1 );
62 QNetworkRequest request( uri );
63 if ( !authcfg.isEmpty() )
68 tr(
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
75 else if ( !userName.isNull() || !password.isNull() )
77 request.setRawHeader(
"Authorization",
"Basic " + QStringLiteral(
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
81 if ( !authcfg.isEmpty() )
87 tr(
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
95 connect( reply, &QNetworkReply::finished,
this, &QgsGml::setFinished );
96 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsGml::handleProgressEvent );
99 QProgressDialog *progressDialog =
nullptr;
100 QWidget *mainWindow =
nullptr;
101 QWidgetList topLevelWidgets = qApp->topLevelWidgets();
102 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
104 if ( ( *it )->objectName() == QLatin1String(
"QgisApp" ) )
112 progressDialog =
new QProgressDialog( tr(
"Loading GML data\n%1" ).arg( mTypeName ), tr(
"Abort" ), 0, 0, mainWindow );
113 progressDialog->setWindowModality( Qt::ApplicationModal );
116 connect( progressDialog, &QProgressDialog::canceled,
this, &QgsGml::setFinished );
117 progressDialog->show();
127 QByteArray readData = reply->readAll();
128 if ( !readData.isEmpty() )
131 if ( !mParser.
processData( readData, atEnd, errorMsg ) )
135 QCoreApplication::processEvents();
138 fillMapsFromParser();
140 QNetworkReply::NetworkError replyError = reply->error();
141 QString replyErrorString = reply->errorString();
144 delete progressDialog;
149 tr(
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
163 calculateExtentFromFeatures();
178 if ( !mParser.
processData( data,
true , errorMsg ) )
181 fillMapsFromParser();
191 void QgsGml::fillMapsFromParser()
197 const QString &gmlId = featPair.second;
198 mFeatures.insert( feat->
id(), feat );
199 if ( !gmlId.isEmpty() )
201 mIdMap.insert( feat->
id(), gmlId );
206 void QgsGml::setFinished()
211 void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
213 if ( totalSteps < 0 )
223 void QgsGml::calculateExtentFromFeatures()
225 if ( mFeatures.empty() )
232 bool bboxInitialized =
false;
234 for (
int i = 0; i < mFeatures.size(); ++i )
236 currentFeature = mFeatures[i];
237 if ( !currentFeature )
241 currentGeometry = currentFeature->
geometry();
242 if ( !currentGeometry.
isNull() )
244 if ( !bboxInitialized )
247 bboxInitialized =
true;
272 const QString &geometryAttribute,
275 bool invertAxisOrientation )
276 : mTypeName( typeName )
277 , mTypeNameBA( mTypeName.toUtf8() )
278 , mTypeNamePtr( mTypeNameBA.constData() )
279 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
281 , mGeometryAttribute( geometryAttribute )
282 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
283 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
284 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
286 , mIsException( false )
287 , mTruncatedResponse( false )
289 , mFeatureTupleDepth( 0 )
291 , mCurrentWKB( nullptr, 0 )
292 , mBoundedByNullFound( false )
294 , mCoorMode( Coordinate )
296 , mAxisOrientationLogic( axisOrientationLogic )
297 , mInvertAxisOrientationRequest( invertAxisOrientation )
298 , mInvertAxisOrientation( invertAxisOrientation )
299 , mNumberReturned( -1 )
300 , mNumberMatched( -1 )
301 , mFoundUnhandledGeometryElement( false )
303 mThematicAttributes.clear();
304 for (
int i = 0; i < fields.
size(); i++ )
306 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
311 int index = mTypeName.indexOf(
':' );
312 if ( index != -1 && index < mTypeName.length() )
314 mTypeName = mTypeName.mid( index + 1 );
315 mTypeNameBA = mTypeName.toUtf8();
316 mTypeNamePtr = mTypeNameBA.constData();
317 mTypeNameUTF8Len = strlen( mTypeNamePtr );
321 XML_SetUserData( mParser,
this );
322 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
323 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
326 static QString stripNS(
const QString &
string )
328 int index =
string.indexOf(
':' );
329 if ( index != -1 && index <
string.length() )
331 return string.mid( index + 1 );
338 const QMap< QString, QPair<QString, QString> > &mapFieldNameToSrcLayerNameFieldName,
340 bool invertAxisOrientation )
341 : mLayerProperties( layerProperties )
342 , mTypeNameUTF8Len( 0 )
344 , mGeometryAttributeUTF8Len( 0 )
346 , mIsException( false )
347 , mTruncatedResponse( false )
349 , mFeatureTupleDepth( 0 )
351 , mCurrentWKB( nullptr, 0 )
352 , mBoundedByNullFound( false )
354 , mCoorMode( Coordinate )
356 , mAxisOrientationLogic( axisOrientationLogic )
357 , mInvertAxisOrientationRequest( invertAxisOrientation )
358 , mInvertAxisOrientation( invertAxisOrientation )
359 , mNumberReturned( -1 )
360 , mNumberMatched( -1 )
361 , mFoundUnhandledGeometryElement( false )
363 mThematicAttributes.clear();
364 for (
int i = 0; i < fields.
size(); i++ )
366 QMap< QString, QPair<QString, QString> >::const_iterator att_it = mapFieldNameToSrcLayerNameFieldName.constFind( fields.
at( i ).
name() );
367 if ( att_it != mapFieldNameToSrcLayerNameFieldName.constEnd() )
369 if ( mLayerProperties.size() == 1 )
370 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
372 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
375 bool alreadyFoundGeometry =
false;
376 for (
int i = 0; i < mLayerProperties.size(); i++ )
379 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
381 if ( alreadyFoundGeometry )
383 QgsDebugMsg( QString(
"Will ignore geometry field %1 from typename %2" ).
384 arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ) );
385 mLayerProperties[i].mGeometryAttribute.clear();
387 alreadyFoundGeometry =
true;
389 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
392 if ( mLayerProperties.size() == 1 )
394 mTypeName = mLayerProperties[0].mName;
395 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
396 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
397 mGeometryAttributePtr = mGeometryAttributeBA.constData();
398 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
399 int index = mTypeName.indexOf(
':' );
400 if ( index != -1 && index < mTypeName.length() )
402 mTypeName = mTypeName.mid( index + 1 );
404 mTypeNameBA = mTypeName.toUtf8();
405 mTypeNamePtr = mTypeNameBA.constData();
406 mTypeNameUTF8Len = strlen( mTypeNamePtr );
412 XML_SetUserData( mParser,
this );
413 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
414 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
420 XML_ParserFree( mParser );
425 delete featPair.first;
428 delete mCurrentFeature;
444 if ( XML_Parse( mParser, data.data(), data.size(), atEnd ) == 0 )
446 XML_Error errorCode = XML_GetErrorCode( mParser );
447 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" )
448 .arg( XML_ErrorString( errorCode ) )
449 .arg( XML_GetCurrentLineNumber( mParser ) )
450 .arg( XML_GetCurrentColumnNumber( mParser ) );
460 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
461 mFeatureList.clear();
465 #define LOCALNAME_EQUALS(string_constant) \ 466 ( localNameLen == ( int )strlen( string_constant ) && memcmp(pszLocalName, string_constant, localNameLen) == 0 ) 468 void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
470 const int elLen = ( int )strlen( el );
472 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
473 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
474 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
475 ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
479 if ( !mGMLNameSpaceURIPtr && pszSep )
486 else if ( nsLen == (
int )strlen( GML32_NAMESPACE ) && memcmp( el, GML32_NAMESPACE, nsLen ) == 0 )
488 mGMLNameSpaceURI = GML32_NAMESPACE;
489 mGMLNameSpaceURIPtr = GML32_NAMESPACE;
493 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
496 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
497 parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
499 mGeometryString.append(
"<", 1 );
500 mGeometryString.append( pszLocalName, localNameLen );
501 mGeometryString.append(
" ", 1 );
502 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
504 mGeometryString.append( attrIter[0] );
505 mGeometryString.append(
"=\"", 2 );
506 mGeometryString.append( attrIter[1] );
507 mGeometryString.append(
"\" ", 2 );
510 mGeometryString.append(
">", 1 );
515 mParseModeStack.push( Coordinate );
516 mCoorMode = QgsGmlStreamingParser::Coordinate;
518 mCoordinateSeparator = readAttribute( QStringLiteral(
"cs" ), attr );
519 if ( mCoordinateSeparator.isEmpty() )
521 mCoordinateSeparator =
',';
523 mTupleSeparator = readAttribute( QStringLiteral(
"ts" ), attr );
524 if ( mTupleSeparator.isEmpty() )
526 mTupleSeparator =
' ';
532 mParseModeStack.push( QgsGmlStreamingParser::PosList );
533 mCoorMode = QgsGmlStreamingParser::PosList;
535 if ( elDimension == 0 )
537 QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
539 int dimension = srsDimension.toInt( &ok );
542 elDimension = dimension;
546 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
548 localNameLen == static_cast<int>( mGeometryAttributeUTF8Len ) &&
549 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
551 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
552 mFoundUnhandledGeometryElement =
false;
553 mGeometryString.clear();
558 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
560 mBoundedByNullFound =
false;
562 else if ( parseMode == BoundingBox &&
565 mParseModeStack.push( QgsGmlStreamingParser::Null );
566 mBoundedByNullFound =
true;
568 else if ( parseMode == BoundingBox &&
572 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
574 else if ( parseMode == Envelope &&
577 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
580 else if ( parseMode == Envelope &&
583 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
586 else if ( parseMode == None && !mTypeNamePtr &&
589 Q_ASSERT( !mCurrentFeature );
590 mCurrentFeature =
new QgsFeature( mFeatureCount );
594 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
595 mCurrentFeatureId.clear();
597 else if ( parseMode == Tuple )
599 QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
600 QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
601 if ( iter != mMapTypeNameToProperties.constEnd() )
603 mFeatureTupleDepth = mParseDepth;
604 mCurrentTypename = currentTypename;
605 mGeometryAttribute.clear();
606 if ( mCurrentWKB.
size() == 0 )
608 mGeometryAttribute = iter.value().mGeometryAttribute;
610 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
611 mGeometryAttributePtr = mGeometryAttributeBA.constData();
612 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
613 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
615 if ( mGMLNameSpaceURI.isEmpty() )
625 id = readAttribute( QString( GML32_NAMESPACE ) +
NS_SEPARATOR +
"id", attr );
628 mGMLNameSpaceURI = GML32_NAMESPACE;
629 mGMLNameSpaceURIPtr = GML32_NAMESPACE;
634 id = readAttribute( mGMLNameSpaceURI +
NS_SEPARATOR +
"id", attr );
635 if ( !mCurrentFeatureId.isEmpty() )
636 mCurrentFeatureId +=
'|';
637 mCurrentFeatureId += id;
640 else if ( parseMode == None &&
641 localNameLen == static_cast<int>( mTypeNameUTF8Len ) &&
642 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
644 Q_ASSERT( !mCurrentFeature );
645 mCurrentFeature =
new QgsFeature( mFeatureCount );
649 mParseModeStack.push( QgsGmlStreamingParser::Feature );
650 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
651 if ( mCurrentFeatureId.isEmpty() )
656 if ( mGMLNameSpaceURI.isEmpty() )
659 if ( !mCurrentFeatureId.isEmpty() )
666 mCurrentFeatureId = readAttribute( QString( GML32_NAMESPACE ) +
NS_SEPARATOR +
"id", attr );
667 if ( !mCurrentFeatureId.isEmpty() )
669 mGMLNameSpaceURI = GML32_NAMESPACE;
670 mGMLNameSpaceURIPtr = GML32_NAMESPACE;
675 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI +
NS_SEPARATOR +
"id", attr );
679 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
692 localNameLen == (
int )strlen(
"Polygon" ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
695 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
700 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
702 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
707 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
709 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
714 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
716 else if ( parseMode == FeatureTuple )
718 QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
719 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
721 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
722 mAttributeName = mCurrentTypename +
'|' + localName;
726 else if ( parseMode == Feature )
728 QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
729 if ( mThematicAttributes.contains( localName ) )
731 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
732 mAttributeName = localName;
739 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
741 QString name = readAttribute( QStringLiteral(
"name" ), attr );
742 if ( mThematicAttributes.contains( name ) )
744 QString value = readAttribute( QStringLiteral(
"value" ), attr );
745 setAttribute( name, value );
752 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
753 if ( numberReturned.isEmpty() )
754 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
756 mNumberReturned = numberReturned.toInt( &conversionOk );
758 mNumberReturned = -1;
760 QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
761 mNumberMatched = numberMatched.toInt( &conversionOk );
768 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
773 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
778 mTruncatedResponse =
true;
780 else if ( !mGeometryString.empty() &&
796 mFoundUnhandledGeometryElement =
true;
799 if ( !mGeometryString.empty() )
802 if ( elDimension == 0 && isGeom )
806 QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
808 int dimension = srsDimension.toInt( &ok );
811 elDimension = dimension;
815 if ( elDimension != 0 )
817 mDimension = elDimension;
819 mDimensionStack.push( mDimension );
821 if ( mEpsg == 0 && isGeom )
823 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
829 QgsDebugMsg( QString(
"mEpsg = %1" ).arg( mEpsg ) );
836 void QgsGmlStreamingParser::endElement(
const XML_Char *el )
840 const int elLen = ( int )strlen( el );
842 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
843 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
844 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
845 ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
847 mDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.top();
849 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
851 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
853 mParseModeStack.pop();
855 else if ( parseMode == PosList && isGMLNS &&
858 mParseModeStack.pop();
860 else if ( parseMode == AttributeTuple &&
861 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
863 mParseModeStack.pop();
865 setAttribute( mAttributeName, mStringCash );
867 else if ( parseMode == Attribute && QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
869 mParseModeStack.pop();
871 setAttribute( mAttributeName, mStringCash );
873 else if ( parseMode == Geometry &&
874 localNameLen == static_cast<int>( mGeometryAttributeUTF8Len ) &&
875 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
877 mParseModeStack.pop();
878 if ( mFoundUnhandledGeometryElement )
883 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
884 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
885 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
887 g.
fromWkb( pabyBuffer, wkbSize );
888 if ( mInvertAxisOrientation )
890 g.transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
892 Q_ASSERT( mCurrentFeature );
896 mGeometryString.clear();
898 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
901 if ( mCurrentExtent.
isNull() &&
902 !mBoundedByNullFound &&
903 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
907 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
908 !mCurrentFeature && mFeatureCount == 0 )
910 mLayerExtent = mCurrentExtent;
914 mParseModeStack.pop();
918 mParseModeStack.pop();
920 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
922 mParseModeStack.pop();
924 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
926 QList<QgsPointXY> points;
927 pointsFromPosListString( points, mStringCash, 2 );
928 if ( points.size() == 1 )
933 mParseModeStack.pop();
935 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
937 QList<QgsPointXY> points;
938 pointsFromPosListString( points, mStringCash, 2 );
939 if ( points.size() == 1 )
944 mParseModeStack.pop();
946 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
948 mParseModeStack.pop();
949 mFeatureTupleDepth = 0;
951 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
953 ( parseMode == Feature &&
954 localNameLen == static_cast<int>( mTypeNameUTF8Len ) &&
955 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
957 Q_ASSERT( mCurrentFeature );
960 if ( mCurrentWKB.
size() > 0 )
967 else if ( !mCurrentExtent.
isEmpty() )
976 mCurrentFeature =
nullptr;
978 mParseModeStack.pop();
982 QList<QgsPointXY> pointList;
983 if ( pointsFromString( pointList, mStringCash ) != 0 )
988 if ( pointList.isEmpty() )
991 if ( parseMode == QgsGmlStreamingParser::Geometry )
994 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
1007 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
1011 if ( !mCurrentWKBFragments.isEmpty() )
1013 mCurrentWKBFragments.last().push_back( wkbPtr );
1026 QList<QgsPointXY> pointList;
1027 if ( pointsFromString( pointList, mStringCash ) != 0 )
1031 if ( parseMode == QgsGmlStreamingParser::Geometry )
1033 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
1046 if ( getLineWKB( wkbPtr, pointList ) != 0 )
1050 if ( !mCurrentWKBFragments.isEmpty() )
1052 mCurrentWKBFragments.last().push_back( wkbPtr );
1061 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1064 QList<QgsPointXY> pointList;
1065 if ( pointsFromString( pointList, mStringCash ) != 0 )
1071 if ( getRingWKB( wkbPtr, pointList ) != 0 )
1076 if ( !mCurrentWKBFragments.isEmpty() )
1078 mCurrentWKBFragments.last().push_back( wkbPtr );
1086 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1094 if ( parseMode == Geometry )
1096 createPolygonFromFragments();
1099 else if ( parseMode == MultiPoint && isGMLNS &&
1103 mParseModeStack.pop();
1104 createMultiPointFromFragments();
1106 else if ( parseMode == MultiLine && isGMLNS &&
1110 mParseModeStack.pop();
1111 createMultiLineFromFragments();
1113 else if ( parseMode == MultiPolygon && isGMLNS &&
1117 mParseModeStack.pop();
1118 createMultiPolygonFromFragments();
1122 mParseModeStack.pop();
1124 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1126 mExceptionText = mStringCash;
1127 mParseModeStack.pop();
1130 if ( !mGeometryString.empty() )
1132 mGeometryString.append(
"</", 2 );
1133 mGeometryString.append( pszLocalName, localNameLen );
1134 mGeometryString.append(
">", 1 );
1139 void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1142 if ( mParseModeStack.isEmpty() )
1147 if ( !mGeometryString.empty() )
1149 mGeometryString.append( chars, len );
1152 QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1153 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1154 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1155 parseMode == QgsGmlStreamingParser::Coordinate ||
1156 parseMode == QgsGmlStreamingParser::PosList ||
1157 parseMode == QgsGmlStreamingParser::LowerCorner ||
1158 parseMode == QgsGmlStreamingParser::UpperCorner ||
1159 parseMode == QgsGmlStreamingParser::ExceptionText )
1161 mStringCash.append( QString::fromUtf8( chars, len ) );
1165 void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1168 QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1169 if ( att_it != mThematicAttributes.constEnd() )
1172 switch ( att_it.value().second.type() )
1174 case QVariant::Double:
1175 var = QVariant( value.toDouble() );
1178 var = QVariant( value.toInt() );
1180 case QVariant::LongLong:
1181 var = QVariant( value.toLongLong() );
1183 case QVariant::DateTime:
1184 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1187 var = QVariant( value );
1190 Q_ASSERT( mCurrentFeature );
1191 mCurrentFeature->
setAttribute( att_it.value().first, var );
1195 int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1200 if ( strcmp( attr[i],
"srsName" ) == 0 )
1202 QString epsgString( attr[i + 1] );
1203 QString epsgNrString;
1204 bool bIsUrn =
false;
1205 if ( epsgString.startsWith( QLatin1String(
"http" ) ) )
1207 epsgNrString = epsgString.section(
'#', 1, 1 );
1210 else if ( epsgString.startsWith( QLatin1String(
"urn:ogc:def:crs:EPSG:" ) ) ||
1211 epsgString.startsWith( QLatin1String(
"urn:x-ogc:def:crs:EPSG:" ) ) )
1214 epsgNrString = epsgString.split(
':' ).last();
1218 epsgNrString = epsgString.section(
':', 1, 1 );
1221 int eNr = epsgNrString.toInt( &conversionOk );
1222 if ( !conversionOk )
1227 mSrsName = epsgString;
1235 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1246 QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const 1251 if ( attributeName.compare( attr[i] ) == 0 )
1253 return QString::fromUtf8( attr[i + 1] );
1260 bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const 1262 QList<QgsPointXY> points;
1263 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1268 if ( points.size() < 2 )
1273 r.
set( points[0], points[1] );
1278 int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const 1281 QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
1282 QStringList tuples_coordinates;
1284 bool conversionSuccess;
1286 QStringList::const_iterator tupleIterator;
1287 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1289 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
1290 if ( tuples_coordinates.size() < 2 )
1294 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1295 if ( !conversionSuccess )
1299 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1300 if ( !conversionSuccess )
1309 int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const 1312 QStringList coordinates = coordString.split(
' ', QString::SkipEmptyParts );
1314 if ( coordinates.size() % dimension != 0 )
1319 int ncoor = coordinates.size() / dimension;
1320 for (
int i = 0; i < ncoor; i++ )
1322 bool conversionSuccess;
1323 double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1324 if ( !conversionSuccess )
1328 double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1329 if ( !conversionSuccess )
1338 int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const 1340 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1342 return pointsFromCoordinateString( points, coordString );
1344 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1346 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1351 int QgsGmlStreamingParser::getPointWKB(
QgsWkbPtr &wkbPtr,
const QgsPointXY &point )
const 1353 int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1354 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1362 int QgsGmlStreamingParser::getLineWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const 1364 int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1365 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1371 QList<QgsPointXY>::const_iterator iter;
1372 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1374 fillPtr << iter->x() << iter->y();
1380 int QgsGmlStreamingParser::getRingWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const 1382 int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1383 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1387 fillPtr << ringCoordinates.
size();
1389 QList<QgsPointXY>::const_iterator iter;
1390 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1392 fillPtr << iter->x() << iter->y();
1398 int QgsGmlStreamingParser::createMultiLineFromFragments()
1400 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1401 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1408 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1409 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1411 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1412 wkbPtr += wkbIt->
size();
1416 mCurrentWKBFragments.clear();
1421 int QgsGmlStreamingParser::createMultiPointFromFragments()
1423 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1424 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1429 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1430 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1432 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1433 wkbPtr += wkbIt->
size();
1437 mCurrentWKBFragments.clear();
1443 int QgsGmlStreamingParser::createPolygonFromFragments()
1445 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1446 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1451 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1452 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1454 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1455 wkbPtr += wkbIt->
size();
1459 mCurrentWKBFragments.clear();
1464 int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1467 size += 1 + 2 *
sizeof( int );
1468 size += totalWKBFragmentSize();
1469 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1471 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1477 QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
1479 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1484 QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
1485 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1487 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->
size() );
1488 wkbPtr += innerWkbIt->
size();
1489 delete[] *innerWkbIt;
1493 mCurrentWKBFragments.clear();
1498 int QgsGmlStreamingParser::totalWKBFragmentSize()
const 1501 Q_FOREACH (
const QList<QgsWkbPtr> &list, mCurrentWKBFragments )
int getEPSGCode() const
Return the EPSG code, or 0 if unknown.
A rectangle specified with double values.
int size() const
Return 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.
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
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
Return 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.
int numberMatched() const
Return 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...
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)
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning)
add a message to the instance (and create it if necessary)
void totalStepsUpdate(int totalSteps)
QgsField at(int i) const
Get field at particular index (must be in range 0..N-1)
const QString GML_NAMESPACE
std::unique_ptr< void, OGRGeometryDeleter > ogr_geometry_unique_ptr
Scoped OGR geometry.
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.
QgsGeometry geometry() const
Returns the geometry associated with this feature.
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)
Expand the rectangle so that 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 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.
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
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
Return the geometry type.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.