35#include <QNetworkReply>
36#include <QNetworkRequest>
37#include <QProgressDialog>
38#include <QRegularExpression>
45#include "moc_qgsgml.cpp"
47using namespace Qt::StringLiterals;
49using namespace nlohmann;
51#ifndef NS_SEPARATOR_DEFINED
52#define NS_SEPARATOR_DEFINED
53static const char NS_SEPARATOR =
'?';
56static const char *
GML_NAMESPACE =
"http://www.opengis.net/gml";
60 const QString &typeName,
61 const QString &geometryAttribute,
63 : mParser( typeName, geometryAttribute, fields )
64 , mTypeName( typeName )
66 const int index = mTypeName.indexOf(
':' );
67 if ( index != -1 && index < mTypeName.length() )
69 mTypeName = mTypeName.mid( index + 1 );
78 QNetworkRequest request( uri );
81 if ( !authcfg.isEmpty() )
86 tr(
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
93 else if ( !userName.isNull() || !password.isNull() )
95 request.setRawHeader(
"Authorization",
"Basic " + u
"%1:%2"_s.arg( userName, password ).toLatin1().toBase64() );
99 if ( !authcfg.isEmpty() )
103 reply->deleteLater();
105 tr(
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
113 connect( reply, &QNetworkReply::finished,
this, &QgsGml::setFinished );
114 connect( reply, &QNetworkReply::downloadProgress,
this, &QgsGml::handleProgressEvent );
117 QProgressDialog *progressDialog =
nullptr;
118 QWidget *mainWindow =
nullptr;
119 const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
120 for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
122 if ( ( *it )->objectName() ==
"QgisApp"_L1 )
130 progressDialog =
new QProgressDialog( tr(
"Loading GML data\n%1" ).arg( mTypeName ), tr(
"Abort" ), 0, 0, mainWindow );
131 progressDialog->setWindowModality( Qt::ApplicationModal );
134 connect( progressDialog, &QProgressDialog::canceled,
this, &QgsGml::setFinished );
135 progressDialog->show();
145 const QByteArray readData = reply->readAll();
146 if ( !readData.isEmpty() )
149 if ( !mParser.processData( readData, atEnd, errorMsg ) )
153 QCoreApplication::processEvents();
156 fillMapsFromParser();
158 const QNetworkReply::NetworkError replyError = reply->error();
159 const QString replyErrorString = reply->errorString();
162 delete progressDialog;
167 tr(
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
174 *wkbType = mParser.wkbType();
178 if ( mExtent.isEmpty() )
181 calculateExtentFromFeatures();
196 if ( !mParser.processData( data,
true , errorMsg ) )
199 fillMapsFromParser();
201 *wkbType = mParser.wkbType();
209void QgsGml::fillMapsFromParser()
212 const auto constFeatures = features;
216 const QString &gmlId = featPair.second;
217 mFeatures.insert( feat->
id(), feat );
218 if ( !gmlId.isEmpty() )
220 mIdMap.insert( feat->
id(), gmlId );
225void QgsGml::setFinished()
230void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
232 if ( totalSteps < 0 )
242void QgsGml::calculateExtentFromFeatures()
244 if ( mFeatures.empty() )
249 QgsFeature *currentFeature =
nullptr;
250 QgsGeometry currentGeometry;
251 bool bboxInitialized =
false;
253 for (
int i = 0; i < mFeatures.size(); ++i )
255 currentFeature = mFeatures[i];
256 if ( !currentFeature )
260 currentGeometry = currentFeature->
geometry();
261 if ( !currentGeometry.
isNull() )
263 if ( !bboxInitialized )
266 bboxInitialized =
true;
270 mExtent.combineExtentWith( currentGeometry.
boundingBox() );
279 if ( !mParser.srsName().isEmpty() )
291 const QString &geometryAttribute,
294 bool invertAxisOrientation )
295 : mTypeName( typeName )
296 , mTypeNameBA( mTypeName.toUtf8() )
297 , mTypeNamePtr( mTypeNameBA.constData() )
298 , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
299 , mWkbType(
Qgis::WkbType::Unknown )
300 , mGeometryAttribute( geometryAttribute )
301 , mGeometryAttributeBA( geometryAttribute.toUtf8() )
302 , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
303 , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
305 , mIsException( false )
306 , mTruncatedResponse( false )
308 , mFeatureTupleDepth( 0 )
310 , mCurrentWKB( nullptr, 0 )
311 , mBoundedByNullFound( false )
313 , mCoorMode( Coordinate )
314 , mAxisOrientationLogic( axisOrientationLogic )
315 , mInvertAxisOrientationRequest( invertAxisOrientation )
316 , mInvertAxisOrientation( invertAxisOrientation )
317 , mNumberReturned( -1 )
318 , mNumberMatched( -1 )
319 , mFoundUnhandledGeometryElement( false )
321 mThematicAttributes.clear();
322 for (
int i = 0; i < fields.
size(); i++ )
324 mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
329 const int index = mTypeName.indexOf(
':' );
330 if ( index != -1 && index < mTypeName.length() )
332 mTypeName = mTypeName.mid( index + 1 );
333 mTypeNameBA = mTypeName.toUtf8();
334 mTypeNamePtr = mTypeNameBA.constData();
335 mTypeNameUTF8Len = strlen( mTypeNamePtr );
341static QString stripNS(
const QString &
string )
343 const int index =
string.indexOf(
':' );
344 if ( index != -1 && index <
string.length() )
346 return string.mid( index + 1 );
353 const QMap< QString, QPair<QString, QString> > &fieldNameToSrcLayerNameFieldNameMap,
355 bool invertAxisOrientation )
356 : mLayerProperties( layerProperties )
357 , mTypeNameUTF8Len( 0 )
358 , mWkbType(
Qgis::WkbType::Unknown )
359 , mGeometryAttributeUTF8Len( 0 )
361 , mIsException( false )
362 , mTruncatedResponse( false )
364 , mFeatureTupleDepth( 0 )
366 , mCurrentWKB( nullptr, 0 )
367 , mBoundedByNullFound( false )
369 , mCoorMode( Coordinate )
370 , mAxisOrientationLogic( axisOrientationLogic )
371 , mInvertAxisOrientationRequest( invertAxisOrientation )
372 , mInvertAxisOrientation( invertAxisOrientation )
373 , mNumberReturned( -1 )
374 , mNumberMatched( -1 )
375 , mFoundUnhandledGeometryElement( false )
377 mThematicAttributes.clear();
378 for (
int i = 0; i < fields.
size(); i++ )
380 const QMap< QString, QPair<QString, QString> >::const_iterator att_it = fieldNameToSrcLayerNameFieldNameMap.constFind( fields.
at( i ).
name() );
381 if ( att_it != fieldNameToSrcLayerNameFieldNameMap.constEnd() )
383 if ( mLayerProperties.size() == 1 )
384 mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
386 mThematicAttributes.insert( stripNS( att_it.value().first ) +
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
389 bool alreadyFoundGeometry =
false;
390 for (
int i = 0; i < mLayerProperties.size(); i++ )
393 if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
395 if ( alreadyFoundGeometry )
398 arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ), 2 );
399 mLayerProperties[i].mGeometryAttribute.clear();
401 alreadyFoundGeometry =
true;
403 mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
406 if ( mLayerProperties.size() == 1 )
408 mTypeName = mLayerProperties[0].mName;
409 mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
410 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
411 mGeometryAttributePtr = mGeometryAttributeBA.constData();
412 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
413 const int index = mTypeName.indexOf(
':' );
414 if ( index != -1 && index < mTypeName.length() )
416 mTypeName = mTypeName.mid( index + 1 );
418 mTypeNameBA = mTypeName.toUtf8();
419 mTypeNamePtr = mTypeNameBA.constData();
420 mTypeNameUTF8Len = strlen( mTypeNamePtr );
430 const QMap<QString, QPair<QString, bool>> &fieldNameToXPathMapAndIsNestedContent,
431 const QMap<QString, QString> &mapNamespacePrefixToURI )
433 for (
auto iter = fieldNameToXPathMapAndIsNestedContent.constBegin(); iter != fieldNameToXPathMapAndIsNestedContent.constEnd(); ++iter )
435 mMapXPathToFieldNameAndIsNestedContent[iter.value().first] = QPair<QString, bool>( iter.key(), iter.value().second );
437 for (
auto iter = mapNamespacePrefixToURI.constBegin(); iter != mapNamespacePrefixToURI.constEnd(); ++iter )
438 mMapNamespaceURIToNamespacePrefix[iter.value()] = iter.key();
444 XML_ParserFree( mParser );
447 const auto constMFeatureList = mFeatureList;
450 delete featPair.first;
453 delete mCurrentFeature;
469 QByteArray data = pdata;
474 QString strData = mCodec->toUnicode( pdata );
475 data = strData.toUtf8();
478 if ( XML_Parse( mParser, data, data.size(), atEnd ) == XML_STATUS_ERROR )
480 const XML_Error errorCode = XML_GetErrorCode( mParser );
481 if ( !mCodec && errorCode == XML_ERROR_UNKNOWN_ENCODING )
485 const thread_local QRegularExpression reEncoding( u
"<?xml.*encoding=['\"]([^'\"]*)['\"].*?>"_s,
486 QRegularExpression::CaseInsensitiveOption );
487 QRegularExpressionMatch match = reEncoding.match( pdata );
488 const QString encoding = match.hasMatch() ? match.captured( 1 ) : QString();
489 mCodec = !encoding.isEmpty() ? QTextCodec::codecForName( encoding.toLatin1() ) :
nullptr;
493 XML_ParserFree( mParser );
495 createParser( QByteArrayLiteral(
"UTF-8" ) );
501 errorMsg = QObject::tr(
"Error: %1 on line %2, column %3" )
502 .arg( XML_ErrorString( errorCode ) )
503 .arg( XML_GetCurrentLineNumber( mParser ) )
504 .arg( XML_GetCurrentColumnNumber( mParser ) );
514 QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
515 mFeatureList.clear();
523static json jsonFromString(
const QString &s )
528 if ( s.indexOf(
'.' ) >= 0 || s.indexOf(
'e' ) >= 0 )
530 const auto doubleVal = s.toDouble( &conversionOk );
533 return json( doubleVal );
538 else if ( !s.isEmpty() && s[0] !=
'0' )
540 const auto longlongVal = s.toLongLong( &conversionOk );
543 return json( longlongVal );
547 return json( s.toStdString() );
550#define LOCALNAME_EQUALS(string_constant) \
551 ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 )
553void QgsGmlStreamingParser::startElement(
const XML_Char *el,
const XML_Char **attr )
555 const int elLen =
static_cast<int>( strlen( el ) );
556 const char *pszSep = strchr( el, NS_SEPARATOR );
557 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
558 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
559 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
560 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
564 if ( !mGMLNameSpaceURIPtr && pszSep )
578 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
581 if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
582 parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
584 mGeometryString.append(
"<", 1 );
585 mGeometryString.append( pszLocalName, localNameLen );
586 mGeometryString.append(
" ", 1 );
587 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
589 const size_t nAttrLen = strlen( attrIter[0] );
592 if ( nAttrLen > GML32_NAMESPACE_LEN &&
593 attrIter[0][GML32_NAMESPACE_LEN] ==
'?' &&
596 mGeometryString.append(
"gml:" );
597 mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
599 else if ( nAttrLen > GML_NAMESPACE_LEN &&
600 attrIter[0][GML_NAMESPACE_LEN] ==
'?' &&
601 memcmp( attrIter[0],
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
603 mGeometryString.append(
"gml:" );
604 mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
608 mGeometryString.append( attrIter[0] );
610 mGeometryString.append(
"=\"", 2 );
611 mGeometryString.append( attrIter[1] );
612 mGeometryString.append(
"\" ", 2 );
615 mGeometryString.append(
">", 1 );
618 if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
620 mParseModeStack.push( Coordinate );
621 mCoorMode = QgsGmlStreamingParser::Coordinate;
623 mCoordinateSeparator = readAttribute( u
"cs"_s, attr );
624 if ( mCoordinateSeparator.isEmpty() )
626 mCoordinateSeparator =
',';
628 mTupleSeparator = readAttribute( u
"ts"_s, attr );
629 if ( mTupleSeparator.isEmpty() )
631 mTupleSeparator =
' ';
634 else if ( !mAttributeValIsNested && isGMLNS &&
637 mParseModeStack.push( QgsGmlStreamingParser::PosList );
638 if ( mCoorMode == QgsGmlStreamingParser::PosList )
640 if ( !mStringCash.isEmpty() )
642 mStringCash.append(
' '_L1 );
649 mCoorMode = QgsGmlStreamingParser::PosList;
650 elDimension = readSrsNameAndDimensionAttributes( attr );
652 else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
654 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
655 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
657 mParseModeStack.push( QgsGmlStreamingParser::Geometry );
658 mFoundUnhandledGeometryElement =
false;
659 mGeometryString.clear();
663 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
665 mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
667 mBoundedByNullFound =
false;
669 else if ( parseMode == BoundingBox &&
672 mParseModeStack.push( QgsGmlStreamingParser::Null );
673 mBoundedByNullFound =
true;
675 else if ( parseMode == BoundingBox &&
679 mParseModeStack.push( QgsGmlStreamingParser::Envelope );
681 else if ( parseMode == Envelope &&
684 mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
687 else if ( parseMode == Envelope &&
690 mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
693 else if ( parseMode == None && !mTypeNamePtr &&
696 Q_ASSERT( !mCurrentFeature );
697 mCurrentFeature =
new QgsFeature( mFeatureCount );
699 const QgsAttributes attributes( mThematicAttributes.size() );
701 mParseModeStack.push( QgsGmlStreamingParser::Tuple );
702 mCurrentFeatureId.clear();
704 else if ( parseMode == Tuple )
706 const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
707 const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
708 if ( iter != mMapTypeNameToProperties.constEnd() )
710 mFeatureTupleDepth = mParseDepth;
711 mCurrentTypename = currentTypename;
712 mGeometryAttribute.clear();
713 if ( mCurrentWKB.size() == 0 )
715 mGeometryAttribute = iter.value().mGeometryAttribute;
717 mGeometryAttributeBA = mGeometryAttribute.toUtf8();
718 mGeometryAttributePtr = mGeometryAttributeBA.constData();
719 mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
720 mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
722 if ( mGMLNameSpaceURI.isEmpty() )
724 id = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
732 id = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
741 id = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
742 if ( !mCurrentFeatureId.isEmpty() )
743 mCurrentFeatureId +=
'|';
744 mCurrentFeatureId += id;
747 else if ( parseMode == None &&
748 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
750 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
752 Q_ASSERT( !mCurrentFeature );
753 mCurrentFeature =
new QgsFeature( mFeatureCount );
755 const QgsAttributes attributes( mThematicAttributes.size() );
757 mParseModeStack.push( QgsGmlStreamingParser::Feature );
758 mCurrentXPathWithinFeature.clear();
759 mCurrentFeatureId = readAttribute( u
"fid"_s, attr );
760 if ( mCurrentFeatureId.isEmpty() )
765 if ( mGMLNameSpaceURI.isEmpty() )
767 mCurrentFeatureId = readAttribute( QString(
GML_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
768 if ( !mCurrentFeatureId.isEmpty() )
775 mCurrentFeatureId = readAttribute( QString(
GML32_NAMESPACE ) + NS_SEPARATOR +
"id", attr );
776 if ( !mCurrentFeatureId.isEmpty() )
784 mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR +
"id", attr );
788 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"Box" ) )
792 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
796 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"LineString" ) )
800 else if ( !mAttributeValIsNested && isGMLNS &&
801 localNameLen ==
static_cast<int>( strlen(
"Polygon" ) ) && memcmp( pszLocalName,
"Polygon", localNameLen ) == 0 )
804 mCurrentWKBFragments.push_back( QList<QByteArray>() );
806 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"MultiPoint" ) )
809 mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
811 mCurrentWKBFragments.push_back( QList<QByteArray>() );
816 mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
818 mCurrentWKBFragments.push_back( QList<QByteArray>() );
823 mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
825 else if ( parseMode == FeatureTuple )
827 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
828 if ( mThematicAttributes.contains( mCurrentTypename +
'|' + localName ) )
830 mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
831 mAttributeName = mCurrentTypename +
'|' + localName;
835 else if ( parseMode == Feature )
837 const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
838 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
840 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
841 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
842 if ( !mCurrentXPathWithinFeature.isEmpty() )
843 mCurrentXPathWithinFeature.append(
'/' );
844 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
846 mCurrentXPathWithinFeature.append( *nsIter );
847 mCurrentXPathWithinFeature.append(
':' );
849 mCurrentXPathWithinFeature.append( localName );
850 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( mCurrentXPathWithinFeature );
851 mAttributeValIsNested =
false;
852 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
854 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
855 mAttributeDepth = mParseDepth;
856 mAttributeName = xpathIter->first;
857 mAttributeValIsNested = xpathIter->second;
858 if ( mAttributeValIsNested )
860 mAttributeJson = json::object();
861 mAttributeJsonCurrentStack.clear();
862 mAttributeJsonCurrentStack.push( &mAttributeJson );
867 else if ( mThematicAttributes.contains( localName ) )
869 mParseModeStack.push( QgsGmlStreamingParser::Attribute );
870 mAttributeDepth = mParseDepth;
871 mAttributeName = localName;
878 if ( localName.compare(
"attribute"_L1, Qt::CaseInsensitive ) == 0 )
880 const QString name = readAttribute( u
"name"_s, attr );
881 if ( mThematicAttributes.contains( name ) )
883 const QString value = readAttribute( u
"value"_s, attr );
884 setAttribute( name, value );
889 else if ( parseMode == Attribute && mAttributeValIsNested )
891 const std::string localName( pszLocalName, localNameLen );
892 const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
893 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
894 const std::string nodeName = nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() ? ( *nsIter ).toStdString() +
':' + localName : localName;
896 addStringContentToJson();
898 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
899 auto iter = jsonParent.find( nodeName );
900 if ( iter != jsonParent.end() )
902 if ( iter->type() != json::value_t::array )
904 auto array = json::array();
905 array.emplace_back( std::move( *iter ) );
908 iter->push_back( json::object() );
909 mAttributeJsonCurrentStack.push( &( iter->back() ) );
913 auto res = jsonParent.emplace( nodeName, json::object() );
917 nlohmann::json *ptr = &( *( res.first ) );
919 mAttributeJsonCurrentStack.push( ptr );
924 QString
numberReturned = readAttribute( u
"numberReturned"_s, attr );
930 mNumberReturned = -1;
932 const QString
numberMatched = readAttribute( u
"numberMatched"_s, attr );
940 mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
945 mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
950 mTruncatedResponse =
true;
952 else if ( !mGeometryString.empty() &&
968 mFoundUnhandledGeometryElement =
true;
972 if ( !mParseModeStack.isEmpty() &&
973 ( mParseModeStack.back() == Feature ||
974 mParseModeStack.back() == Attribute ) &&
975 !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
977 for (
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
979 const char *questionMark = strchr( attrIter[0],
'?' );
983 const QString nsURI( QString::fromUtf8( attrIter[0],
static_cast<int>( questionMark - attrIter[0] ) ) );
984 const QString localName( QString::fromUtf8( questionMark + 1 ) );
985 const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
986 if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
988 key.append( *nsIter );
991 key.append( localName );
995 const QString localName( QString::fromUtf8( attrIter[0] ) );
996 key.append( localName );
999 if ( mAttributeValIsNested && mParseModeStack.back() == Attribute )
1001 mAttributeJsonCurrentStack.top()->emplace(
1003 jsonFromString( QString::fromUtf8( attrIter[1] ) ) );
1007 QString xpath( mCurrentXPathWithinFeature );
1008 if ( !xpath.isEmpty() )
1009 xpath.append(
'/' );
1010 xpath.append( key );
1011 const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( xpath );
1012 if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
1014 setAttribute( xpathIter->first, QString::fromUtf8( attrIter[1] ) );
1020 if ( !mGeometryString.empty() )
1025 elDimension = readSrsNameAndDimensionAttributes( attr );
1028 if ( elDimension != 0 || mDimensionStack.isEmpty() )
1030 mDimensionStack.push( elDimension );
1034 mDimensionStack.push( mDimensionStack.back() );
1040void QgsGmlStreamingParser::endElement(
const XML_Char *el )
1044 const int elLen =
static_cast<int>( strlen( el ) );
1045 const char *pszSep = strchr( el, NS_SEPARATOR );
1046 const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
1047 const int nsLen = ( pszSep ) ? (
int )( pszSep - el ) : 0;
1048 const int localNameLen = ( pszSep ) ? (
int )( elLen - nsLen ) - 1 : elLen;
1049 const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
1051 const int lastDimension = mDimensionStack.isEmpty() ? 2 : mDimensionStack.pop();
1053 const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
1055 if ( parseMode == Feature || ( parseMode == Attribute && mAttributeDepth == mParseDepth ) )
1057 if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
1059 const auto nPos = mCurrentXPathWithinFeature.lastIndexOf(
'/' );
1061 mCurrentXPathWithinFeature.clear();
1063 mCurrentXPathWithinFeature.resize( nPos );
1067 if ( parseMode == Attribute && mAttributeValIsNested )
1069 if ( !mStringCash.isEmpty() )
1071 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1072 if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
1074 jsonParent = jsonFromString( mStringCash );
1076 else if ( jsonParent.type() == json::value_t::object )
1078 addStringContentToJson();
1080 mStringCash.clear();
1083 mAttributeJsonCurrentStack.pop();
1086 if ( parseMode == Coordinate && isGMLNS &&
LOCALNAME_EQUALS(
"coordinates" ) )
1088 mParseModeStack.pop();
1090 else if ( parseMode == PosList && isGMLNS &&
1093 mDimension = lastDimension;
1094 mParseModeStack.pop();
1096 else if ( parseMode == AttributeTuple &&
1097 mCurrentTypename +
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName )
1099 mParseModeStack.pop();
1101 setAttribute( mAttributeName, mStringCash );
1103 else if ( parseMode == Attribute && mAttributeDepth == mParseDepth )
1105 mParseModeStack.pop();
1108 if ( mAttributeValIsNested )
1110 mAttributeValIsNested =
false;
1111 auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
1112 if ( iter == mMapFieldNameToJSONContent.end() )
1114 mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
1118 QString &str = iter.value();
1119 if ( str[0] ==
'[' && str.back() ==
']' )
1125 str.insert( 0,
'[' );
1128 str.append( QString::fromStdString( mAttributeJson.dump() ) );
1134 setAttribute( mAttributeName, mStringCash );
1137 else if ( parseMode == Geometry &&
1138 localNameLen ==
static_cast<int>( mGeometryAttributeUTF8Len ) &&
1139 memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
1141 mParseModeStack.pop();
1142 if ( mFoundUnhandledGeometryElement )
1148 const int wkbSize = OGR_G_WkbSize( hGeom.get() );
1149 unsigned char *pabyBuffer =
new unsigned char[ wkbSize ];
1150 OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
1152 g.
fromWkb( pabyBuffer, wkbSize );
1153 if ( mInvertAxisOrientation )
1155 g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
1157 Q_ASSERT( mCurrentFeature );
1158 mCurrentFeature->setGeometry( g );
1161 mGeometryString.clear();
1163 else if ( parseMode == BoundingBox && isGMLNS &&
LOCALNAME_EQUALS(
"boundedBy" ) )
1166 if ( mCurrentExtent.isNull() &&
1167 !mBoundedByNullFound &&
1168 !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
1172 if ( !mCurrentExtent.isNull() && mLayerExtent.isNull() &&
1173 !mCurrentFeature && mFeatureCount == 0 )
1175 mLayerExtent = mCurrentExtent;
1176 mCurrentExtent = QgsRectangle();
1179 mParseModeStack.pop();
1183 mParseModeStack.pop();
1185 else if ( parseMode == Envelope && isGMLNS &&
LOCALNAME_EQUALS(
"Envelope" ) )
1187 mParseModeStack.pop();
1189 else if ( parseMode == LowerCorner && isGMLNS &&
LOCALNAME_EQUALS(
"lowerCorner" ) )
1191 QList<QgsPoint> points;
1192 pointsFromPosListString( points, mStringCash, 2 );
1193 if ( points.size() == 1 )
1195 mCurrentExtent.setXMinimum( points[0].x() );
1196 mCurrentExtent.setYMinimum( points[0].y() );
1198 mParseModeStack.pop();
1200 else if ( parseMode == UpperCorner && isGMLNS &&
LOCALNAME_EQUALS(
"upperCorner" ) )
1202 QList<QgsPoint> points;
1203 pointsFromPosListString( points, mStringCash, 2 );
1204 if ( points.size() == 1 )
1206 mCurrentExtent.setXMaximum( points[0].x() );
1207 mCurrentExtent.setYMaximum( points[0].y() );
1209 mParseModeStack.pop();
1211 else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
1213 mParseModeStack.pop();
1214 mFeatureTupleDepth = 0;
1216 else if ( ( parseMode == Tuple && !mTypeNamePtr &&
1218 ( parseMode == Feature &&
1219 localNameLen ==
static_cast<int>( mTypeNameUTF8Len ) &&
1220 memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
1222 Q_ASSERT( mCurrentFeature );
1223 if ( !mCurrentFeature->hasGeometry() )
1225 if ( mCurrentWKB.size() > 0 )
1229 mCurrentFeature->setGeometry( g );
1230 mCurrentWKB = QByteArray();
1232 else if ( !mCurrentExtent.isEmpty() )
1237 mCurrentFeature->setValid(
true );
1239 for (
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
1241 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
1242 const int attrIndex = att_it.value().first;
1243 mCurrentFeature->setAttribute( attrIndex, iter.value() );
1245 mMapFieldNameToJSONContent.clear();
1249 mCurrentFeature =
nullptr;
1251 mParseModeStack.pop();
1253 else if ( !mAttributeValIsNested && isGMLNS &&
LOCALNAME_EQUALS(
"Point" ) )
1255 QList<QgsPoint> pointList;
1257 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1261 mStringCash.clear();
1262 mDimension = dimension;
1264 if ( pointList.isEmpty() )
1267 if ( parseMode == QgsGmlStreamingParser::Geometry )
1270 if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ), dimension ) != 0 )
1284 if ( getPointWKB( wkbPtr, *( pointList.constBegin() ), dimension ) != 0 )
1288 if ( !mCurrentWKBFragments.isEmpty() )
1290 mCurrentWKBFragments.last().push_back( wkbPtr );
1298 else if ( !mAttributeValIsNested &&
1303 QList<QgsPoint> pointList;
1305 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1309 mStringCash.clear();
1310 mDimension = dimension;
1312 if ( parseMode == QgsGmlStreamingParser::Geometry )
1314 if ( getLineWKB( mCurrentWKB, pointList, dimension ) != 0 )
1323 else if ( dimension > 2 )
1327 mDimension = dimension;
1332 if ( getLineWKB( wkbPtr, pointList, dimension ) != 0 )
1336 mDimension = dimension;
1337 if ( !mCurrentWKBFragments.isEmpty() )
1339 mCurrentWKBFragments.last().push_back( wkbPtr );
1347 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
1350 QList<QgsPoint> pointList;
1352 if ( pointsFromString( pointList, mStringCash, &dimension ) != 0 )
1356 mStringCash.clear();
1357 mDimension = dimension;
1360 if ( getRingWKB( wkbPtr, pointList, dimension ) != 0 )
1365 if ( !mCurrentWKBFragments.isEmpty() )
1367 mCurrentWKBFragments.last().push_back( wkbPtr );
1374 else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
1382 if ( parseMode == Geometry )
1384 createPolygonFromFragments();
1387 else if ( parseMode == MultiPoint && isGMLNS &&
1391 mParseModeStack.pop();
1392 createMultiPointFromFragments();
1394 else if ( parseMode == MultiLine && isGMLNS &&
1398 mParseModeStack.pop();
1399 createMultiLineFromFragments();
1401 else if ( parseMode == MultiPolygon && isGMLNS &&
1405 mParseModeStack.pop();
1406 createMultiPolygonFromFragments();
1410 mParseModeStack.pop();
1412 else if ( parseMode == ExceptionText &&
LOCALNAME_EQUALS(
"ExceptionText" ) )
1414 mExceptionText = mStringCash;
1415 mParseModeStack.pop();
1418 if ( !mGeometryString.empty() )
1420 mGeometryString.append(
"</", 2 );
1421 mGeometryString.append( pszLocalName, localNameLen );
1422 mGeometryString.append(
">", 1 );
1427void QgsGmlStreamingParser::characters(
const XML_Char *chars,
int len )
1430 if ( mParseModeStack.isEmpty() )
1435 if ( !mGeometryString.empty() )
1437 mGeometryString.append( chars, len );
1440 const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
1441 if ( parseMode == QgsGmlStreamingParser::Attribute ||
1442 parseMode == QgsGmlStreamingParser::AttributeTuple ||
1443 parseMode == QgsGmlStreamingParser::Coordinate ||
1444 parseMode == QgsGmlStreamingParser::PosList ||
1445 parseMode == QgsGmlStreamingParser::LowerCorner ||
1446 parseMode == QgsGmlStreamingParser::UpperCorner ||
1447 parseMode == QgsGmlStreamingParser::ExceptionText )
1449 mStringCash.append( QString::fromUtf8( chars, len ) );
1453void QgsGmlStreamingParser::addStringContentToJson()
1455 const QString s( mStringCash.trimmed() );
1458 auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
1459 auto textIter = jsonParent.find(
"_text" );
1460 if ( textIter != jsonParent.end() )
1462 if ( textIter->type() != json::value_t::array )
1464 auto array = json::array();
1465 array.emplace_back( std::move( *textIter ) );
1468 textIter->emplace_back( jsonFromString( s ) );
1472 jsonParent.emplace(
"_text", jsonFromString( s ) );
1475 mStringCash.clear();
1478void QgsGmlStreamingParser::setAttribute(
const QString &name,
const QString &value )
1481 const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
1482 bool conversionOk =
true;
1483 if ( att_it != mThematicAttributes.constEnd() )
1486 switch ( att_it.value().second.type() )
1488 case QMetaType::Type::Double:
1489 var = QVariant( value.toDouble( &conversionOk ) );
1491 case QMetaType::Type::Int:
1492 var = QVariant( value.toInt( &conversionOk ) );
1494 case QMetaType::Type::LongLong:
1495 var = QVariant( value.toLongLong( &conversionOk ) );
1497 case QMetaType::Type::QDateTime:
1498 var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
1501 var = QVariant( value );
1504 if ( ! conversionOk )
1508 Q_ASSERT( mCurrentFeature );
1509 mCurrentFeature->setAttribute( att_it.value().first, var );
1513int QgsGmlStreamingParser::readSrsNameAndDimensionAttributes(
const XML_Char **attr )
1515 int elDimension = 0;
1516 for (
int i = 0; attr[i] && attr[i + 1]; i += 2 )
1518 if ( strcmp( attr[i],
"srsName" ) == 0 )
1520 const QString
srsName( attr[i + 1] );
1521 if ( mSrsName.isEmpty() )
1538 mInvertAxisOrientation = !mInvertAxisOrientationRequest;
1542 if ( elDimension == 0 )
1543 elDimension = mDimensionForCurSrsName;
1547 else if (
srsName == mSrsName && elDimension == 0 )
1549 elDimension = mDimensionForCurSrsName;
1552 else if ( strcmp( attr[i],
"srsDimension" ) == 0 )
1554 const QString srsDimension( attr[i + 1] );
1556 const int dimension = srsDimension.toInt( &ok );
1559 elDimension = dimension;
1567QString QgsGmlStreamingParser::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const
1572 if ( attributeName.compare( attr[i] ) == 0 )
1574 return QString::fromUtf8( attr[i + 1] );
1581bool QgsGmlStreamingParser::createBBoxFromCoordinateString(
QgsRectangle &r,
const QString &coordString )
const
1583 QList<QgsPoint> points;
1584 if ( pointsFromCoordinateString( points, coordString ) != 0 )
1589 if ( points.size() < 2 )
1594 r.
set( points[0], points[1] );
1599int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPoint> &points,
const QString &coordString,
int *dimension )
const
1602 const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
1603 QStringList tuples_coordinates;
1605 bool conversionSuccess;
1610 QStringList::const_iterator tupleIterator;
1611 for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
1613 tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
1616 *dimension = std::max( *dimension,
static_cast<int>( tuples_coordinates.size() ) );
1618 if ( tuples_coordinates.size() < 2 )
1622 x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
1623 if ( !conversionSuccess )
1627 y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
1628 if ( !conversionSuccess )
1632 if ( tuples_coordinates.size() > 2 )
1634 z = tuples_coordinates.at( 2 ).toDouble( &conversionSuccess );
1635 if ( !conversionSuccess )
1642 z = std::numeric_limits<double>::quiet_NaN();
1644 points.push_back( ( mInvertAxisOrientation ) ? QgsPoint( y, x, z ) : QgsPoint( x, y, z ) );
1647 if ( dimension && *dimension == 0 )
1655int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPoint> &points,
const QString &coordString,
int dimension )
const
1658 const QStringList coordinates = coordString.split(
' ', Qt::SkipEmptyParts );
1660 if ( coordinates.size() % dimension != 0 )
1665 const int ncoor = coordinates.size() / dimension;
1666 for (
int i = 0; i < ncoor; i++ )
1668 bool conversionSuccess;
1669 const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
1670 if ( !conversionSuccess )
1674 const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
1675 if ( !conversionSuccess )
1679 double z = std::numeric_limits<double>::quiet_NaN();
1680 if ( dimension > 2 )
1682 z = coordinates.value( i * dimension + 2 ).toDouble( &conversionSuccess );
1683 if ( !conversionSuccess )
1688 points.append( mInvertAxisOrientation ? QgsPoint( y, x, z ) : QgsPoint( x, y, z ) );
1693int QgsGmlStreamingParser::pointsFromString( QList<QgsPoint> &points,
const QString &coordString,
int *dimension )
const
1695 if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
1697 return pointsFromCoordinateString( points, coordString, dimension );
1699 else if ( mCoorMode == QgsGmlStreamingParser::PosList )
1703 *dimension = mDimension ? mDimension : 2;
1705 return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
1710int QgsGmlStreamingParser::getPointWKB( QByteArray &wkbPtr,
const QgsPoint &point,
int dimension )
const
1712 const int wkbSize = 1 +
static_cast<int>(
sizeof( int ) ) + dimension *
static_cast<int>(
sizeof(
double ) );
1713 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1715 QgsWkbPtr fillPtr( wkbPtr );
1717 if ( dimension > 2 )
1719 fillPtr << point.
z();
1725int QgsGmlStreamingParser::getLineWKB( QByteArray &wkbPtr,
const QList<QgsPoint> &lineCoordinates,
int dimension )
const
1727 const int wkbSize = 1 + 2 *
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( lineCoordinates.size() ) * dimension *
static_cast<int>(
sizeof( double ) );
1728 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1730 QgsWkbPtr fillPtr( wkbPtr );
1734 QList<QgsPoint>::const_iterator iter;
1735 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
1737 fillPtr << iter->x() << iter->y();
1738 if ( dimension > 2 )
1740 fillPtr << iter->z();
1747int QgsGmlStreamingParser::getRingWKB( QByteArray &wkbPtr,
const QList<QgsPoint> &ringCoordinates,
int dimension )
const
1749 const int wkbSize =
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( ringCoordinates.size() ) * dimension *
static_cast<int>(
sizeof( double ) );
1750 wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
1752 QgsWkbPtr fillPtr( wkbPtr );
1754 fillPtr << ringCoordinates.size();
1756 QList<QgsPoint>::const_iterator iter;
1757 for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
1759 fillPtr << iter->x() << iter->y();
1760 if ( dimension > 2 )
1762 fillPtr << iter->z();
1769int QgsGmlStreamingParser::createMultiLineFromFragments()
1771 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1772 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1774 QgsWkbPtr wkbPtr( mCurrentWKB );
1779 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1780 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1782 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1783 wkbPtr += wkbIt->size();
1786 mCurrentWKBFragments.clear();
1791int QgsGmlStreamingParser::createMultiPointFromFragments()
1793 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1794 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1796 QgsWkbPtr wkbPtr( mCurrentWKB );
1799 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1800 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1802 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1803 wkbPtr += wkbIt->size();
1806 mCurrentWKBFragments.clear();
1812int QgsGmlStreamingParser::createPolygonFromFragments()
1814 const int size = 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) ) + totalWKBFragmentSize();
1815 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1817 QgsWkbPtr wkbPtr( mCurrentWKB );
1820 auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
1821 for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
1823 memcpy( wkbPtr, *wkbIt, wkbIt->size() );
1824 wkbPtr += wkbIt->size();
1827 mCurrentWKBFragments.clear();
1832int QgsGmlStreamingParser::createMultiPolygonFromFragments()
1835 size += 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof(
int ) );
1836 size += totalWKBFragmentSize();
1837 size += mCurrentWKBFragments.size() * ( 1 + ( mDimension > 2 ? mDimension : 2 ) *
static_cast<int>(
sizeof( int ) ) );
1839 mCurrentWKB = QByteArray( size, Qt::Uninitialized );
1841 QgsWkbPtr wkbPtr( mCurrentWKB );
1845 auto outerWkbIt = mCurrentWKBFragments.constBegin();
1847 for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
1852 auto innerWkbIt = outerWkbIt->constBegin();
1853 for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
1855 memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
1856 wkbPtr += innerWkbIt->size();
1860 mCurrentWKBFragments.clear();
1865int QgsGmlStreamingParser::totalWKBFragmentSize()
const
1868 for (
const QList<QByteArray> &list : std::as_const( mCurrentWKBFragments ) )
1870 for (
const QByteArray &i : list )
1878void QgsGmlStreamingParser::createParser(
const QByteArray &encoding )
1880 Q_ASSERT( !mParser );
1882 mParser = XML_ParserCreateNS( encoding.isEmpty() ?
nullptr : encoding.data(), NS_SEPARATOR );
1883 XML_SetUserData( mParser,
this );
1884 XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
1885 XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
Provides global constants and enumerations for use throughout the application.
@ Critical
Critical/error message.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ MultiPointZ
MultiPointZ.
@ MultiPolygon
MultiPolygon.
@ MultiLineString
MultiLineString.
@ MultiLineStringZ
MultiLineStringZ.
@ MultiPolygonZ
MultiPolygonZ.
@ LineStringZ
LineStringZ.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static endian_t endian()
Returns whether this machine uses big or little endian.
Represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool hasVerticalAxis() const
Returns true if the CRS has a vertical axis.
bool hasAxisInverted() const
Returns whether the axis order is inverted for the CRS compared to the order east/north (longitude/la...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
Container of fields for a vector layer.
int size() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
QPair< QgsFeature *, QString > QgsGmlFeaturePtrGmlIdPair
void setFieldsXPath(const QMap< QString, QPair< QString, bool > > &fieldNameToSrcLayerNameFieldNameMap, const QMap< QString, QString > &namespacePrefixToURIMap)
Define the XPath of the attributes and whether they are made of nested content.
int numberReturned() const
Returns WFS 2.0 "numberReturned" or WFS 1.1 "numberOfFeatures" attribute, or -1 if invalid/not found.
AxisOrientationLogic
Axis orientation logic.
@ Honour_EPSG
Honour EPSG axis order.
@ Honour_EPSG_if_urn
Honour EPSG axis order only if srsName is of the form urn:ogc:def:crs:EPSG:
int numberMatched() const
Returns WFS 2.0 "numberMatched" attribute, or -1 if invalid/not found.
QgsGmlStreamingParser(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields, AxisOrientationLogic axisOrientationLogic=Honour_EPSG_if_urn, bool invertAxisOrientation=false)
Constructor.
bool processData(const QByteArray &data, bool atEnd, QString &errorMsg)
Process a new chunk of data.
QVector< QgsGmlFeaturePtrGmlIdPair > getAndStealReadyFeatures()
Returns the list of features that have been completely parsed.
QString srsName() const
Returns the value of the srsName attribute.
void totalStepsUpdate(int totalSteps)
Emitted when the total number of bytes to read changes.
void dataReadProgress(int progress)
Emitted when data reading progresses.
QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)
QgsCoordinateReferenceSystem crs() const
Returns the spatial reference system for features.
int getFeatures(const QString &uri, Qgis::WkbType *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.
void dataProgressAndSteps(int progress, int totalSteps)
Emitted when data reading progresses or the total number of bytes to read changes.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
@ OGC_HTTP_URI
E.g. http://www.opengis.net/def/crs/EPSG/0/4326.
@ X_OGC_URN
E.g. urn:x-ogc:def:crs:EPSG::4326.
@ UNKNOWN
Unknown/unhandled flavor.
@ OGC_URN
E.g. urn:ogc:def:crs:EPSG::4326.
static CRSFlavor parseCrsName(const QString &crsName, QString &authority, QString &code)
Parse a CRS name in one of the flavors of OGC services, and decompose it as authority and code.
Point geometry type, with support for z-dimension and m-values.
A rectangle specified with double values.
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
void setNull()
Mark a rectangle as being null (holding no spatial information).
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
std::unique_ptr< std::remove_pointer< OGRGeometryH >::type, OGRGeometryDeleter > ogr_geometry_unique_ptr
Scoped OGR geometry.
#define LOCALNAME_EQUALS(string_constant)
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
#define QgsSetRequestInitiatorClass(request, _class)