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";
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( QStringLiteral(
"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 == static_cast<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 =
static_cast<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 == static_cast<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 == static_cast<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 || mDimensionStack.isEmpty() )
817 mDimensionStack.push( elDimension );
821 mDimensionStack.push( mDimensionStack.back() );
824 if ( mEpsg == 0 && isGeom )
826 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
828 QgsDebugMsg( QStringLiteral(
"error, could not get epsg id" ) );
832 QgsDebugMsg( QStringLiteral(
"mEpsg = %1" ).arg( mEpsg ) );
839 void QgsGmlStreamingParser::endElement(
const XML_Char *el )
843 const int elLen =
static_cast<int>( strlen( el ) );
845 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
846 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
847 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
848 ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
850 int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
852 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
854 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
856 mParseModeStack.pop();
858 else if ( parseMode == PosList && isGMLNS &&
861 mDimension = lastDimension;
862 mParseModeStack.pop();
864 else if ( parseMode == AttributeTuple &&
865 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
867 mParseModeStack.pop();
869 setAttribute( mAttributeName, mStringCash );
871 else if ( parseMode == Attribute && QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
873 mParseModeStack.pop();
875 setAttribute( mAttributeName, mStringCash );
877 else if ( parseMode == Geometry &&
878 localNameLen == static_cast<int>( mGeometryAttributeUTF8Len ) &&
879 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
881 mParseModeStack.pop();
882 if ( mFoundUnhandledGeometryElement )
887 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
888 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
889 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
891 g.
fromWkb( pabyBuffer, wkbSize );
892 if ( mInvertAxisOrientation )
894 g.transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
896 Q_ASSERT( mCurrentFeature );
900 mGeometryString.clear();
902 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
905 if ( mCurrentExtent.
isNull() &&
906 !mBoundedByNullFound &&
907 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
909 QgsDebugMsg( QStringLiteral(
"creation of bounding box failed" ) );
911 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
912 !mCurrentFeature && mFeatureCount == 0 )
914 mLayerExtent = mCurrentExtent;
918 mParseModeStack.pop();
922 mParseModeStack.pop();
924 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
926 mParseModeStack.pop();
928 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
930 QList<QgsPointXY> points;
931 pointsFromPosListString( points, mStringCash, 2 );
932 if ( points.size() == 1 )
937 mParseModeStack.pop();
939 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
941 QList<QgsPointXY> points;
942 pointsFromPosListString( points, mStringCash, 2 );
943 if ( points.size() == 1 )
948 mParseModeStack.pop();
950 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
952 mParseModeStack.pop();
953 mFeatureTupleDepth = 0;
955 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
957 ( parseMode == Feature &&
958 localNameLen == static_cast<int>( mTypeNameUTF8Len ) &&
959 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
961 Q_ASSERT( mCurrentFeature );
964 if ( mCurrentWKB.
size() > 0 )
971 else if ( !mCurrentExtent.
isEmpty() )
980 mCurrentFeature =
nullptr;
982 mParseModeStack.pop();
986 QList<QgsPointXY> pointList;
987 if ( pointsFromString( pointList, mStringCash ) != 0 )
992 if ( pointList.isEmpty() )
995 if ( parseMode == QgsGmlStreamingParser::Geometry )
998 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
1011 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
1015 if ( !mCurrentWKBFragments.isEmpty() )
1017 mCurrentWKBFragments.last().push_back( wkbPtr );
1021 QgsDebugMsg( QStringLiteral(
"No wkb fragments" ) );
1030 QList<QgsPointXY> pointList;
1031 if ( pointsFromString( pointList, mStringCash ) != 0 )
1035 if ( parseMode == QgsGmlStreamingParser::Geometry )
1037 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
1050 if ( getLineWKB( wkbPtr, pointList ) != 0 )
1054 if ( !mCurrentWKBFragments.isEmpty() )
1056 mCurrentWKBFragments.last().push_back( wkbPtr );
1060 QgsDebugMsg( QStringLiteral(
"no wkb fragments" ) );
1065 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1068 QList<QgsPointXY> pointList;
1069 if ( pointsFromString( pointList, mStringCash ) != 0 )
1075 if ( getRingWKB( wkbPtr, pointList ) != 0 )
1080 if ( !mCurrentWKBFragments.isEmpty() )
1082 mCurrentWKBFragments.last().push_back( wkbPtr );
1087 QgsDebugMsg( QStringLiteral(
"no wkb fragments" ) );
1090 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1098 if ( parseMode == Geometry )
1100 createPolygonFromFragments();
1103 else if ( parseMode == MultiPoint && isGMLNS &&
1107 mParseModeStack.pop();
1108 createMultiPointFromFragments();
1110 else if ( parseMode == MultiLine && isGMLNS &&
1114 mParseModeStack.pop();
1115 createMultiLineFromFragments();
1117 else if ( parseMode == MultiPolygon && isGMLNS &&
1121 mParseModeStack.pop();
1122 createMultiPolygonFromFragments();
1126 mParseModeStack.pop();
1128 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1130 mExceptionText = mStringCash;
1131 mParseModeStack.pop();
1134 if ( !mGeometryString.empty() )
1136 mGeometryString.append(
"</", 2 );
1137 mGeometryString.append( pszLocalName, localNameLen );
1138 mGeometryString.append(
">", 1 );
1143 void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1146 if ( mParseModeStack.isEmpty() )
1151 if ( !mGeometryString.empty() )
1153 mGeometryString.append( chars, len );
1156 QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1157 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1158 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1159 parseMode == QgsGmlStreamingParser::Coordinate ||
1160 parseMode == QgsGmlStreamingParser::PosList ||
1161 parseMode == QgsGmlStreamingParser::LowerCorner ||
1162 parseMode == QgsGmlStreamingParser::UpperCorner ||
1163 parseMode == QgsGmlStreamingParser::ExceptionText )
1165 mStringCash.append( QString::fromUtf8( chars, len ) );
1169 void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1172 QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1173 bool conversionOk =
true;
1174 if ( att_it != mThematicAttributes.constEnd() )
1177 switch ( att_it.value().second.type() )
1179 case QVariant::Double:
1180 var = QVariant( value.toDouble( &conversionOk ) );
1183 var = QVariant( value.toInt( &conversionOk ) );
1185 case QVariant::LongLong:
1186 var = QVariant( value.toLongLong( &conversionOk ) );
1188 case QVariant::DateTime:
1189 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1192 var = QVariant( value );
1195 if ( ! conversionOk )
1199 Q_ASSERT( mCurrentFeature );
1200 mCurrentFeature->
setAttribute( att_it.value().first, var );
1204 int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1209 if ( strcmp( attr[i],
"srsName" ) == 0 )
1211 QString epsgString( attr[i + 1] );
1212 QString epsgNrString;
1213 bool bIsUrn =
false;
1214 if ( epsgString.startsWith( QLatin1String(
"http" ) ) )
1216 epsgNrString = epsgString.section(
'#', 1, 1 );
1219 else if ( epsgString.startsWith( QLatin1String(
"urn:ogc:def:crs:EPSG:" ) ) ||
1220 epsgString.startsWith( QLatin1String(
"urn:x-ogc:def:crs:EPSG:" ) ) )
1223 epsgNrString = epsgString.split(
':' ).last();
1227 epsgNrString = epsgString.section(
':', 1, 1 );
1230 int eNr = epsgNrString.toInt( &conversionOk );
1231 if ( !conversionOk )
1236 mSrsName = epsgString;
1244 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1255 QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const 1260 if ( attributeName.compare( attr[i] ) == 0 )
1262 return QString::fromUtf8( attr[i + 1] );
1269 bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const 1271 QList<QgsPointXY> points;
1272 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1277 if ( points.size() < 2 )
1282 r.
set( points[0], points[1] );
1287 int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const 1290 QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
1291 QStringList tuples_coordinates;
1293 bool conversionSuccess;
1295 QStringList::const_iterator tupleIterator;
1296 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1298 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
1299 if ( tuples_coordinates.size() < 2 )
1303 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1304 if ( !conversionSuccess )
1308 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1309 if ( !conversionSuccess )
1318 int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const 1321 QStringList coordinates = coordString.split(
' ', QString::SkipEmptyParts );
1323 if ( coordinates.size() % dimension != 0 )
1325 QgsDebugMsg( QStringLiteral(
"Wrong number of coordinates" ) );
1328 int ncoor = coordinates.size() / dimension;
1329 for (
int i = 0; i < ncoor; i++ )
1331 bool conversionSuccess;
1332 double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1333 if ( !conversionSuccess )
1337 double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1338 if ( !conversionSuccess )
1347 int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const 1349 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1351 return pointsFromCoordinateString( points, coordString );
1353 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1355 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1360 int QgsGmlStreamingParser::getPointWKB(
QgsWkbPtr &wkbPtr,
const QgsPointXY &point )
const 1362 int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1363 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1371 int QgsGmlStreamingParser::getLineWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const 1373 int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1374 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1380 QList<QgsPointXY>::const_iterator iter;
1381 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1383 fillPtr << iter->x() << iter->y();
1389 int QgsGmlStreamingParser::getRingWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const 1391 int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1392 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1396 fillPtr << ringCoordinates.
size();
1398 QList<QgsPointXY>::const_iterator iter;
1399 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1401 fillPtr << iter->x() << iter->y();
1407 int QgsGmlStreamingParser::createMultiLineFromFragments()
1409 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1410 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1417 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1418 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1420 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1421 wkbPtr += wkbIt->
size();
1425 mCurrentWKBFragments.clear();
1430 int QgsGmlStreamingParser::createMultiPointFromFragments()
1432 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1433 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1438 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1439 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1441 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1442 wkbPtr += wkbIt->
size();
1446 mCurrentWKBFragments.clear();
1452 int QgsGmlStreamingParser::createPolygonFromFragments()
1454 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1455 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1460 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1461 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1463 memcpy( wkbPtr, *wkbIt, wkbIt->
size() );
1464 wkbPtr += wkbIt->
size();
1468 mCurrentWKBFragments.clear();
1473 int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1476 size += 1 + 2 *
sizeof( int );
1477 size += totalWKBFragmentSize();
1478 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1480 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1486 QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
1488 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1493 QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
1494 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1496 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->
size() );
1497 wkbPtr += innerWkbIt->
size();
1498 delete[] *innerWkbIt;
1502 mCurrentWKBFragments.clear();
1507 int QgsGmlStreamingParser::totalWKBFragmentSize()
const 1510 Q_FOREACH (
const QList<QgsWkbPtr> &list, mCurrentWKBFragments )
int getEPSGCode() const
Returns the EPSG code, or 0 if unknown.
A rectangle specified with double values.
bool isEmpty() const
Returns true if the rectangle is empty.
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...
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.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
QgsRectangle boundingBox() const
Returns the bounding box of the 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)
int numberReturned() const
Returns WFS 2.0 "numberReturned" or WFS 1.1 "numberOfFeatures" attribute, or -1 if invalid/not found...
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
const QgsCoordinateReferenceSystem & crs
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
static endian_t endian()
Returns whether this machine uses big or little endian.
#define LOCALNAME_EQUALS(string_constant)
void totalStepsUpdate(int totalSteps)
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) ...
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).
QgsWkbTypes::Type wkbType() const
Returns the geometry type.
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.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
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.
This class represents a coordinate reference system (CRS).
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
int size() const
Returns number of items.
QgsGmlStreamingParser(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields, AxisOrientationLogic axisOrientationLogic=Honour_EPSG_if_urn, bool invertAxisOrientation=false)
Constructor.
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...
QgsCoordinateReferenceSystem crs() const
Returns features spatial reference system.
void set(const QgsPointXY &p1, const QgsPointXY &p2)
Sets the rectangle from two QgsPoints.
void setXMinimum(double x)
Set the minimum x value.
bool hasAxisInverted() const
Returns whether axis is inverted (e.g., for WMS 1.3) for the CRS.