28 #include <QNetworkRequest>
29 #include <QNetworkReply>
30 #include <QProgressDialog>
35 #include <QRegularExpression>
42 static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
47 const QString &geometryAttribute,
49 : mParser(
typeName, geometryAttribute, fields )
53 const int index = mTypeName.indexOf(
':' );
54 if ( index != -1 && index < mTypeName.length() )
56 mTypeName = mTypeName.mid( index + 1 );
65 QNetworkRequest request( uri );
68 if ( !authcfg.isEmpty() )
73 tr(
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
75 Qgis::MessageLevel::Critical
80 else if ( !userName.isNull() || !password.isNull() )
82 request.setRawHeader(
"Authorization",
"Basic " + QStringLiteral(
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
86 if ( !authcfg.isEmpty() )
92 tr(
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
94 Qgis::MessageLevel::Critical
100 connect( reply, &QNetworkReply::finished,
this, &QgsGml::setFinished );
101 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsGml::handleProgressEvent );
104 QProgressDialog *progressDialog =
nullptr;
105 QWidget *mainWindow =
nullptr;
106 const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
107 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
109 if ( ( *it )->objectName() == QLatin1String(
"QgisApp" ) )
117 progressDialog =
new QProgressDialog( tr(
"Loading GML data\n%1" ).arg( mTypeName ), tr(
"Abort" ), 0, 0, mainWindow );
118 progressDialog->setWindowModality( Qt::ApplicationModal );
121 connect( progressDialog, &QProgressDialog::canceled,
this, &QgsGml::setFinished );
122 progressDialog->show();
132 const QByteArray readData = reply->readAll();
133 if ( !readData.isEmpty() )
136 if ( !mParser.
processData( readData, atEnd, errorMsg ) )
140 QCoreApplication::processEvents();
143 fillMapsFromParser();
145 const QNetworkReply::NetworkError replyError = reply->error();
146 const QString replyErrorString = reply->errorString();
149 delete progressDialog;
154 tr(
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
156 Qgis::MessageLevel::Critical
168 calculateExtentFromFeatures();
183 if ( !mParser.
processData( data,
true , errorMsg ) )
186 fillMapsFromParser();
196 void QgsGml::fillMapsFromParser()
199 const auto constFeatures = features;
203 const QString &gmlId = featPair.second;
204 mFeatures.insert( feat->
id(), feat );
205 if ( !gmlId.isEmpty() )
207 mIdMap.insert( feat->
id(), gmlId );
212 void QgsGml::setFinished()
217 void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
219 if ( totalSteps < 0 )
229 void QgsGml::calculateExtentFromFeatures()
231 if ( mFeatures.empty() )
238 bool bboxInitialized =
false;
240 for (
int i = 0; i < mFeatures.size(); ++i )
242 currentFeature = mFeatures[i];
243 if ( !currentFeature )
247 currentGeometry = currentFeature->
geometry();
248 if ( !currentGeometry.
isNull() )
250 if ( !bboxInitialized )
253 bboxInitialized =
true;
278 const QString &geometryAttribute,
281 bool invertAxisOrientation )
283 , mTypeNameBA( mTypeName.toUtf8() )
284 , mTypeNamePtr( mTypeNameBA.constData() )
285 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
287 , mGeometryAttribute( geometryAttribute )
288 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
289 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
290 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
292 , mIsException( false )
293 , mTruncatedResponse( false )
295 , mFeatureTupleDepth( 0 )
297 , mCurrentWKB( nullptr, 0 )
298 , mBoundedByNullFound( false )
300 , mCoorMode( Coordinate )
302 , mAxisOrientationLogic( axisOrientationLogic )
303 , mInvertAxisOrientationRequest( invertAxisOrientation )
304 , mInvertAxisOrientation( invertAxisOrientation )
305 , mNumberReturned( -1 )
306 , mNumberMatched( -1 )
307 , mFoundUnhandledGeometryElement( false )
309 mThematicAttributes.clear();
310 for (
int i = 0; i < fields.
size(); i++ )
312 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
317 const int index = mTypeName.indexOf(
':' );
318 if ( index != -1 && index < mTypeName.length() )
320 mTypeName = mTypeName.mid( index + 1 );
321 mTypeNameBA = mTypeName.toUtf8();
322 mTypeNamePtr = mTypeNameBA.constData();
323 mTypeNameUTF8Len = strlen( mTypeNamePtr );
329 static QString stripNS(
const QString &
string )
331 const int index =
string.indexOf(
':' );
332 if ( index != -1 && index <
string.length() )
334 return string.mid( index + 1 );
341 const QMap< QString, QPair<QString, QString> > &mapFieldNameToSrcLayerNameFieldName,
343 bool invertAxisOrientation )
344 : mLayerProperties( layerProperties )
345 , mTypeNameUTF8Len( 0 )
347 , mGeometryAttributeUTF8Len( 0 )
349 , mIsException( false )
350 , mTruncatedResponse( false )
352 , mFeatureTupleDepth( 0 )
354 , mCurrentWKB( nullptr, 0 )
355 , mBoundedByNullFound( false )
357 , mCoorMode( Coordinate )
359 , mAxisOrientationLogic( axisOrientationLogic )
360 , mInvertAxisOrientationRequest( invertAxisOrientation )
361 , mInvertAxisOrientation( invertAxisOrientation )
362 , mNumberReturned( -1 )
363 , mNumberMatched( -1 )
364 , mFoundUnhandledGeometryElement( false )
366 mThematicAttributes.clear();
367 for (
int i = 0; i < fields.
size(); i++ )
369 const QMap< QString, QPair<QString, QString> >::const_iterator att_it = mapFieldNameToSrcLayerNameFieldName.constFind( fields.
at( i ).
name() );
370 if ( att_it != mapFieldNameToSrcLayerNameFieldName.constEnd() )
372 if ( mLayerProperties.size() == 1 )
373 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
375 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
378 bool alreadyFoundGeometry =
false;
379 for (
int i = 0; i < mLayerProperties.size(); i++ )
382 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
384 if ( alreadyFoundGeometry )
386 QgsDebugMsgLevel( QStringLiteral(
"Will ignore geometry field %1 from typename %2" ).
387 arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ), 2 );
388 mLayerProperties[i].mGeometryAttribute.clear();
390 alreadyFoundGeometry =
true;
392 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
395 if ( mLayerProperties.size() == 1 )
397 mTypeName = mLayerProperties[0].mName;
398 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
399 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
400 mGeometryAttributePtr = mGeometryAttributeBA.constData();
401 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
402 const int index = mTypeName.indexOf(
':' );
403 if ( index != -1 && index < mTypeName.length() )
405 mTypeName = mTypeName.mid( index + 1 );
407 mTypeNameBA = mTypeName.toUtf8();
408 mTypeNamePtr = mTypeNameBA.constData();
409 mTypeNameUTF8Len = strlen( mTypeNamePtr );
420 XML_ParserFree( mParser );
423 const auto constMFeatureList = mFeatureList;
426 delete featPair.first;
429 delete mCurrentFeature;
445 QByteArray data = pdata;
450 QString strData = mCodec->toUnicode( pdata );
451 data = strData.toUtf8();
454 if ( XML_Parse( mParser, data, data.size(), atEnd ) == XML_STATUS_ERROR )
456 const XML_Error errorCode = XML_GetErrorCode( mParser );
457 if ( !mCodec && errorCode == XML_ERROR_UNKNOWN_ENCODING )
461 QRegularExpression reEncoding( QStringLiteral(
"<?xml.*encoding=['\"]([^'\"]*)['\"].*?>" ),
462 QRegularExpression::CaseInsensitiveOption );
463 QRegularExpressionMatch match = reEncoding.match( pdata );
464 const QString encoding = match.hasMatch() ? match.captured( 1 ) : QString();
465 mCodec = !encoding.isEmpty() ? QTextCodec::codecForName( encoding.toLatin1() ) :
nullptr;
469 XML_ParserFree( mParser );
471 createParser( QByteArrayLiteral(
"UTF-8" ) );
477 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" )
478 .arg( XML_ErrorString( errorCode ) )
479 .arg( XML_GetCurrentLineNumber( mParser ) )
480 .arg( XML_GetCurrentColumnNumber( mParser ) );
490 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
491 mFeatureList.clear();
495 #define LOCALNAME_EQUALS(string_constant) \
496 ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 )
498 void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
500 const int elLen =
static_cast<int>( strlen( el ) );
502 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
503 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
504 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
505 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
509 if ( !mGMLNameSpaceURIPtr && pszSep )
523 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
526 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
527 parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
529 mGeometryString.append(
"<", 1 );
530 mGeometryString.append( pszLocalName, localNameLen );
531 mGeometryString.append(
" ", 1 );
532 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
534 const size_t nAttrLen = strlen( attrIter[0] );
537 if ( nAttrLen > GML32_NAMESPACE_LEN &&
538 attrIter[0][GML32_NAMESPACE_LEN] ==
'?' &&
541 mGeometryString.append(
"gml:" );
542 mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
544 else if ( nAttrLen > GML_NAMESPACE_LEN &&
545 attrIter[0][GML_NAMESPACE_LEN] ==
'?' &&
546 memcmp( attrIter[0],
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
548 mGeometryString.append(
"gml:" );
549 mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
553 mGeometryString.append( attrIter[0] );
555 mGeometryString.append(
"=\"", 2 );
556 mGeometryString.append( attrIter[1] );
557 mGeometryString.append(
"\" ", 2 );
560 mGeometryString.append(
">", 1 );
565 mParseModeStack.push( Coordinate );
566 mCoorMode = QgsGmlStreamingParser::Coordinate;
568 mCoordinateSeparator = readAttribute( QStringLiteral(
"cs" ), attr );
569 if ( mCoordinateSeparator.isEmpty() )
571 mCoordinateSeparator =
',';
573 mTupleSeparator = readAttribute( QStringLiteral(
"ts" ), attr );
574 if ( mTupleSeparator.isEmpty() )
576 mTupleSeparator =
' ';
582 mParseModeStack.push( QgsGmlStreamingParser::PosList );
583 mCoorMode = QgsGmlStreamingParser::PosList;
585 if ( elDimension == 0 )
587 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
589 const int dimension = srsDimension.toInt( &ok );
592 elDimension = dimension;
596 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
598 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
599 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
601 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
602 mFoundUnhandledGeometryElement =
false;
603 mGeometryString.clear();
608 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
610 mBoundedByNullFound =
false;
612 else if ( parseMode == BoundingBox &&
615 mParseModeStack.push( QgsGmlStreamingParser::Null );
616 mBoundedByNullFound =
true;
618 else if ( parseMode == BoundingBox &&
622 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
624 else if ( parseMode == Envelope &&
627 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
630 else if ( parseMode == Envelope &&
633 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
636 else if ( parseMode == None && !mTypeNamePtr &&
639 Q_ASSERT( !mCurrentFeature );
640 mCurrentFeature =
new QgsFeature( mFeatureCount );
642 const QgsAttributes attributes( mThematicAttributes.size() );
644 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
645 mCurrentFeatureId.clear();
647 else if ( parseMode == Tuple )
649 const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
650 const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
651 if ( iter != mMapTypeNameToProperties.constEnd() )
653 mFeatureTupleDepth = mParseDepth;
654 mCurrentTypename = currentTypename;
655 mGeometryAttribute.clear();
656 if ( mCurrentWKB.
size() == 0 )
658 mGeometryAttribute = iter.value().mGeometryAttribute;
660 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
661 mGeometryAttributePtr = mGeometryAttributeBA.constData();
662 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
663 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
665 if ( mGMLNameSpaceURI.isEmpty() )
684 id = readAttribute( mGMLNameSpaceURI +
NS_SEPARATOR +
"id", attr );
685 if ( !mCurrentFeatureId.isEmpty() )
686 mCurrentFeatureId +=
'|';
687 mCurrentFeatureId += id;
690 else if ( parseMode == None &&
691 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
692 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
694 Q_ASSERT( !mCurrentFeature );
695 mCurrentFeature =
new QgsFeature( mFeatureCount );
697 const QgsAttributes attributes( mThematicAttributes.size() );
699 mParseModeStack.push( QgsGmlStreamingParser::Feature );
700 mCurrentFeatureId = readAttribute( QStringLiteral(
"fid" ), attr );
701 if ( mCurrentFeatureId.isEmpty() )
706 if ( mGMLNameSpaceURI.isEmpty() )
709 if ( !mCurrentFeatureId.isEmpty() )
717 if ( !mCurrentFeatureId.isEmpty() )
725 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI +
NS_SEPARATOR +
"id", attr );
729 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
742 localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
745 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
750 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
752 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
757 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
759 mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
764 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
766 else if ( parseMode == FeatureTuple )
768 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
769 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
771 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
772 mAttributeName = mCurrentTypename +
'|' + localName;
776 else if ( parseMode == Feature )
778 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
779 if ( mThematicAttributes.contains( localName ) )
781 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
782 mAttributeName = localName;
789 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0 )
791 const QString name = readAttribute( QStringLiteral(
"name" ), attr );
792 if ( mThematicAttributes.contains( name ) )
794 const QString value = readAttribute( QStringLiteral(
"value" ), attr );
795 setAttribute( name, value );
802 QString
numberReturned = readAttribute( QStringLiteral(
"numberReturned" ), attr );
804 numberReturned = readAttribute( QStringLiteral(
"numberOfFeatures" ), attr );
808 mNumberReturned = -1;
810 const QString
numberMatched = readAttribute( QStringLiteral(
"numberMatched" ), attr );
818 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
823 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
828 mTruncatedResponse =
true;
830 else if ( !mGeometryString.empty() &&
846 mFoundUnhandledGeometryElement =
true;
849 if ( !mGeometryString.empty() )
852 if ( elDimension == 0 && isGeom )
856 const QString srsDimension = readAttribute( QStringLiteral(
"srsDimension" ), attr );
858 const int dimension = srsDimension.toInt( &ok );
861 elDimension = dimension;
865 if ( elDimension != 0 || mDimensionStack.isEmpty() )
867 mDimensionStack.push( elDimension );
871 mDimensionStack.push( mDimensionStack.back() );
874 if ( mEpsg == 0 && isGeom )
876 if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
878 QgsDebugMsg( QStringLiteral(
"error, could not get epsg id" ) );
889 void QgsGmlStreamingParser::endElement(
const XML_Char *el )
893 const int elLen =
static_cast<int>( strlen( el ) );
895 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
896 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
897 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
898 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
900 const int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
902 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
904 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
906 mParseModeStack.pop();
908 else if ( parseMode == PosList && isGMLNS &&
911 mDimension = lastDimension;
912 mParseModeStack.pop();
914 else if ( parseMode == AttributeTuple &&
915 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
917 mParseModeStack.pop();
919 setAttribute( mAttributeName, mStringCash );
921 else if ( parseMode == Attribute && QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
923 mParseModeStack.pop();
925 setAttribute( mAttributeName, mStringCash );
927 else if ( parseMode == Geometry &&
928 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
929 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
931 mParseModeStack.pop();
932 if ( mFoundUnhandledGeometryElement )
938 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
939 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
940 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
942 g.
fromWkb( pabyBuffer, wkbSize );
943 if ( mInvertAxisOrientation )
945 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
947 Q_ASSERT( mCurrentFeature );
951 mGeometryString.clear();
953 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
956 if ( mCurrentExtent.
isNull() &&
957 !mBoundedByNullFound &&
958 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
960 QgsDebugMsg( QStringLiteral(
"creation of bounding box failed" ) );
962 if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
963 !mCurrentFeature && mFeatureCount == 0 )
965 mLayerExtent = mCurrentExtent;
969 mParseModeStack.pop();
973 mParseModeStack.pop();
975 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
977 mParseModeStack.pop();
979 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
981 QList<QgsPointXY> points;
982 pointsFromPosListString( points, mStringCash, 2 );
983 if ( points.size() == 1 )
988 mParseModeStack.pop();
990 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
992 QList<QgsPointXY> points;
993 pointsFromPosListString( points, mStringCash, 2 );
994 if ( points.size() == 1 )
999 mParseModeStack.pop();
1001 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
1003 mParseModeStack.pop();
1004 mFeatureTupleDepth = 0;
1006 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
1008 ( parseMode == Feature &&
1009 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
1010 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
1012 Q_ASSERT( mCurrentFeature );
1015 if ( mCurrentWKB.
size() > 0 )
1022 else if ( !mCurrentExtent.
isEmpty() )
1031 mCurrentFeature =
nullptr;
1033 mParseModeStack.pop();
1037 QList<QgsPointXY> pointList;
1038 if ( pointsFromString( pointList, mStringCash ) != 0 )
1043 if ( pointList.isEmpty() )
1046 if ( parseMode == QgsGmlStreamingParser::Geometry )
1049 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
1062 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
1066 if ( !mCurrentWKBFragments.isEmpty() )
1068 mCurrentWKBFragments.last().push_back( wkbPtr );
1072 QgsDebugMsg( QStringLiteral(
"No wkb fragments" ) );
1081 QList<QgsPointXY> pointList;
1082 if ( pointsFromString( pointList, mStringCash ) != 0 )
1086 if ( parseMode == QgsGmlStreamingParser::Geometry )
1088 if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
1101 if ( getLineWKB( wkbPtr, pointList ) != 0 )
1105 if ( !mCurrentWKBFragments.isEmpty() )
1107 mCurrentWKBFragments.last().push_back( wkbPtr );
1111 QgsDebugMsg( QStringLiteral(
"no wkb fragments" ) );
1116 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1119 QList<QgsPointXY> pointList;
1120 if ( pointsFromString( pointList, mStringCash ) != 0 )
1126 if ( getRingWKB( wkbPtr, pointList ) != 0 )
1131 if ( !mCurrentWKBFragments.isEmpty() )
1133 mCurrentWKBFragments.last().push_back( wkbPtr );
1138 QgsDebugMsg( QStringLiteral(
"no wkb fragments" ) );
1141 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1149 if ( parseMode == Geometry )
1151 createPolygonFromFragments();
1154 else if ( parseMode == MultiPoint && isGMLNS &&
1158 mParseModeStack.pop();
1159 createMultiPointFromFragments();
1161 else if ( parseMode == MultiLine && isGMLNS &&
1165 mParseModeStack.pop();
1166 createMultiLineFromFragments();
1168 else if ( parseMode == MultiPolygon && isGMLNS &&
1172 mParseModeStack.pop();
1173 createMultiPolygonFromFragments();
1177 mParseModeStack.pop();
1179 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1181 mExceptionText = mStringCash;
1182 mParseModeStack.pop();
1185 if ( !mGeometryString.empty() )
1187 mGeometryString.append(
"</", 2 );
1188 mGeometryString.append( pszLocalName, localNameLen );
1189 mGeometryString.append(
">", 1 );
1194 void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1197 if ( mParseModeStack.isEmpty() )
1202 if ( !mGeometryString.empty() )
1204 mGeometryString.append( chars, len );
1207 const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1208 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1209 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1210 parseMode == QgsGmlStreamingParser::Coordinate ||
1211 parseMode == QgsGmlStreamingParser::PosList ||
1212 parseMode == QgsGmlStreamingParser::LowerCorner ||
1213 parseMode == QgsGmlStreamingParser::UpperCorner ||
1214 parseMode == QgsGmlStreamingParser::ExceptionText )
1216 mStringCash.append( QString::fromUtf8( chars, len ) );
1220 void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1223 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1224 bool conversionOk =
true;
1225 if ( att_it != mThematicAttributes.constEnd() )
1228 switch ( att_it.value().second.type() )
1230 case QVariant::Double:
1231 var = QVariant( value.toDouble( &conversionOk ) );
1234 var = QVariant( value.toInt( &conversionOk ) );
1236 case QVariant::LongLong:
1237 var = QVariant( value.toLongLong( &conversionOk ) );
1239 case QVariant::DateTime:
1240 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1243 var = QVariant( value );
1246 if ( ! conversionOk )
1250 Q_ASSERT( mCurrentFeature );
1251 mCurrentFeature->
setAttribute( att_it.value().first, var );
1255 int QgsGmlStreamingParser::readEpsgFromAttribute(
int &epsgNr,
const XML_Char **attr )
1260 if ( strcmp( attr[i],
"srsName" ) == 0 )
1262 const QString epsgString( attr[i + 1] );
1263 QString epsgNrString;
1264 bool bIsUrn =
false;
1265 if ( epsgString.startsWith( QLatin1String(
"http://www.opengis.net/gml/srs/" ) ) )
1267 epsgNrString = epsgString.section(
'#', 1, 1 );
1270 else if ( epsgString.startsWith( QLatin1String(
"urn:ogc:def:crs:EPSG:" ) ) ||
1271 epsgString.startsWith( QLatin1String(
"urn:x-ogc:def:crs:EPSG:" ) ) )
1274 epsgNrString = epsgString.split(
':' ).last();
1276 else if ( epsgString.startsWith( QLatin1String(
"http://www.opengis.net/def/crs/EPSG/" ) ) )
1279 epsgNrString = epsgString.split(
'/' ).last();
1283 epsgNrString = epsgString.section(
':', 1, 1 );
1286 const int eNr = epsgNrString.toInt( &conversionOk );
1287 if ( !conversionOk )
1292 mSrsName = epsgString;
1300 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1311 QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1316 if ( attributeName.compare( attr[i] ) == 0 )
1318 return QString::fromUtf8( attr[i + 1] );
1325 bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1327 QList<QgsPointXY> points;
1328 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1333 if ( points.size() < 2 )
1338 r.
set( points[0], points[1] );
1343 int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points,
const QString &coordString )
const
1346 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1347 QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
1349 const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1351 QStringList tuples_coordinates;
1353 bool conversionSuccess;
1355 QStringList::const_iterator tupleIterator;
1356 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1358 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1359 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
1361 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1363 if ( tuples_coordinates.size() < 2 )
1367 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1368 if ( !conversionSuccess )
1372 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1373 if ( !conversionSuccess )
1382 int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points,
const QString &coordString,
int dimension )
const
1385 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1386 QStringList coordinates = coordString.split(
' ', QString::SkipEmptyParts );
1388 const QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1391 if ( coordinates.size() % dimension != 0 )
1393 QgsDebugMsg( QStringLiteral(
"Wrong number of coordinates" ) );
1396 const int ncoor = coordinates.size() / dimension;
1397 for (
int i = 0; i < ncoor; i++ )
1399 bool conversionSuccess;
1400 const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1401 if ( !conversionSuccess )
1405 const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1406 if ( !conversionSuccess )
1415 int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points,
const QString &coordString )
const
1417 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1419 return pointsFromCoordinateString( points, coordString );
1421 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1423 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1428 int QgsGmlStreamingParser::getPointWKB(
QgsWkbPtr &wkbPtr,
const QgsPointXY &point )
const
1430 const int wkbSize = 1 +
sizeof( int ) + 2 *
sizeof(
double );
1431 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1439 int QgsGmlStreamingParser::getLineWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &lineCoordinates )
const
1441 const int wkbSize = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
1442 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1448 QList<QgsPointXY>::const_iterator iter;
1449 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1451 fillPtr << iter->x() << iter->y();
1457 int QgsGmlStreamingParser::getRingWKB(
QgsWkbPtr &wkbPtr,
const QList<QgsPointXY> &ringCoordinates )
const
1459 const int wkbSize =
sizeof( int ) + ringCoordinates.size() * 2 *
sizeof( double );
1460 wkbPtr =
QgsWkbPtr(
new unsigned char[wkbSize], wkbSize );
1464 fillPtr << ringCoordinates.size();
1466 QList<QgsPointXY>::const_iterator iter;
1467 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1469 fillPtr << iter->x() << iter->y();
1475 int QgsGmlStreamingParser::createMultiLineFromFragments()
1477 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1478 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1485 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1486 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1488 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1489 wkbPtr += wkbIt->
size();
1493 mCurrentWKBFragments.clear();
1498 int QgsGmlStreamingParser::createMultiPointFromFragments()
1500 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1501 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1506 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1507 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1509 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1510 wkbPtr += wkbIt->
size();
1514 mCurrentWKBFragments.clear();
1520 int QgsGmlStreamingParser::createPolygonFromFragments()
1522 const int size = 1 + 2 *
sizeof( int ) + totalWKBFragmentSize();
1523 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1528 QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1529 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1531 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1532 wkbPtr += wkbIt->
size();
1536 mCurrentWKBFragments.clear();
1541 int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1544 size += 1 + 2 *
sizeof( int );
1545 size += totalWKBFragmentSize();
1546 size += mCurrentWKBFragments.size() * ( 1 + 2 *
sizeof( int ) );
1548 mCurrentWKB =
QgsWkbPtr(
new unsigned char[size], size );
1554 QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
1556 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1561 QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
1562 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1564 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1565 wkbPtr += innerWkbIt->
size();
1566 delete[] *innerWkbIt;
1570 mCurrentWKBFragments.clear();
1575 int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1578 const auto constMCurrentWKBFragments = mCurrentWKBFragments;
1579 for (
const QList<QgsWkbPtr> &list : constMCurrentWKBFragments )
1581 const auto constList = list;
1590 void QgsGmlStreamingParser::createParser(
const QByteArray &encoding )
1592 Q_ASSERT( !mParser );
1594 mParser = XML_ParserCreateNS( encoding.isEmpty() ?
nullptr : encoding.data(),
NS_SEPARATOR );
1595 XML_SetUserData( mParser,
this );
1596 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
1597 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );