28 #include <QNetworkRequest>
29 #include <QNetworkReply>
30 #include <QProgressDialog>
40 static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
45 const QString &geometryAttribute,
47 : mParser(
typeName, geometryAttribute, fields )
51 int index = mTypeName.indexOf(
':' );
52 if ( index != -1 && index < mTypeName.length() )
54 mTypeName = mTypeName.mid( index + 1 );
63 QNetworkRequest request( uri );
66 if ( !authcfg.isEmpty() )
71 tr(
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
78 else if ( !userName.isNull() || !password.isNull() )
80 request.setRawHeader(
"Authorization",
"Basic " + QStringLiteral(
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
84 if ( !authcfg.isEmpty() )
90 tr(
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
98 connect( reply, &QNetworkReply::finished,
this, &QgsGml::setFinished );
99 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsGml::handleProgressEvent );
102 QProgressDialog *progressDialog =
nullptr;
103 QWidget *mainWindow =
nullptr;
104 QWidgetList topLevelWidgets = qApp->topLevelWidgets();
105 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
107 if ( ( *it )->objectName() == QLatin1String(
"QgisApp" ) )
115 progressDialog =
new QProgressDialog( tr(
"Loading GML data\n%1" ).arg( mTypeName ), tr(
"Abort" ), 0, 0, mainWindow );
116 progressDialog->setWindowModality( Qt::ApplicationModal );
119 connect( progressDialog, &QProgressDialog::canceled,
this, &QgsGml::setFinished );
120 progressDialog->show();
130 QByteArray readData = reply->readAll();
131 if ( !readData.isEmpty() )
134 if ( !mParser.
processData( readData, atEnd, errorMsg ) )
138 QCoreApplication::processEvents();
141 fillMapsFromParser();
143 QNetworkReply::NetworkError replyError = reply->error();
144 QString replyErrorString = reply->errorString();
147 delete progressDialog;
152 tr(
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
166 calculateExtentFromFeatures();
181 if ( !mParser.
processData( data,
true , errorMsg ) )
184 fillMapsFromParser();
194 void QgsGml::fillMapsFromParser()
197 const auto constFeatures = features;
201 const QString &gmlId = featPair.second;
202 mFeatures.insert( feat->
id(), feat );
203 if ( !gmlId.isEmpty() )
205 mIdMap.insert( feat->
id(), gmlId );
210 void QgsGml::setFinished()
215 void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
217 if ( totalSteps < 0 )
227 void QgsGml::calculateExtentFromFeatures()
229 if ( mFeatures.empty() )
236 bool bboxInitialized =
false;
238 for (
int i = 0; i < mFeatures.size(); ++i )
240 currentFeature = mFeatures[i];
241 if ( !currentFeature )
245 currentGeometry = currentFeature->
geometry();
246 if ( !currentGeometry.
isNull() )
248 if ( !bboxInitialized )
251 bboxInitialized =
true;
276 const QString &geometryAttribute,
279 bool invertAxisOrientation )
281 , mTypeNameBA( mTypeName.toUtf8() )
282 , mTypeNamePtr( mTypeNameBA.constData() )
283 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
285 , mGeometryAttribute( geometryAttribute )
286 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
287 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
288 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
290 , mIsException( false )
291 , mTruncatedResponse( false )
293 , mFeatureTupleDepth( 0 )
295 , mCurrentWKB( nullptr, 0 )
296 , mBoundedByNullFound( false )
298 , mCoorMode( Coordinate )
300 , mAxisOrientationLogic( axisOrientationLogic )
301 , mInvertAxisOrientationRequest( invertAxisOrientation )
302 , mInvertAxisOrientation( invertAxisOrientation )
303 , mNumberReturned( -1 )
304 , mNumberMatched( -1 )
305 , mFoundUnhandledGeometryElement( false )
307 mThematicAttributes.clear();
308 for (
int i = 0; i < fields.
size(); i++ )
310 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
315 int index = mTypeName.indexOf(
':' );
316 if ( index != -1 && index < mTypeName.length() )
318 mTypeName = mTypeName.mid( index + 1 );
319 mTypeNameBA = mTypeName.toUtf8();
320 mTypeNamePtr = mTypeNameBA.constData();
321 mTypeNameUTF8Len = strlen( mTypeNamePtr );
325 XML_SetUserData( mParser,
this );
326 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
327 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
330 static QString stripNS(
const QString &
string )
332 int index =
string.indexOf(
':' );
333 if ( index != -1 && index <
string.length() )
335 return string.mid( index + 1 );
342 const QMap< QString, QPair<QString, QString> > &mapFieldNameToSrcLayerNameFieldName,
344 bool invertAxisOrientation )
345 : mLayerProperties( layerProperties )
346 , mTypeNameUTF8Len( 0 )
348 , mGeometryAttributeUTF8Len( 0 )
350 , mIsException( false )
351 , mTruncatedResponse( false )
353 , mFeatureTupleDepth( 0 )
355 , mCurrentWKB( nullptr, 0 )
356 , mBoundedByNullFound( false )
358 , mCoorMode( Coordinate )
360 , mAxisOrientationLogic( axisOrientationLogic )
361 , mInvertAxisOrientationRequest( invertAxisOrientation )
362 , mInvertAxisOrientation( invertAxisOrientation )
363 , mNumberReturned( -1 )
364 , mNumberMatched( -1 )
365 , mFoundUnhandledGeometryElement( false )
367 mThematicAttributes.clear();
368 for (
int i = 0; i < fields.
size(); i++ )
370 QMap< QString, QPair<QString, QString> >::const_iterator att_it = mapFieldNameToSrcLayerNameFieldName.constFind( fields.
at( i ).
name() );
371 if ( att_it != mapFieldNameToSrcLayerNameFieldName.constEnd() )
373 if ( mLayerProperties.size() == 1 )
374 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
376 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
379 bool alreadyFoundGeometry =
false;
380 for (
int i = 0; i < mLayerProperties.size(); i++ )
383 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
385 if ( alreadyFoundGeometry )
387 QgsDebugMsg( QStringLiteral(
"Will ignore geometry field %1 from typename %2" ).
388 arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ) );
389 mLayerProperties[i].mGeometryAttribute.clear();
391 alreadyFoundGeometry =
true;
393 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
396 if ( mLayerProperties.size() == 1 )
398 mTypeName = mLayerProperties[0].mName;
399 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
400 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
401 mGeometryAttributePtr = mGeometryAttributeBA.constData();
402 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
403 int index = mTypeName.indexOf(
':' );
404 if ( index != -1 && index < mTypeName.length() )
406 mTypeName = mTypeName.mid( index + 1 );
408 mTypeNameBA = mTypeName.toUtf8();
409 mTypeNamePtr = mTypeNameBA.constData();
410 mTypeNameUTF8Len = strlen( mTypeNamePtr );
416 XML_SetUserData( mParser,
this );
417 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
418 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
424 XML_ParserFree( mParser );
427 const auto constMFeatureList = mFeatureList;
430 delete featPair.first;
433 delete mCurrentFeature;
449 if ( XML_Parse( mParser, data.data(), data.size(), atEnd ) == 0 )
451 XML_Error errorCode = XML_GetErrorCode( mParser );
452 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" )
453 .arg( XML_ErrorString( errorCode ) )
454 .arg( XML_GetCurrentLineNumber( mParser ) )
455 .arg( XML_GetCurrentColumnNumber( mParser ) );
465 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
466 mFeatureList.clear();
470 #define LOCALNAME_EQUALS(string_constant) \
471 ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 )
473 void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
475 const int elLen =
static_cast<int>( strlen( el ) );
477 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
478 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
479 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
480 ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
484 if ( !mGMLNameSpaceURIPtr && pszSep )
498 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
501 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
502 parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
504 mGeometryString.append(
"<", 1 );
505 mGeometryString.append( pszLocalName, localNameLen );
506 mGeometryString.append(
" ", 1 );
507 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
509 const size_t nAttrLen = strlen( attrIter[0] );
512 if ( nAttrLen > GML32_NAMESPACE_LEN &&
513 attrIter[0][GML32_NAMESPACE_LEN] ==
'?' &&
516 mGeometryString.append(
"gml:" );
517 mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
519 else if ( nAttrLen > GML_NAMESPACE_LEN &&
520 attrIter[0][GML_NAMESPACE_LEN] ==
'?' &&
521 memcmp( attrIter[0],
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
523 mGeometryString.append(
"gml:" );
524 mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
528 mGeometryString.append( attrIter[0] );
530 mGeometryString.append(
"=\"", 2 );
531 mGeometryString.append( attrIter[1] );
532 mGeometryString.append(
"\" ", 2 );
535 mGeometryString.append(
">", 1 );
540 mParseModeStack.push( Coordinate );
541 mCoorMode = QgsGmlStreamingParser::Coordinate;
543 mCoordinateSeparator = readAttribute( QStringLiteral(
"cs" ), attr );
544 if ( mCoordinateSeparator.isEmpty() )
546 mCoordinateSeparator =
',';
548 mTupleSeparator = readAttribute( QStringLiteral(
"ts" ), attr );
549 if ( mTupleSeparator.isEmpty() )
551 mTupleSeparator =
' ';
557 mParseModeStack.push( QgsGmlStreamingParser::PosList );
558 mCoorMode = QgsGmlStreamingParser::PosList;
560 if ( elDimension == 0 )
562 QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
564 int dimension = srsDimension.toInt( &ok );
567 elDimension = dimension;
571 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
573 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
574 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
576 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
577 mFoundUnhandledGeometryElement =
false;
578 mGeometryString.clear();
583 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
585 mBoundedByNullFound =
false;
587 else if ( parseMode == BoundingBox &&
590 mParseModeStack.push( QgsGmlStreamingParser::Null );
591 mBoundedByNullFound =
true;
593 else if ( parseMode == BoundingBox &&
597 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
599 else if ( parseMode == Envelope &&
602 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
605 else if ( parseMode == Envelope &&
608 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
611 else if ( parseMode == None && !mTypeNamePtr &&
614 Q_ASSERT( !mCurrentFeature );
615 mCurrentFeature =
new QgsFeature( mFeatureCount );
619 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
620 mCurrentFeatureId.clear();
622 else if ( parseMode == Tuple )
624 QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
625 QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
626 if ( iter != mMapTypeNameToProperties.constEnd() )
628 mFeatureTupleDepth = mParseDepth;
629 mCurrentTypename = currentTypename;
630 mGeometryAttribute.clear();
631 if ( mCurrentWKB.
size() == 0 )
633 mGeometryAttribute = iter.value().mGeometryAttribute;
635 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
636 mGeometryAttributePtr = mGeometryAttributeBA.constData();
637 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
638 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
640 if ( mGMLNameSpaceURI.isEmpty() )
659 id = readAttribute( mGMLNameSpaceURI +
NS_SEPARATOR +
"id", attr );
660 if ( !mCurrentFeatureId.isEmpty() )
661 mCurrentFeatureId +=
'|';
662 mCurrentFeatureId += id;
665 else if ( parseMode == None &&
666 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
667 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
669 Q_ASSERT( !mCurrentFeature );
670 mCurrentFeature =
new QgsFeature( mFeatureCount );
674 mParseModeStack.push( QgsGmlStreamingParser::Feature );
675 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
676 if ( mCurrentFeatureId.isEmpty() )
681 if ( mGMLNameSpaceURI.isEmpty() )
684 if ( !mCurrentFeatureId.isEmpty() )
692 if ( !mCurrentFeatureId.isEmpty() )
700 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI +
NS_SEPARATOR +
"id", attr );
704 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
717 localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
720 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
725 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
727 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
732 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
734 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
739 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
741 else if ( parseMode == FeatureTuple )
743 QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
744 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
746 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
747 mAttributeName = mCurrentTypename +
'|' + localName;
751 else if ( parseMode == Feature )
753 QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
754 if ( mThematicAttributes.contains( localName ) )
756 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
757 mAttributeName = localName;
764 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
766 QString name = readAttribute( QStringLiteral(
"name" ), attr );
767 if ( mThematicAttributes.contains( name ) )
769 QString value = readAttribute( QStringLiteral(
"value" ), attr );
770 setAttribute( name, value );
777 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
779 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
783 mNumberReturned = -1;
785 QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
793 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
798 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
803 mTruncatedResponse =
true;
805 else if ( !mGeometryString.empty() &&
821 mFoundUnhandledGeometryElement =
true;
824 if ( !mGeometryString.empty() )
827 if ( elDimension == 0 && isGeom )
831 QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
833 int dimension = srsDimension.toInt( &ok );
836 elDimension = dimension;
840 if ( elDimension != 0 || mDimensionStack.isEmpty() )
842 mDimensionStack.push( elDimension );
846 mDimensionStack.push( mDimensionStack.back() );
849 if ( mEpsg == 0 && isGeom )
851 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
853 QgsDebugMsg( QStringLiteral(
"error, could not get epsg id" ) );
857 QgsDebugMsg( QStringLiteral(
"mEpsg = %1" ).arg( mEpsg ) );
864 void QgsGmlStreamingParser::endElement(
const XML_Char *el )
868 const int elLen =
static_cast<int>( strlen( el ) );
870 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
871 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
872 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
873 ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
875 int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
877 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
879 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
881 mParseModeStack.pop();
883 else if ( parseMode == PosList && isGMLNS &&
886 mDimension = lastDimension;
887 mParseModeStack.pop();
889 else if ( parseMode == AttributeTuple &&
890 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
892 mParseModeStack.pop();
894 setAttribute( mAttributeName, mStringCash );
896 else if ( parseMode == Attribute && QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
898 mParseModeStack.pop();
900 setAttribute( mAttributeName, mStringCash );
902 else if ( parseMode == Geometry &&
903 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
904 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
906 mParseModeStack.pop();
907 if ( mFoundUnhandledGeometryElement )
913 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
914 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
915 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
917 g.
fromWkb( pabyBuffer, wkbSize );
918 if ( mInvertAxisOrientation )
920 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
922 Q_ASSERT( mCurrentFeature );
926 mGeometryString.clear();
928 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
931 if ( mCurrentExtent.
isNull() &&
932 !mBoundedByNullFound &&
933 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
935 QgsDebugMsg( QStringLiteral(
"creation of bounding box failed" ) );
937 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
938 !mCurrentFeature && mFeatureCount == 0 )
940 mLayerExtent = mCurrentExtent;
944 mParseModeStack.pop();
948 mParseModeStack.pop();
950 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
952 mParseModeStack.pop();
954 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
956 QList<QgsPointXY> points;
957 pointsFromPosListString( points, mStringCash, 2 );
958 if ( points.size() == 1 )
963 mParseModeStack.pop();
965 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
967 QList<QgsPointXY> points;
968 pointsFromPosListString( points, mStringCash, 2 );
969 if ( points.size() == 1 )
974 mParseModeStack.pop();
976 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
978 mParseModeStack.pop();
979 mFeatureTupleDepth = 0;
981 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
983 ( parseMode == Feature &&
984 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
985 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
987 Q_ASSERT( mCurrentFeature );
990 if ( mCurrentWKB.
size() > 0 )
997 else if ( !mCurrentExtent.
isEmpty() )
1006 mCurrentFeature =
nullptr;
1008 mParseModeStack.pop();
1012 QList<QgsPointXY> pointList;
1013 if ( pointsFromString( pointList, mStringCash ) != 0 )
1018 if ( pointList.isEmpty() )
1021 if ( parseMode == QgsGmlStreamingParser::Geometry )
1024 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
1037 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
1041 if ( !mCurrentWKBFragments.isEmpty() )
1043 mCurrentWKBFragments.last().push_back( wkbPtr );
1047 QgsDebugMsg( QStringLiteral(
"No wkb fragments" ) );
1056 QList<QgsPointXY> pointList;
1057 if ( pointsFromString( pointList, mStringCash ) != 0 )
1061 if ( parseMode == QgsGmlStreamingParser::Geometry )
1063 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
1076 if ( getLineWKB( wkbPtr, pointList ) != 0 )
1080 if ( !mCurrentWKBFragments.isEmpty() )
1082 mCurrentWKBFragments.last().push_back( wkbPtr );
1086 QgsDebugMsg( QStringLiteral(
"no wkb fragments" ) );
1091 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1094 QList<QgsPointXY> pointList;
1095 if ( pointsFromString( pointList, mStringCash ) != 0 )
1101 if ( getRingWKB( wkbPtr, pointList ) != 0 )
1106 if ( !mCurrentWKBFragments.isEmpty() )
1108 mCurrentWKBFragments.last().push_back( wkbPtr );
1113 QgsDebugMsg( QStringLiteral(
"no wkb fragments" ) );
1116 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1124 if ( parseMode == Geometry )
1126 createPolygonFromFragments();
1129 else if ( parseMode == MultiPoint && isGMLNS &&
1133 mParseModeStack.pop();
1134 createMultiPointFromFragments();
1136 else if ( parseMode == MultiLine && isGMLNS &&
1140 mParseModeStack.pop();
1141 createMultiLineFromFragments();
1143 else if ( parseMode == MultiPolygon && isGMLNS &&
1147 mParseModeStack.pop();
1148 createMultiPolygonFromFragments();
1152 mParseModeStack.pop();
1154 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1156 mExceptionText = mStringCash;
1157 mParseModeStack.pop();
1160 if ( !mGeometryString.empty() )
1162 mGeometryString.append(
"</", 2 );
1163 mGeometryString.append( pszLocalName, localNameLen );
1164 mGeometryString.append(
">", 1 );
1169 void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1172 if ( mParseModeStack.isEmpty() )
1177 if ( !mGeometryString.empty() )
1179 mGeometryString.append( chars, len );
1182 QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1183 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1184 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1185 parseMode == QgsGmlStreamingParser::Coordinate ||
1186 parseMode == QgsGmlStreamingParser::PosList ||
1187 parseMode == QgsGmlStreamingParser::LowerCorner ||
1188 parseMode == QgsGmlStreamingParser::UpperCorner ||
1189 parseMode == QgsGmlStreamingParser::ExceptionText )
1191 mStringCash.append( QString::fromUtf8( chars, len ) );
1195 void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1198 QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1199 bool conversionOk =
true;
1200 if ( att_it != mThematicAttributes.constEnd() )
1203 switch ( att_it.value().second.type() )
1205 case QVariant::Double:
1206 var = QVariant( value.toDouble( &conversionOk ) );
1209 var = QVariant( value.toInt( &conversionOk ) );
1211 case QVariant::LongLong:
1212 var = QVariant( value.toLongLong( &conversionOk ) );
1214 case QVariant::DateTime:
1215 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1218 var = QVariant( value );
1221 if ( ! conversionOk )
1225 Q_ASSERT( mCurrentFeature );
1226 mCurrentFeature->
setAttribute( att_it.value().first, var );
1230 int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1235 if ( strcmp( attr[i],
"srsName" ) == 0 )
1237 QString epsgString( attr[i + 1] );
1238 QString epsgNrString;
1239 bool bIsUrn =
false;
1240 if ( epsgString.startsWith( QLatin1String(
"http://www.opengis.net/gml/srs/" ) ) )
1242 epsgNrString = epsgString.section(
'#', 1, 1 );
1245 else if ( epsgString.startsWith( QLatin1String(
"urn:ogc:def:crs:EPSG:" ) ) ||
1246 epsgString.startsWith( QLatin1String(
"urn:x-ogc:def:crs:EPSG:" ) ) )
1249 epsgNrString = epsgString.split(
':' ).last();
1251 else if ( epsgString.startsWith( QLatin1String(
"http://www.opengis.net/def/crs/EPSG/" ) ) )
1254 epsgNrString = epsgString.split(
'/' ).last();
1258 epsgNrString = epsgString.section(
':', 1, 1 );
1261 int eNr = epsgNrString.toInt( &conversionOk );
1262 if ( !conversionOk )
1267 mSrsName = epsgString;
1275 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1286 QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1291 if ( attributeName.compare( attr[i] ) == 0 )
1293 return QString::fromUtf8( attr[i + 1] );
1300 bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1302 QList<QgsPointXY> points;
1303 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1308 if ( points.size() < 2 )
1313 r.
set( points[0], points[1] );
1318 int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const
1321 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1322 QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
1324 QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1326 QStringList tuples_coordinates;
1328 bool conversionSuccess;
1330 QStringList::const_iterator tupleIterator;
1331 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1333 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1334 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
1336 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1338 if ( tuples_coordinates.size() < 2 )
1342 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1343 if ( !conversionSuccess )
1347 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1348 if ( !conversionSuccess )
1357 int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const
1360 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1361 QStringList coordinates = coordString.split(
' ', QString::SkipEmptyParts );
1363 QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1366 if ( coordinates.size() % dimension != 0 )
1368 QgsDebugMsg( QStringLiteral(
"Wrong number of coordinates" ) );
1371 int ncoor = coordinates.size() / dimension;
1372 for (
int i = 0; i < ncoor; i++ )
1374 bool conversionSuccess;
1375 double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1376 if ( !conversionSuccess )
1380 double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1381 if ( !conversionSuccess )
1390 int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const
1392 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1394 return pointsFromCoordinateString( points, coordString );
1396 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1398 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1403 int QgsGmlStreamingParser::getPointWKB(
QgsWkbPtr &wkbPtr,
const QgsPointXY &point )
const
1405 int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1406 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1414 int QgsGmlStreamingParser::getLineWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const
1416 int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1417 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1423 QList<QgsPointXY>::const_iterator iter;
1424 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1426 fillPtr << iter->x() << iter->y();
1432 int QgsGmlStreamingParser::getRingWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const
1434 int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1435 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1439 fillPtr << ringCoordinates.size();
1441 QList<QgsPointXY>::const_iterator iter;
1442 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1444 fillPtr << iter->x() << iter->y();
1450 int QgsGmlStreamingParser::createMultiLineFromFragments()
1452 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1453 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::createMultiPointFromFragments()
1475 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1476 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1481 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1482 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1484 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1485 wkbPtr += wkbIt->
size();
1489 mCurrentWKBFragments.clear();
1495 int QgsGmlStreamingParser::createPolygonFromFragments()
1497 int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1498 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1503 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1504 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1506 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1507 wkbPtr += wkbIt->
size();
1511 mCurrentWKBFragments.clear();
1516 int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1519 size += 1 + 2 *
sizeof( int );
1520 size += totalWKBFragmentSize();
1521 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1523 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1529 QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
1531 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1536 QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
1537 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1539 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1540 wkbPtr += innerWkbIt->
size();
1541 delete[] *innerWkbIt;
1545 mCurrentWKBFragments.clear();
1550 int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1553 const auto constMCurrentWKBFragments = mCurrentWKBFragments;
1554 for (
const QList<QgsWkbPtr> &list : constMCurrentWKBFragments )
1556 const auto constList = list;