16#include "moc_qgsgml.cpp" 
   31#include <QNetworkRequest> 
   32#include <QNetworkReply> 
   33#include <QProgressDialog> 
   38#include <QRegularExpression> 
   44using namespace nlohmann;
 
   46#ifndef NS_SEPARATOR_DEFINED 
   47#define NS_SEPARATOR_DEFINED 
   48static const char NS_SEPARATOR = 
'?';
 
   51static const char *
GML_NAMESPACE = 
"http://www.opengis.net/gml";
 
   56  const QString &geometryAttribute,
 
   58  : mParser( 
typeName, geometryAttribute, fields )
 
   62  const int index = mTypeName.indexOf( 
':' );
 
   63  if ( index != -1 && index < mTypeName.length() )
 
   65    mTypeName = mTypeName.mid( index + 1 );
 
 
   74  QNetworkRequest request( uri );
 
   77  if ( !authcfg.isEmpty() )
 
   82        tr( 
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
 
   89  else if ( !userName.isNull() || !password.isNull() )
 
   91    request.setRawHeader( 
"Authorization", 
"Basic " + QStringLiteral( 
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
 
   95  if ( !authcfg.isEmpty() )
 
  101        tr( 
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
 
  109  connect( reply, &QNetworkReply::finished, 
this, &QgsGml::setFinished );
 
  110  connect( reply, &QNetworkReply::downloadProgress, 
this, &QgsGml::handleProgressEvent );
 
  113  QProgressDialog *progressDialog = 
nullptr;
 
  114  QWidget *mainWindow = 
nullptr;
 
  115  const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
 
  116  for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
 
  118    if ( ( *it )->objectName() == QLatin1String( 
"QgisApp" ) )
 
  126    progressDialog = 
new QProgressDialog( tr( 
"Loading GML data\n%1" ).arg( mTypeName ), tr( 
"Abort" ), 0, 0, mainWindow );
 
  127    progressDialog->setWindowModality( Qt::ApplicationModal );
 
  130    connect( progressDialog, &QProgressDialog::canceled, 
this, &QgsGml::setFinished );
 
  131    progressDialog->show();
 
  141    const QByteArray readData = reply->readAll();
 
  142    if ( !readData.isEmpty() )
 
  145      if ( !mParser.
processData( readData, atEnd, errorMsg ) )
 
  149    QCoreApplication::processEvents();
 
  152  fillMapsFromParser();
 
  154  const QNetworkReply::NetworkError replyError = reply->error();
 
  155  const QString replyErrorString = reply->errorString();
 
  158  delete progressDialog;
 
  163      tr( 
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
 
  177      calculateExtentFromFeatures();
 
 
  192  if ( !mParser.
processData( data, 
true , errorMsg ) )
 
  195  fillMapsFromParser();
 
 
  205void QgsGml::fillMapsFromParser()
 
  208  const auto constFeatures = features;
 
  212    const QString &gmlId = featPair.second;
 
  213    mFeatures.insert( feat->
id(), feat );
 
  214    if ( !gmlId.isEmpty() )
 
  216      mIdMap.insert( feat->
id(), gmlId );
 
  221void QgsGml::setFinished()
 
  226void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
 
  228  if ( totalSteps < 0 )
 
  238void QgsGml::calculateExtentFromFeatures()
 
  240  if ( mFeatures.empty() )
 
  247  bool bboxInitialized = 
false; 
 
  249  for ( 
int i = 0; i < mFeatures.size(); ++i )
 
  251    currentFeature = mFeatures[i];
 
  252    if ( !currentFeature )
 
  256    currentGeometry = currentFeature->
geometry();
 
  257    if ( !currentGeometry.
isNull() )
 
  259      if ( !bboxInitialized )
 
  262        bboxInitialized = 
true;
 
  287    const QString &geometryAttribute,
 
  290    bool invertAxisOrientation )
 
  292  , mTypeNameBA( mTypeName.toUtf8() )
 
  293  , mTypeNamePtr( mTypeNameBA.constData() )
 
  294  , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
 
  295  , mWkbType( 
Qgis::WkbType::Unknown )
 
  296  , mGeometryAttribute( geometryAttribute )
 
  297  , mGeometryAttributeBA( geometryAttribute.toUtf8() )
 
  298  , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
 
  299  , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
 
  301  , mIsException( false )
 
  302  , mTruncatedResponse( false )
 
  304  , mFeatureTupleDepth( 0 )
 
  306  , mCurrentWKB( nullptr, 0 )
 
  307  , mBoundedByNullFound( false )
 
  309  , mCoorMode( Coordinate )
 
  311  , mAxisOrientationLogic( axisOrientationLogic )
 
  312  , mInvertAxisOrientationRequest( invertAxisOrientation )
 
  313  , mInvertAxisOrientation( invertAxisOrientation )
 
  314  , mNumberReturned( -1 )
 
  315  , mNumberMatched( -1 )
 
  316  , mFoundUnhandledGeometryElement( false )
 
  318  mThematicAttributes.clear();
 
  319  for ( 
int i = 0; i < fields.
size(); i++ )
 
  321    mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
 
  326  const int index = mTypeName.indexOf( 
':' );
 
  327  if ( index != -1 && index < mTypeName.length() )
 
  329    mTypeName = mTypeName.mid( index + 1 );
 
  330    mTypeNameBA = mTypeName.toUtf8();
 
  331    mTypeNamePtr = mTypeNameBA.constData();
 
  332    mTypeNameUTF8Len = strlen( mTypeNamePtr );
 
 
  338static QString stripNS( 
const QString &
string )
 
  340  const int index = 
string.indexOf( 
':' );
 
  341  if ( index != -1 && index < 
string.length() )
 
  343    return string.mid( index + 1 );
 
  350    const QMap< QString, QPair<QString, QString> > &fieldNameToSrcLayerNameFieldNameMap,
 
  352    bool invertAxisOrientation )
 
  353  : mLayerProperties( layerProperties )
 
  354  , mTypeNameUTF8Len( 0 )
 
  355  , mWkbType( 
Qgis::WkbType::Unknown )
 
  356  , mGeometryAttributeUTF8Len( 0 )
 
  358  , mIsException( false )
 
  359  , mTruncatedResponse( false )
 
  361  , mFeatureTupleDepth( 0 )
 
  363  , mCurrentWKB( nullptr, 0 )
 
  364  , mBoundedByNullFound( false )
 
  366  , mCoorMode( Coordinate )
 
  368  , mAxisOrientationLogic( axisOrientationLogic )
 
  369  , mInvertAxisOrientationRequest( invertAxisOrientation )
 
  370  , mInvertAxisOrientation( invertAxisOrientation )
 
  371  , mNumberReturned( -1 )
 
  372  , mNumberMatched( -1 )
 
  373  , mFoundUnhandledGeometryElement( false )
 
  375  mThematicAttributes.clear();
 
  376  for ( 
int i = 0; i < fields.
size(); i++ )
 
  378    const QMap< QString, QPair<QString, QString> >::const_iterator att_it = fieldNameToSrcLayerNameFieldNameMap.constFind( fields.
at( i ).
name() );
 
  379    if ( att_it != fieldNameToSrcLayerNameFieldNameMap.constEnd() )
 
  381      if ( mLayerProperties.size() == 1 )
 
  382        mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
 
  384        mThematicAttributes.insert( stripNS( att_it.value().first ) + 
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
 
  387  bool alreadyFoundGeometry = 
false;
 
  388  for ( 
int i = 0; i < mLayerProperties.size(); i++ )
 
  391    if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
 
  393      if ( alreadyFoundGeometry )
 
  395        QgsDebugMsgLevel( QStringLiteral( 
"Will ignore geometry field %1 from typename %2" ).
 
  396                          arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ), 2 );
 
  397        mLayerProperties[i].mGeometryAttribute.clear();
 
  399      alreadyFoundGeometry = 
true;
 
  401    mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
 
  404  if ( mLayerProperties.size() == 1 )
 
  406    mTypeName = mLayerProperties[0].mName;
 
  407    mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
 
  408    mGeometryAttributeBA = mGeometryAttribute.toUtf8();
 
  409    mGeometryAttributePtr = mGeometryAttributeBA.constData();
 
  410    mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
 
  411    const int index = mTypeName.indexOf( 
':' );
 
  412    if ( index != -1 && index < mTypeName.length() )
 
  414      mTypeName = mTypeName.mid( index + 1 );
 
  416    mTypeNameBA = mTypeName.toUtf8();
 
  417    mTypeNamePtr = mTypeNameBA.constData();
 
  418    mTypeNameUTF8Len = strlen( mTypeNamePtr );
 
 
  428  const QMap<QString, QPair<QString, bool>> &fieldNameToXPathMapAndIsNestedContent,
 
  429  const QMap<QString, QString> &mapNamespacePrefixToURI )
 
  431  for ( 
auto iter = fieldNameToXPathMapAndIsNestedContent.constBegin(); iter != fieldNameToXPathMapAndIsNestedContent.constEnd(); ++iter )
 
  433    mMapXPathToFieldNameAndIsNestedContent[iter.value().first] = QPair<QString, bool>( iter.key(), iter.value().second );
 
  435  for ( 
auto iter = mapNamespacePrefixToURI.constBegin(); iter != mapNamespacePrefixToURI.constEnd(); ++iter )
 
  436    mMapNamespaceURIToNamespacePrefix[iter.value()] = iter.key();
 
 
  442  XML_ParserFree( mParser );
 
  445  const auto constMFeatureList = mFeatureList;
 
  448    delete featPair.first;
 
  451  delete mCurrentFeature;
 
 
  467  QByteArray data = pdata;
 
  472    QString strData = mCodec->toUnicode( pdata );
 
  473    data = strData.toUtf8();
 
  476  if ( XML_Parse( mParser, data, data.size(), atEnd ) == XML_STATUS_ERROR )
 
  478    const XML_Error errorCode = XML_GetErrorCode( mParser );
 
  479    if ( !mCodec && errorCode == XML_ERROR_UNKNOWN_ENCODING )
 
  483      const thread_local QRegularExpression reEncoding( QStringLiteral( 
"<?xml.*encoding=['\"]([^'\"]*)['\"].*?>" ),
 
  484          QRegularExpression::CaseInsensitiveOption );
 
  485      QRegularExpressionMatch match = reEncoding.match( pdata );
 
  486      const QString encoding = match.hasMatch() ? match.captured( 1 ) : QString();
 
  487      mCodec = !encoding.isEmpty() ? QTextCodec::codecForName( encoding.toLatin1() ) : 
nullptr;
 
  491        XML_ParserFree( mParser );
 
  493        createParser( QByteArrayLiteral( 
"UTF-8" ) );
 
  499    errorMsg = QObject::tr( 
"Error: %1 on line %2, column %3" )
 
  500               .arg( XML_ErrorString( errorCode ) )
 
  501               .arg( XML_GetCurrentLineNumber( mParser ) )
 
  502               .arg( XML_GetCurrentColumnNumber( mParser ) );
 
 
  512  QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
 
  513  mFeatureList.clear();
 
 
  521static json jsonFromString( 
const QString &s )
 
  526  if ( s.indexOf( 
'.' ) >= 0 || s.indexOf( 
'e' ) >= 0 )
 
  528    const auto doubleVal = s.toDouble( &conversionOk );
 
  531      return json( doubleVal );
 
  536  else if ( !s.isEmpty() && s[0] != 
'0' )
 
  538    const auto longlongVal = s.toLongLong( &conversionOk );
 
  541      return json( longlongVal );
 
  545  return json( s.toStdString() );
 
  548#define LOCALNAME_EQUALS(string_constant) \ 
  549  ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 ) 
 
  551void QgsGmlStreamingParser::startElement( 
const XML_Char *el, 
const XML_Char **attr )
 
  553  const int elLen = 
static_cast<int>( strlen( el ) );
 
  554  const char *pszSep = strchr( el, NS_SEPARATOR );
 
  555  const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
 
  556  const int nsLen = ( pszSep ) ? ( 
int )( pszSep - el ) : 0;
 
  557  const int localNameLen = ( pszSep ) ? ( 
int )( elLen - nsLen ) - 1 : elLen;
 
  558  const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
 
  562  if ( !mGMLNameSpaceURIPtr && pszSep )
 
  576  const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
 
  579  if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
 
  580       parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
 
  582    mGeometryString.append( 
"<", 1 );
 
  583    mGeometryString.append( pszLocalName, localNameLen );
 
  584    mGeometryString.append( 
" ", 1 );
 
  585    for ( 
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
 
  587      const size_t nAttrLen = strlen( attrIter[0] );
 
  590      if ( nAttrLen > GML32_NAMESPACE_LEN &&
 
  591           attrIter[0][GML32_NAMESPACE_LEN] == 
'?' &&
 
  594        mGeometryString.append( 
"gml:" );
 
  595        mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
 
  597      else if ( nAttrLen > GML_NAMESPACE_LEN &&
 
  598                attrIter[0][GML_NAMESPACE_LEN] == 
'?' &&
 
  599                memcmp( attrIter[0], 
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
 
  601        mGeometryString.append( 
"gml:" );
 
  602        mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
 
  606        mGeometryString.append( attrIter[0] );
 
  608      mGeometryString.append( 
"=\"", 2 );
 
  609      mGeometryString.append( attrIter[1] );
 
  610      mGeometryString.append( 
"\" ", 2 );
 
  613    mGeometryString.append( 
">", 1 );
 
  616  if ( !mAttributeValIsNested && isGMLNS && 
LOCALNAME_EQUALS( 
"coordinates" ) )
 
  618    mParseModeStack.push( Coordinate );
 
  619    mCoorMode = QgsGmlStreamingParser::Coordinate;
 
  621    mCoordinateSeparator = readAttribute( QStringLiteral( 
"cs" ), attr );
 
  622    if ( mCoordinateSeparator.isEmpty() )
 
  624      mCoordinateSeparator = 
',';
 
  626    mTupleSeparator = readAttribute( QStringLiteral( 
"ts" ), attr );
 
  627    if ( mTupleSeparator.isEmpty() )
 
  629      mTupleSeparator = 
' ';
 
  632  else if ( !mAttributeValIsNested && isGMLNS &&
 
  635    mParseModeStack.push( QgsGmlStreamingParser::PosList );
 
  636    if ( mCoorMode == QgsGmlStreamingParser::PosList )
 
  638      if ( !mStringCash.isEmpty() )
 
  640        mStringCash.append( QLatin1Char( 
' ' ) );
 
  647    mCoorMode = QgsGmlStreamingParser::PosList;
 
  648    if ( elDimension == 0 )
 
  650      const QString srsDimension = readAttribute( QStringLiteral( 
"srsDimension" ), attr );
 
  652      const int dimension = srsDimension.toInt( &ok );
 
  655        elDimension = dimension;
 
  659  else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
 
  661            localNameLen == 
static_cast<int>( mGeometryAttributeUTF8Len ) &&
 
  662            memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
 
  664    mParseModeStack.push( QgsGmlStreamingParser::Geometry );
 
  665    mFoundUnhandledGeometryElement = 
false;
 
  666    mGeometryString.clear();
 
  670  else if ( !mAttributeValIsNested && isGMLNS && 
LOCALNAME_EQUALS( 
"boundedBy" ) )
 
  672    mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
 
  674    mBoundedByNullFound = 
false;
 
  676  else if ( parseMode == BoundingBox &&
 
  679    mParseModeStack.push( QgsGmlStreamingParser::Null );
 
  680    mBoundedByNullFound = 
true;
 
  682  else if ( parseMode == BoundingBox &&
 
  686    mParseModeStack.push( QgsGmlStreamingParser::Envelope );
 
  688  else if ( parseMode == Envelope &&
 
  691    mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
 
  694  else if ( parseMode == Envelope &&
 
  697    mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
 
  700  else if ( parseMode == None && !mTypeNamePtr &&
 
  703    Q_ASSERT( !mCurrentFeature );
 
  704    mCurrentFeature = 
new QgsFeature( mFeatureCount );
 
  706    const QgsAttributes attributes( mThematicAttributes.size() ); 
 
  708    mParseModeStack.push( QgsGmlStreamingParser::Tuple );
 
  709    mCurrentFeatureId.clear();
 
  711  else if ( parseMode == Tuple )
 
  713    const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
 
  714    const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
 
  715    if ( iter != mMapTypeNameToProperties.constEnd() )
 
  717      mFeatureTupleDepth = mParseDepth;
 
  718      mCurrentTypename = currentTypename;
 
  719      mGeometryAttribute.clear();
 
  720      if ( mCurrentWKB.size() == 0 )
 
  722        mGeometryAttribute = iter.value().mGeometryAttribute;
 
  724      mGeometryAttributeBA = mGeometryAttribute.toUtf8();
 
  725      mGeometryAttributePtr = mGeometryAttributeBA.constData();
 
  726      mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
 
  727      mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
 
  729      if ( mGMLNameSpaceURI.isEmpty() )
 
  731        id = readAttribute( QString( 
GML_NAMESPACE ) + NS_SEPARATOR + 
"id", attr );
 
  739          id = readAttribute( QString( 
GML32_NAMESPACE ) + NS_SEPARATOR + 
"id", attr );
 
  748        id = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR + 
"id", attr );
 
  749      if ( !mCurrentFeatureId.isEmpty() )
 
  750        mCurrentFeatureId += 
'|';
 
  751      mCurrentFeatureId += id;
 
  754  else if ( parseMode == None &&
 
  755            localNameLen == 
static_cast<int>( mTypeNameUTF8Len ) &&
 
  757            memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
 
  759    Q_ASSERT( !mCurrentFeature );
 
  760    mCurrentFeature = 
new QgsFeature( mFeatureCount );
 
  762    const QgsAttributes attributes( mThematicAttributes.size() ); 
 
  764    mParseModeStack.push( QgsGmlStreamingParser::Feature );
 
  765    mCurrentXPathWithinFeature.clear();
 
  766    mCurrentFeatureId = readAttribute( QStringLiteral( 
"fid" ), attr );
 
  767    if ( mCurrentFeatureId.isEmpty() )
 
  772      if ( mGMLNameSpaceURI.isEmpty() )
 
  774        mCurrentFeatureId = readAttribute( QString( 
GML_NAMESPACE ) + NS_SEPARATOR + 
"id", attr );
 
  775        if ( !mCurrentFeatureId.isEmpty() )
 
  782          mCurrentFeatureId = readAttribute( QString( 
GML32_NAMESPACE ) + NS_SEPARATOR + 
"id", attr );
 
  783          if ( !mCurrentFeatureId.isEmpty() )
 
  791        mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR + 
"id", attr );
 
  795  else if ( parseMode == BoundingBox && isGMLNS && 
LOCALNAME_EQUALS( 
"Box" ) )
 
  799  else if ( !mAttributeValIsNested && isGMLNS && 
LOCALNAME_EQUALS( 
"Point" ) )
 
  803  else if ( !mAttributeValIsNested && isGMLNS && 
LOCALNAME_EQUALS( 
"LineString" ) )
 
  807  else if ( !mAttributeValIsNested && isGMLNS &&
 
  808            localNameLen == 
static_cast<int>( strlen( 
"Polygon" ) ) && memcmp( pszLocalName, 
"Polygon", localNameLen ) == 0 )
 
  811    mCurrentWKBFragments.push_back( QList<QByteArray>() );
 
  813  else if ( !mAttributeValIsNested && isGMLNS && 
LOCALNAME_EQUALS( 
"MultiPoint" ) )
 
  816    mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
 
  818    mCurrentWKBFragments.push_back( QList<QByteArray>() );
 
  823    mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
 
  825    mCurrentWKBFragments.push_back( QList<QByteArray>() );
 
  830    mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
 
  832  else if ( parseMode == FeatureTuple )
 
  834    const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
 
  835    if ( mThematicAttributes.contains( mCurrentTypename + 
'|' + localName ) )
 
  837      mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
 
  838      mAttributeName = mCurrentTypename + 
'|' + localName;
 
  842  else if ( parseMode == Feature )
 
  844    const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
 
  845    if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
 
  847      const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
 
  848      const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
 
  849      if ( !mCurrentXPathWithinFeature.isEmpty() )
 
  850        mCurrentXPathWithinFeature.append( 
'/' );
 
  851      if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
 
  853        mCurrentXPathWithinFeature.append( *nsIter );
 
  854        mCurrentXPathWithinFeature.append( 
':' );
 
  856      mCurrentXPathWithinFeature.append( localName );
 
  857      const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( mCurrentXPathWithinFeature );
 
  858      mAttributeValIsNested = 
false;
 
  859      if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
 
  861        mParseModeStack.push( QgsGmlStreamingParser::Attribute );
 
  862        mAttributeDepth = mParseDepth;
 
  863        mAttributeName = xpathIter->first;
 
  864        mAttributeValIsNested = xpathIter->second;
 
  865        if ( mAttributeValIsNested )
 
  867          mAttributeJson = json::object();
 
  868          mAttributeJsonCurrentStack.clear();
 
  869          mAttributeJsonCurrentStack.push( &mAttributeJson );
 
  874    else if ( mThematicAttributes.contains( localName ) )
 
  876      mParseModeStack.push( QgsGmlStreamingParser::Attribute );
 
  877      mAttributeDepth = mParseDepth;
 
  878      mAttributeName = localName;
 
  885      if ( localName.compare( QLatin1String( 
"attribute" ), Qt::CaseInsensitive ) == 0 )
 
  887        const QString name = readAttribute( QStringLiteral( 
"name" ), attr );
 
  888        if ( mThematicAttributes.contains( name ) )
 
  890          const QString value = readAttribute( QStringLiteral( 
"value" ), attr );
 
  891          setAttribute( name, value );
 
  896  else if ( parseMode == Attribute && mAttributeValIsNested )
 
  898    const std::string localName( pszLocalName, localNameLen );
 
  899    const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
 
  900    const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
 
  901    const std::string nodeName = nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() ? ( *nsIter ).toStdString() + 
':' + localName : localName;
 
  903    addStringContentToJson();
 
  905    auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
 
  906    auto iter = jsonParent.find( nodeName );
 
  907    if ( iter != jsonParent.end() )
 
  909      if ( iter->type() != json::value_t::array )
 
  911        auto array = json::array();
 
  912        array.emplace_back( std::move( *iter ) );
 
  915      iter->push_back( json::object() );
 
  916      mAttributeJsonCurrentStack.push( &( iter->back() ) );
 
  920      auto res = jsonParent.emplace( nodeName, json::object() );
 
  924      nlohmann::json *ptr = &( *( res.first ) );
 
  926      mAttributeJsonCurrentStack.push( ptr );
 
  931    QString 
numberReturned = readAttribute( QStringLiteral( 
"numberReturned" ), attr ); 
 
  933      numberReturned = readAttribute( QStringLiteral( 
"numberOfFeatures" ), attr ); 
 
  937      mNumberReturned = -1;
 
  939    const QString 
numberMatched = readAttribute( QStringLiteral( 
"numberMatched" ), attr ); 
 
  947    mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
 
  952    mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
 
  957    mTruncatedResponse = 
true;
 
  959  else if ( !mGeometryString.empty() &&
 
  975    mFoundUnhandledGeometryElement = 
true;
 
  979  if ( !mParseModeStack.isEmpty() &&
 
  980       ( mParseModeStack.back() == Feature ||
 
  981         mParseModeStack.back() == Attribute ) &&
 
  982       !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
 
  984    for ( 
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
 
  986      const char *questionMark = strchr( attrIter[0], 
'?' );
 
  990        const QString nsURI( QString::fromUtf8( attrIter[0], 
static_cast<int>( questionMark - attrIter[0] ) ) );
 
  991        const QString localName( QString::fromUtf8( questionMark + 1 ) );
 
  992        const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
 
  993        if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
 
  995          key.append( *nsIter );
 
  998        key.append( localName );
 
 1002        const QString localName( QString::fromUtf8( attrIter[0] ) );
 
 1003        key.append( localName );
 
 1006      if ( mAttributeValIsNested && mParseModeStack.back() == Attribute )
 
 1008        mAttributeJsonCurrentStack.top()->emplace(
 
 1010          jsonFromString( QString::fromUtf8( attrIter[1] ) ) );
 
 1014        QString xpath( mCurrentXPathWithinFeature );
 
 1015        if ( !xpath.isEmpty() )
 
 1016          xpath.append( 
'/' );
 
 1017        xpath.append( key );
 
 1018        const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( xpath );
 
 1019        if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
 
 1021          setAttribute( xpathIter->first, QString::fromUtf8( attrIter[1] ) );
 
 1027  if ( !mGeometryString.empty() )
 
 1030  if ( elDimension == 0 && isGeom )
 
 1034    const QString srsDimension = readAttribute( QStringLiteral( 
"srsDimension" ), attr );
 
 1036    const int dimension = srsDimension.toInt( &ok );
 
 1039      elDimension = dimension;
 
 1043  if ( elDimension != 0 || mDimensionStack.isEmpty() )
 
 1045    mDimensionStack.push( elDimension );
 
 1049    mDimensionStack.push( mDimensionStack.back() );
 
 1052  if ( mEpsg == 0 && isGeom )
 
 1054    if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
 
 1056      QgsDebugError( QStringLiteral( 
"error, could not get epsg id" ) );
 
 1067void QgsGmlStreamingParser::endElement( 
const XML_Char *el )
 
 1071  const int elLen = 
static_cast<int>( strlen( el ) );
 
 1072  const char *pszSep = strchr( el, NS_SEPARATOR );
 
 1073  const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
 
 1074  const int nsLen = ( pszSep ) ? ( 
int )( pszSep - el ) : 0;
 
 1075  const int localNameLen = ( pszSep ) ? ( 
int )( elLen - nsLen ) - 1 : elLen;
 
 1076  const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
 
 1078  const int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
 
 1080  const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
 
 1082  if ( parseMode == Feature || ( parseMode == Attribute && mAttributeDepth == mParseDepth ) )
 
 1084    if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
 
 1086      const auto nPos = mCurrentXPathWithinFeature.lastIndexOf( 
'/' );
 
 1088        mCurrentXPathWithinFeature.clear();
 
 1090        mCurrentXPathWithinFeature.resize( nPos );
 
 1094  if ( parseMode == Attribute && mAttributeValIsNested )
 
 1096    if ( !mStringCash.isEmpty() )
 
 1098      auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
 
 1099      if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
 
 1101        jsonParent = jsonFromString( mStringCash );
 
 1103      else if ( jsonParent.type() == json::value_t::object )
 
 1105        addStringContentToJson();
 
 1107      mStringCash.clear();
 
 1110    mAttributeJsonCurrentStack.pop();
 
 1113  if ( parseMode == Coordinate && isGMLNS && 
LOCALNAME_EQUALS( 
"coordinates" ) )
 
 1115    mParseModeStack.pop();
 
 1117  else if ( parseMode == PosList && isGMLNS &&
 
 1120    mDimension = lastDimension;
 
 1121    mParseModeStack.pop();
 
 1123  else if ( parseMode == AttributeTuple &&
 
 1124            mCurrentTypename + 
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName ) 
 
 1126    mParseModeStack.pop();
 
 1128    setAttribute( mAttributeName, mStringCash );
 
 1130  else if ( parseMode == Attribute && mAttributeDepth == mParseDepth ) 
 
 1132    mParseModeStack.pop();
 
 1135    if ( mAttributeValIsNested )
 
 1137      mAttributeValIsNested = 
false;
 
 1138      auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
 
 1139      if ( iter == mMapFieldNameToJSONContent.end() )
 
 1141        mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
 
 1145        QString &str = iter.value();
 
 1146        if ( str[0] == 
'[' && str.back() == 
']' )
 
 1152          str.insert( 0, 
'[' );
 
 1155        str.append( QString::fromStdString( mAttributeJson.dump() ) );
 
 1161      setAttribute( mAttributeName, mStringCash );
 
 1164  else if ( parseMode == Geometry &&
 
 1165            localNameLen == 
static_cast<int>( mGeometryAttributeUTF8Len ) &&
 
 1166            memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
 
 1168    mParseModeStack.pop();
 
 1169    if ( mFoundUnhandledGeometryElement )
 
 1175        const int wkbSize = OGR_G_WkbSize( hGeom.get() );
 
 1176        unsigned char *pabyBuffer = 
new unsigned char[ wkbSize ];
 
 1177        OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
 
 1179        g.
fromWkb( pabyBuffer, wkbSize );
 
 1180        if ( mInvertAxisOrientation )
 
 1182          g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
 
 1184        Q_ASSERT( mCurrentFeature );
 
 1188    mGeometryString.clear();
 
 1190  else if ( parseMode == BoundingBox && isGMLNS && 
LOCALNAME_EQUALS( 
"boundedBy" ) )
 
 1193    if ( mCurrentExtent.
isNull() &&
 
 1194         !mBoundedByNullFound &&
 
 1195         !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
 
 1197      QgsDebugError( QStringLiteral( 
"creation of bounding box failed" ) );
 
 1199    if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
 
 1200         !mCurrentFeature && mFeatureCount == 0 )
 
 1202      mLayerExtent = mCurrentExtent;
 
 1206    mParseModeStack.pop();
 
 1210    mParseModeStack.pop();
 
 1212  else if ( parseMode == Envelope && isGMLNS && 
LOCALNAME_EQUALS( 
"Envelope" ) )
 
 1214    mParseModeStack.pop();
 
 1216  else if ( parseMode == LowerCorner && isGMLNS && 
LOCALNAME_EQUALS( 
"lowerCorner" ) )
 
 1218    QList<QgsPointXY> points;
 
 1219    pointsFromPosListString( points, mStringCash, 2 );
 
 1220    if ( points.size() == 1 )
 
 1225    mParseModeStack.pop();
 
 1227  else if ( parseMode == UpperCorner && isGMLNS && 
LOCALNAME_EQUALS( 
"upperCorner" ) )
 
 1229    QList<QgsPointXY> points;
 
 1230    pointsFromPosListString( points, mStringCash, 2 );
 
 1231    if ( points.size() == 1 )
 
 1236    mParseModeStack.pop();
 
 1238  else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
 
 1240    mParseModeStack.pop();
 
 1241    mFeatureTupleDepth = 0;
 
 1243  else if ( ( parseMode == Tuple && !mTypeNamePtr &&
 
 1245            ( parseMode == Feature &&
 
 1246              localNameLen == 
static_cast<int>( mTypeNameUTF8Len ) &&
 
 1247              memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
 
 1249    Q_ASSERT( mCurrentFeature );
 
 1252      if ( mCurrentWKB.size() > 0 )
 
 1257        mCurrentWKB = QByteArray();
 
 1259      else if ( !mCurrentExtent.
isEmpty() )
 
 1266    for ( 
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
 
 1268      const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
 
 1269      const int attrIndex = att_it.value().first;
 
 1270      mCurrentFeature->
setAttribute( attrIndex, iter.value() );
 
 1272    mMapFieldNameToJSONContent.clear();
 
 1276    mCurrentFeature = 
nullptr;
 
 1278    mParseModeStack.pop();
 
 1280  else if ( !mAttributeValIsNested && isGMLNS && 
LOCALNAME_EQUALS( 
"Point" ) )
 
 1282    QList<QgsPointXY> pointList;
 
 1283    if ( pointsFromString( pointList, mStringCash ) != 0 )
 
 1287    mStringCash.clear();
 
 1289    if ( pointList.isEmpty() )
 
 1292    if ( parseMode == QgsGmlStreamingParser::Geometry )
 
 1295      if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
 
 1308      if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
 
 1312      if ( !mCurrentWKBFragments.isEmpty() )
 
 1314        mCurrentWKBFragments.last().push_back( wkbPtr );
 
 1322  else if ( !mAttributeValIsNested &&
 
 1327    QList<QgsPointXY> pointList;
 
 1328    if ( pointsFromString( pointList, mStringCash ) != 0 )
 
 1332    mStringCash.clear();
 
 1334    if ( parseMode == QgsGmlStreamingParser::Geometry )
 
 1336      if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
 
 1349      if ( getLineWKB( wkbPtr, pointList ) != 0 )
 
 1353      if ( !mCurrentWKBFragments.isEmpty() )
 
 1355        mCurrentWKBFragments.last().push_back( wkbPtr );
 
 1363  else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
 
 1366    QList<QgsPointXY> pointList;
 
 1367    if ( pointsFromString( pointList, mStringCash ) != 0 )
 
 1371    mStringCash.clear();
 
 1374    if ( getRingWKB( wkbPtr, pointList ) != 0 )
 
 1379    if ( !mCurrentWKBFragments.isEmpty() )
 
 1381      mCurrentWKBFragments.last().push_back( wkbPtr );
 
 1388  else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
 
 1396    if ( parseMode == Geometry )
 
 1398      createPolygonFromFragments();
 
 1401  else if ( parseMode == MultiPoint &&  isGMLNS &&
 
 1405    mParseModeStack.pop();
 
 1406    createMultiPointFromFragments();
 
 1408  else if ( parseMode == MultiLine && isGMLNS &&
 
 1412    mParseModeStack.pop();
 
 1413    createMultiLineFromFragments();
 
 1415  else if ( parseMode == MultiPolygon && isGMLNS &&
 
 1419    mParseModeStack.pop();
 
 1420    createMultiPolygonFromFragments();
 
 1424    mParseModeStack.pop();
 
 1426  else if ( parseMode == ExceptionText && 
LOCALNAME_EQUALS( 
"ExceptionText" ) )
 
 1428    mExceptionText = mStringCash;
 
 1429    mParseModeStack.pop();
 
 1432  if ( !mGeometryString.empty() )
 
 1434    mGeometryString.append( 
"</", 2 );
 
 1435    mGeometryString.append( pszLocalName, localNameLen );
 
 1436    mGeometryString.append( 
">", 1 );
 
 1441void QgsGmlStreamingParser::characters( 
const XML_Char *chars, 
int len )
 
 1444  if ( mParseModeStack.isEmpty() )
 
 1449  if ( !mGeometryString.empty() )
 
 1451    mGeometryString.append( chars, len );
 
 1454  const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
 
 1455  if ( parseMode == QgsGmlStreamingParser::Attribute ||
 
 1456       parseMode == QgsGmlStreamingParser::AttributeTuple ||
 
 1457       parseMode == QgsGmlStreamingParser::Coordinate ||
 
 1458       parseMode == QgsGmlStreamingParser::PosList ||
 
 1459       parseMode == QgsGmlStreamingParser::LowerCorner ||
 
 1460       parseMode == QgsGmlStreamingParser::UpperCorner ||
 
 1461       parseMode == QgsGmlStreamingParser::ExceptionText )
 
 1463    mStringCash.append( QString::fromUtf8( chars, len ) );
 
 1467void QgsGmlStreamingParser::addStringContentToJson()
 
 1469  const QString s( mStringCash.trimmed() );
 
 1472    auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
 
 1473    auto textIter = jsonParent.find( 
"_text" );
 
 1474    if ( textIter != jsonParent.end() )
 
 1476      if ( textIter->type() != json::value_t::array )
 
 1478        auto array = json::array();
 
 1479        array.emplace_back( std::move( *textIter ) );
 
 1482      textIter->emplace_back( jsonFromString( s ) );
 
 1486      jsonParent.emplace( 
"_text", jsonFromString( s ) );
 
 1489  mStringCash.clear();
 
 1492void QgsGmlStreamingParser::setAttribute( 
const QString &name, 
const QString &value )
 
 1495  const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
 
 1496  bool conversionOk = 
true;
 
 1497  if ( att_it != mThematicAttributes.constEnd() )
 
 1500    switch ( att_it.value().second.type() )
 
 1502      case QMetaType::Type::Double:
 
 1503        var = QVariant( value.toDouble( &conversionOk ) );
 
 1505      case QMetaType::Type::Int:
 
 1506        var = QVariant( value.toInt( &conversionOk ) );
 
 1508      case QMetaType::Type::LongLong:
 
 1509        var = QVariant( value.toLongLong( &conversionOk ) );
 
 1511      case QMetaType::Type::QDateTime:
 
 1512        var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
 
 1515        var = QVariant( value );
 
 1518    if ( ! conversionOk )  
 
 1522    Q_ASSERT( mCurrentFeature );
 
 1523    mCurrentFeature->
setAttribute( att_it.value().first, var );
 
 1527int QgsGmlStreamingParser::readEpsgFromAttribute( 
int &epsgNr, 
const XML_Char **attr )
 
 1532    if ( strcmp( attr[i], 
"srsName" ) == 0 )
 
 1534      const QString 
srsName( attr[i + 1] );
 
 1546      const int eNr = code.toInt( &conversionOk );
 
 1547      if ( !conversionOk )
 
 1560          mInvertAxisOrientation = !mInvertAxisOrientationRequest;
 
 1571QString QgsGmlStreamingParser::readAttribute( 
const QString &attributeName, 
const XML_Char **attr )
 const 
 1576    if ( attributeName.compare( attr[i] ) == 0 )
 
 1578      return QString::fromUtf8( attr[i + 1] );
 
 1585bool QgsGmlStreamingParser::createBBoxFromCoordinateString( 
QgsRectangle &r, 
const QString &coordString )
 const 
 1587  QList<QgsPointXY> points;
 
 1588  if ( pointsFromCoordinateString( points, coordString ) != 0 )
 
 1593  if ( points.size() < 2 )
 
 1598  r.
set( points[0], points[1] );
 
 1603int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points, 
const QString &coordString )
 const 
 1606  const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
 
 1607  QStringList tuples_coordinates;
 
 1609  bool conversionSuccess;
 
 1611  QStringList::const_iterator tupleIterator;
 
 1612  for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
 
 1614    tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
 
 1615    if ( tuples_coordinates.size() < 2 )
 
 1619    x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
 
 1620    if ( !conversionSuccess )
 
 1624    y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
 
 1625    if ( !conversionSuccess )
 
 1634int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points, 
const QString &coordString, 
int dimension )
 const 
 1637  const QStringList coordinates = coordString.split( 
' ', Qt::SkipEmptyParts );
 
 1639  if ( coordinates.size() % dimension != 0 )
 
 1641    QgsDebugError( QStringLiteral( 
"Wrong number of coordinates" ) );
 
 1644  const int ncoor = coordinates.size() / dimension;
 
 1645  for ( 
int i = 0; i < ncoor; i++ )
 
 1647    bool conversionSuccess;
 
 1648    const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
 
 1649    if ( !conversionSuccess )
 
 1653    const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
 
 1654    if ( !conversionSuccess )
 
 1663int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points, 
const QString &coordString )
 const 
 1665  if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
 
 1667    return pointsFromCoordinateString( points, coordString );
 
 1669  else if ( mCoorMode == QgsGmlStreamingParser::PosList )
 
 1671    return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
 
 1676int QgsGmlStreamingParser::getPointWKB( QByteArray &wkbPtr, 
const QgsPointXY &point )
 const 
 1678  const int wkbSize = 1 + 
sizeof( int ) + 2 * 
sizeof( 
double );
 
 1679  wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
 
 1687int QgsGmlStreamingParser::getLineWKB( QByteArray &wkbPtr, 
const QList<QgsPointXY> &lineCoordinates )
 const 
 1689  const int wkbSize = 1 + 2 * 
sizeof( int ) + lineCoordinates.size() * 2 * 
sizeof( double );
 
 1690  wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
 
 1696  QList<QgsPointXY>::const_iterator iter;
 
 1697  for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
 
 1699    fillPtr << iter->x() << iter->y();
 
 1705int QgsGmlStreamingParser::getRingWKB( QByteArray &wkbPtr, 
const QList<QgsPointXY> &ringCoordinates )
 const 
 1707  const int wkbSize = 
sizeof( int ) + ringCoordinates.size() * 2 * 
sizeof( double );
 
 1708  wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
 
 1712  fillPtr << ringCoordinates.size();
 
 1714  QList<QgsPointXY>::const_iterator iter;
 
 1715  for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
 
 1717    fillPtr << iter->x() << iter->y();
 
 1723int QgsGmlStreamingParser::createMultiLineFromFragments()
 
 1725  const int size = 1 + 2 * 
sizeof( int ) + totalWKBFragmentSize();
 
 1726  mCurrentWKB = QByteArray( size, Qt::Uninitialized );
 
 1733  auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
 
 1734  for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
 
 1736    memcpy( wkbPtr, *wkbIt, wkbIt->size() );
 
 1737    wkbPtr += wkbIt->size();
 
 1740  mCurrentWKBFragments.clear();
 
 1745int QgsGmlStreamingParser::createMultiPointFromFragments()
 
 1747  const int size = 1 + 2 * 
sizeof( int ) + totalWKBFragmentSize();
 
 1748  mCurrentWKB = QByteArray( size, Qt::Uninitialized );
 
 1753  auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
 
 1754  for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
 
 1756    memcpy( wkbPtr, *wkbIt, wkbIt->size() );
 
 1757    wkbPtr += wkbIt->size();
 
 1760  mCurrentWKBFragments.clear();
 
 1766int QgsGmlStreamingParser::createPolygonFromFragments()
 
 1768  const int size = 1 + 2 * 
sizeof( int ) + totalWKBFragmentSize();
 
 1769  mCurrentWKB = QByteArray( size, Qt::Uninitialized );
 
 1774  auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
 
 1775  for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
 
 1777    memcpy( wkbPtr, *wkbIt, wkbIt->size() );
 
 1778    wkbPtr += wkbIt->size();
 
 1781  mCurrentWKBFragments.clear();
 
 1786int QgsGmlStreamingParser::createMultiPolygonFromFragments()
 
 1789  size += 1 + 2 * 
sizeof( int );
 
 1790  size += totalWKBFragmentSize();
 
 1791  size += mCurrentWKBFragments.size() * ( 1 + 2 * 
sizeof( int ) ); 
 
 1793  mCurrentWKB = QByteArray( size, Qt::Uninitialized );
 
 1799  auto outerWkbIt = mCurrentWKBFragments.constBegin();
 
 1801  for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
 
 1806    auto innerWkbIt = outerWkbIt->constBegin();
 
 1807    for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
 
 1809      memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
 
 1810      wkbPtr += innerWkbIt->size();
 
 1814  mCurrentWKBFragments.clear();
 
 1819int QgsGmlStreamingParser::totalWKBFragmentSize()
 const 
 1822  for ( 
const QList<QByteArray> &list : std::as_const( mCurrentWKBFragments ) )
 
 1824    for ( 
const QByteArray &i : list )
 
 1832void QgsGmlStreamingParser::createParser( 
const QByteArray &encoding )
 
 1834  Q_ASSERT( !mParser );
 
 1836  mParser = XML_ParserCreateNS( encoding.isEmpty() ? 
nullptr : encoding.data(), NS_SEPARATOR );
 
 1837  XML_SetUserData( mParser, 
this );
 
 1838  XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
 
 1839  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.
 
@ MultiPolygon
MultiPolygon.
 
@ MultiLineString
MultiLineString.
 
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 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...
 
Q_INVOKABLE bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
 
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.
 
void setValid(bool validity)
Sets the validity of the feature.
 
bool hasGeometry() const
Returns true if the feature has an associated geometry.
 
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
 
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).
 
A geometry is the spatial representation of a feature.
 
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.
 
Qgis::WkbType wkbType() const
Returns the geometry type.
 
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.
 
int getEPSGCode() const
Returns the EPSG code, or 0 if unknown.
 
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.
 
A rectangle specified with double values.
 
void setYMinimum(double y)
Set the minimum y value.
 
void setXMinimum(double x)
Set the minimum x value.
 
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
 
void setYMaximum(double y)
Set the maximum y value.
 
void setXMaximum(double x)
Set the maximum x value.
 
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
 
void setNull()
Mark a rectangle as being null (holding no spatial information).
 
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)
 
const QgsCoordinateReferenceSystem & crs