30#include <QNetworkRequest> 
   31#include <QNetworkReply> 
   32#include <QProgressDialog> 
   37#include <QRegularExpression> 
   43using namespace nlohmann;
 
   45static const char NS_SEPARATOR = 
'?';
 
   46static const char *
GML_NAMESPACE = 
"http://www.opengis.net/gml";
 
   51  const QString &geometryAttribute,
 
   53  : mParser( 
typeName, geometryAttribute, fields )
 
   57  const int index = mTypeName.indexOf( 
':' );
 
   58  if ( index != -1 && index < mTypeName.length() )
 
   60    mTypeName = mTypeName.mid( index + 1 );
 
 
   69  QNetworkRequest request( uri );
 
   72  if ( !authcfg.isEmpty() )
 
   77        tr( 
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
 
   84  else if ( !userName.isNull() || !password.isNull() )
 
   86    request.setRawHeader( 
"Authorization", 
"Basic " + QStringLiteral( 
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
 
   90  if ( !authcfg.isEmpty() )
 
   96        tr( 
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
 
  104  connect( reply, &QNetworkReply::finished, 
this, &QgsGml::setFinished );
 
  105  connect( reply, &QNetworkReply::downloadProgress, 
this, &QgsGml::handleProgressEvent );
 
  108  QProgressDialog *progressDialog = 
nullptr;
 
  109  QWidget *mainWindow = 
nullptr;
 
  110  const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
 
  111  for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
 
  113    if ( ( *it )->objectName() == QLatin1String( 
"QgisApp" ) )
 
  121    progressDialog = 
new QProgressDialog( tr( 
"Loading GML data\n%1" ).arg( mTypeName ), tr( 
"Abort" ), 0, 0, mainWindow );
 
  122    progressDialog->setWindowModality( Qt::ApplicationModal );
 
  125    connect( progressDialog, &QProgressDialog::canceled, 
this, &QgsGml::setFinished );
 
  126    progressDialog->show();
 
  136    const QByteArray readData = reply->readAll();
 
  137    if ( !readData.isEmpty() )
 
  140      if ( !mParser.
processData( readData, atEnd, errorMsg ) )
 
  144    QCoreApplication::processEvents();
 
  147  fillMapsFromParser();
 
  149  const QNetworkReply::NetworkError replyError = reply->error();
 
  150  const QString replyErrorString = reply->errorString();
 
  153  delete progressDialog;
 
  158      tr( 
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
 
  172      calculateExtentFromFeatures();
 
 
  187  if ( !mParser.
processData( data, 
true , errorMsg ) )
 
  190  fillMapsFromParser();
 
 
  200void QgsGml::fillMapsFromParser()
 
  203  const auto constFeatures = features;
 
  207    const QString &gmlId = featPair.second;
 
  208    mFeatures.insert( feat->
id(), feat );
 
  209    if ( !gmlId.isEmpty() )
 
  211      mIdMap.insert( feat->
id(), gmlId );
 
  216void QgsGml::setFinished()
 
  221void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
 
  223  if ( totalSteps < 0 )
 
  233void QgsGml::calculateExtentFromFeatures()
 
  235  if ( mFeatures.empty() )
 
  242  bool bboxInitialized = 
false; 
 
  244  for ( 
int i = 0; i < mFeatures.size(); ++i )
 
  246    currentFeature = mFeatures[i];
 
  247    if ( !currentFeature )
 
  251    currentGeometry = currentFeature->
geometry();
 
  252    if ( !currentGeometry.
isNull() )
 
  254      if ( !bboxInitialized )
 
  257        bboxInitialized = 
true;
 
  282    const QString &geometryAttribute,
 
  285    bool invertAxisOrientation )
 
  287  , mTypeNameBA( mTypeName.toUtf8() )
 
  288  , mTypeNamePtr( mTypeNameBA.constData() )
 
  289  , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
 
  290  , mWkbType( 
Qgis::WkbType::Unknown )
 
  291  , mGeometryAttribute( geometryAttribute )
 
  292  , mGeometryAttributeBA( geometryAttribute.toUtf8() )
 
  293  , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
 
  294  , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
 
  296  , mIsException( false )
 
  297  , mTruncatedResponse( false )
 
  299  , mFeatureTupleDepth( 0 )
 
  301  , mCurrentWKB( nullptr, 0 )
 
  302  , mBoundedByNullFound( false )
 
  304  , mCoorMode( Coordinate )
 
  306  , mAxisOrientationLogic( axisOrientationLogic )
 
  307  , mInvertAxisOrientationRequest( invertAxisOrientation )
 
  308  , mInvertAxisOrientation( invertAxisOrientation )
 
  309  , mNumberReturned( -1 )
 
  310  , mNumberMatched( -1 )
 
  311  , mFoundUnhandledGeometryElement( false )
 
  313  mThematicAttributes.clear();
 
  314  for ( 
int i = 0; i < fields.
size(); i++ )
 
  316    mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
 
  321  const int index = mTypeName.indexOf( 
':' );
 
  322  if ( index != -1 && index < mTypeName.length() )
 
  324    mTypeName = mTypeName.mid( index + 1 );
 
  325    mTypeNameBA = mTypeName.toUtf8();
 
  326    mTypeNamePtr = mTypeNameBA.constData();
 
  327    mTypeNameUTF8Len = strlen( mTypeNamePtr );
 
 
  333static QString stripNS( 
const QString &
string )
 
  335  const int index = 
string.indexOf( 
':' );
 
  336  if ( index != -1 && index < 
string.length() )
 
  338    return string.mid( index + 1 );
 
  345    const QMap< QString, QPair<QString, QString> > &fieldNameToSrcLayerNameFieldNameMap,
 
  347    bool invertAxisOrientation )
 
  348  : mLayerProperties( layerProperties )
 
  349  , mTypeNameUTF8Len( 0 )
 
  350  , mWkbType( 
Qgis::WkbType::Unknown )
 
  351  , mGeometryAttributeUTF8Len( 0 )
 
  353  , mIsException( false )
 
  354  , mTruncatedResponse( false )
 
  356  , mFeatureTupleDepth( 0 )
 
  358  , mCurrentWKB( nullptr, 0 )
 
  359  , mBoundedByNullFound( false )
 
  361  , mCoorMode( Coordinate )
 
  363  , mAxisOrientationLogic( axisOrientationLogic )
 
  364  , mInvertAxisOrientationRequest( invertAxisOrientation )
 
  365  , mInvertAxisOrientation( invertAxisOrientation )
 
  366  , mNumberReturned( -1 )
 
  367  , mNumberMatched( -1 )
 
  368  , mFoundUnhandledGeometryElement( false )
 
  370  mThematicAttributes.clear();
 
  371  for ( 
int i = 0; i < fields.
size(); i++ )
 
  373    const QMap< QString, QPair<QString, QString> >::const_iterator att_it = fieldNameToSrcLayerNameFieldNameMap.constFind( fields.
at( i ).
name() );
 
  374    if ( att_it != fieldNameToSrcLayerNameFieldNameMap.constEnd() )
 
  376      if ( mLayerProperties.size() == 1 )
 
  377        mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
 
  379        mThematicAttributes.insert( stripNS( att_it.value().first ) + 
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
 
  382  bool alreadyFoundGeometry = 
false;
 
  383  for ( 
int i = 0; i < mLayerProperties.size(); i++ )
 
  386    if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
 
  388      if ( alreadyFoundGeometry )
 
  390        QgsDebugMsgLevel( QStringLiteral( 
"Will ignore geometry field %1 from typename %2" ).
 
  391                          arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ), 2 );
 
  392        mLayerProperties[i].mGeometryAttribute.clear();
 
  394      alreadyFoundGeometry = 
true;
 
  396    mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
 
  399  if ( mLayerProperties.size() == 1 )
 
  401    mTypeName = mLayerProperties[0].mName;
 
  402    mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
 
  403    mGeometryAttributeBA = mGeometryAttribute.toUtf8();
 
  404    mGeometryAttributePtr = mGeometryAttributeBA.constData();
 
  405    mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
 
  406    const int index = mTypeName.indexOf( 
':' );
 
  407    if ( index != -1 && index < mTypeName.length() )
 
  409      mTypeName = mTypeName.mid( index + 1 );
 
  411    mTypeNameBA = mTypeName.toUtf8();
 
  412    mTypeNamePtr = mTypeNameBA.constData();
 
  413    mTypeNameUTF8Len = strlen( mTypeNamePtr );
 
 
  423  const QMap<QString, QPair<QString, bool>> &fieldNameToXPathMapAndIsNestedContent,
 
  424  const QMap<QString, QString> &mapNamespacePrefixToURI )
 
  426  for ( 
auto iter = fieldNameToXPathMapAndIsNestedContent.constBegin(); iter != fieldNameToXPathMapAndIsNestedContent.constEnd(); ++iter )
 
  428    mMapXPathToFieldNameAndIsNestedContent[iter.value().first] = QPair<QString, bool>( iter.key(), iter.value().second );
 
  430  for ( 
auto iter = mapNamespacePrefixToURI.constBegin(); iter != mapNamespacePrefixToURI.constEnd(); ++iter )
 
  431    mMapNamespaceURIToNamespacePrefix[iter.value()] = iter.key();
 
 
  437  XML_ParserFree( mParser );
 
  440  const auto constMFeatureList = mFeatureList;
 
  443    delete featPair.first;
 
  446  delete mCurrentFeature;
 
 
  462  QByteArray data = pdata;
 
  467    QString strData = mCodec->toUnicode( pdata );
 
  468    data = strData.toUtf8();
 
  471  if ( XML_Parse( mParser, data, data.size(), atEnd ) == XML_STATUS_ERROR )
 
  473    const XML_Error errorCode = XML_GetErrorCode( mParser );
 
  474    if ( !mCodec && errorCode == XML_ERROR_UNKNOWN_ENCODING )
 
  478      const thread_local QRegularExpression reEncoding( QStringLiteral( 
"<?xml.*encoding=['\"]([^'\"]*)['\"].*?>" ),
 
  479          QRegularExpression::CaseInsensitiveOption );
 
  480      QRegularExpressionMatch match = reEncoding.match( pdata );
 
  481      const QString encoding = match.hasMatch() ? match.captured( 1 ) : QString();
 
  482      mCodec = !encoding.isEmpty() ? QTextCodec::codecForName( encoding.toLatin1() ) : 
nullptr;
 
  486        XML_ParserFree( mParser );
 
  488        createParser( QByteArrayLiteral( 
"UTF-8" ) );
 
  494    errorMsg = QObject::tr( 
"Error: %1 on line %2, column %3" )
 
  495               .arg( XML_ErrorString( errorCode ) )
 
  496               .arg( XML_GetCurrentLineNumber( mParser ) )
 
  497               .arg( XML_GetCurrentColumnNumber( mParser ) );
 
 
  507  QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
 
  508  mFeatureList.clear();
 
 
  516static json jsonFromString( 
const QString &s )
 
  521  if ( s.indexOf( 
'.' ) >= 0 || s.indexOf( 
'e' ) >= 0 )
 
  523    const auto doubleVal = s.toDouble( &conversionOk );
 
  526      return json( doubleVal );
 
  531  else if ( !s.isEmpty() && s[0] != 
'0' )
 
  533    const auto longlongVal = s.toLongLong( &conversionOk );
 
  536      return json( longlongVal );
 
  540  return json( s.toStdString() );
 
  543#define LOCALNAME_EQUALS(string_constant) \ 
  544  ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 ) 
 
  546void QgsGmlStreamingParser::startElement( 
const XML_Char *el, 
const XML_Char **attr )
 
  548  const int elLen = 
static_cast<int>( strlen( el ) );
 
  549  const char *pszSep = strchr( el, NS_SEPARATOR );
 
  550  const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
 
  551  const int nsLen = ( pszSep ) ? ( 
int )( pszSep - el ) : 0;
 
  552  const int localNameLen = ( pszSep ) ? ( 
int )( elLen - nsLen ) - 1 : elLen;
 
  553  const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
 
  557  if ( !mGMLNameSpaceURIPtr && pszSep )
 
  571  const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
 
  574  if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
 
  575       parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
 
  577    mGeometryString.append( 
"<", 1 );
 
  578    mGeometryString.append( pszLocalName, localNameLen );
 
  579    mGeometryString.append( 
" ", 1 );
 
  580    for ( 
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
 
  582      const size_t nAttrLen = strlen( attrIter[0] );
 
  585      if ( nAttrLen > GML32_NAMESPACE_LEN &&
 
  586           attrIter[0][GML32_NAMESPACE_LEN] == 
'?' &&
 
  589        mGeometryString.append( 
"gml:" );
 
  590        mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
 
  592      else if ( nAttrLen > GML_NAMESPACE_LEN &&
 
  593                attrIter[0][GML_NAMESPACE_LEN] == 
'?' &&
 
  594                memcmp( attrIter[0], 
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
 
  596        mGeometryString.append( 
"gml:" );
 
  597        mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
 
  601        mGeometryString.append( attrIter[0] );
 
  603      mGeometryString.append( 
"=\"", 2 );
 
  604      mGeometryString.append( attrIter[1] );
 
  605      mGeometryString.append( 
"\" ", 2 );
 
  608    mGeometryString.append( 
">", 1 );
 
  611  if ( !mAttributeValIsNested && isGMLNS && 
LOCALNAME_EQUALS( 
"coordinates" ) )
 
  613    mParseModeStack.push( Coordinate );
 
  614    mCoorMode = QgsGmlStreamingParser::Coordinate;
 
  616    mCoordinateSeparator = readAttribute( QStringLiteral( 
"cs" ), attr );
 
  617    if ( mCoordinateSeparator.isEmpty() )
 
  619      mCoordinateSeparator = 
',';
 
  621    mTupleSeparator = readAttribute( QStringLiteral( 
"ts" ), attr );
 
  622    if ( mTupleSeparator.isEmpty() )
 
  624      mTupleSeparator = 
' ';
 
  627  else if ( !mAttributeValIsNested && isGMLNS &&
 
  630    mParseModeStack.push( QgsGmlStreamingParser::PosList );
 
  631    mCoorMode = QgsGmlStreamingParser::PosList;
 
  633    if ( elDimension == 0 )
 
  635      const QString srsDimension = readAttribute( QStringLiteral( 
"srsDimension" ), attr );
 
  637      const int dimension = srsDimension.toInt( &ok );
 
  640        elDimension = dimension;
 
  644  else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
 
  646            localNameLen == 
static_cast<int>( mGeometryAttributeUTF8Len ) &&
 
  647            memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
 
  649    mParseModeStack.push( QgsGmlStreamingParser::Geometry );
 
  650    mFoundUnhandledGeometryElement = 
false;
 
  651    mGeometryString.clear();
 
  654  else if ( !mAttributeValIsNested && isGMLNS && 
LOCALNAME_EQUALS( 
"boundedBy" ) )
 
  656    mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
 
  658    mBoundedByNullFound = 
false;
 
  660  else if ( parseMode == BoundingBox &&
 
  663    mParseModeStack.push( QgsGmlStreamingParser::Null );
 
  664    mBoundedByNullFound = 
true;
 
  666  else if ( parseMode == BoundingBox &&
 
  670    mParseModeStack.push( QgsGmlStreamingParser::Envelope );
 
  672  else if ( parseMode == Envelope &&
 
  675    mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
 
  678  else if ( parseMode == Envelope &&
 
  681    mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
 
  684  else if ( parseMode == None && !mTypeNamePtr &&
 
  687    Q_ASSERT( !mCurrentFeature );
 
  688    mCurrentFeature = 
new QgsFeature( mFeatureCount );
 
  690    const QgsAttributes attributes( mThematicAttributes.size() ); 
 
  692    mParseModeStack.push( QgsGmlStreamingParser::Tuple );
 
  693    mCurrentFeatureId.clear();
 
  695  else if ( parseMode == Tuple )
 
  697    const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
 
  698    const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
 
  699    if ( iter != mMapTypeNameToProperties.constEnd() )
 
  701      mFeatureTupleDepth = mParseDepth;
 
  702      mCurrentTypename = currentTypename;
 
  703      mGeometryAttribute.clear();
 
  704      if ( mCurrentWKB.
size() == 0 )
 
  706        mGeometryAttribute = iter.value().mGeometryAttribute;
 
  708      mGeometryAttributeBA = mGeometryAttribute.toUtf8();
 
  709      mGeometryAttributePtr = mGeometryAttributeBA.constData();
 
  710      mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
 
  711      mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
 
  713      if ( mGMLNameSpaceURI.isEmpty() )
 
  715        id = readAttribute( QString( 
GML_NAMESPACE ) + NS_SEPARATOR + 
"id", attr );
 
  723          id = readAttribute( QString( 
GML32_NAMESPACE ) + NS_SEPARATOR + 
"id", attr );
 
  732        id = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR + 
"id", attr );
 
  733      if ( !mCurrentFeatureId.isEmpty() )
 
  734        mCurrentFeatureId += 
'|';
 
  735      mCurrentFeatureId += id;
 
  738  else if ( parseMode == None &&
 
  739            localNameLen == 
static_cast<int>( mTypeNameUTF8Len ) &&
 
  741            memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
 
  743    Q_ASSERT( !mCurrentFeature );
 
  744    mCurrentFeature = 
new QgsFeature( mFeatureCount );
 
  746    const QgsAttributes attributes( mThematicAttributes.size() ); 
 
  748    mParseModeStack.push( QgsGmlStreamingParser::Feature );
 
  749    mCurrentXPathWithinFeature.clear();
 
  750    mCurrentFeatureId = readAttribute( QStringLiteral( 
"fid" ), attr );
 
  751    if ( mCurrentFeatureId.isEmpty() )
 
  756      if ( mGMLNameSpaceURI.isEmpty() )
 
  758        mCurrentFeatureId = readAttribute( QString( 
GML_NAMESPACE ) + NS_SEPARATOR + 
"id", attr );
 
  759        if ( !mCurrentFeatureId.isEmpty() )
 
  766          mCurrentFeatureId = readAttribute( QString( 
GML32_NAMESPACE ) + NS_SEPARATOR + 
"id", attr );
 
  767          if ( !mCurrentFeatureId.isEmpty() )
 
  775        mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + NS_SEPARATOR + 
"id", attr );
 
  779  else if ( parseMode == BoundingBox && isGMLNS && 
LOCALNAME_EQUALS( 
"Box" ) )
 
  783  else if ( !mAttributeValIsNested && isGMLNS && 
LOCALNAME_EQUALS( 
"Point" ) )
 
  787  else if ( !mAttributeValIsNested && isGMLNS && 
LOCALNAME_EQUALS( 
"LineString" ) )
 
  791  else if ( !mAttributeValIsNested && isGMLNS &&
 
  792            localNameLen == 
static_cast<int>( strlen( 
"Polygon" ) ) && memcmp( pszLocalName, 
"Polygon", localNameLen ) == 0 )
 
  795    mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
 
  797  else if ( !mAttributeValIsNested && isGMLNS && 
LOCALNAME_EQUALS( 
"MultiPoint" ) )
 
  800    mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
 
  802    mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
 
  807    mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
 
  809    mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
 
  814    mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
 
  816  else if ( parseMode == FeatureTuple )
 
  818    const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
 
  819    if ( mThematicAttributes.contains( mCurrentTypename + 
'|' + localName ) )
 
  821      mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
 
  822      mAttributeName = mCurrentTypename + 
'|' + localName;
 
  826  else if ( parseMode == Feature )
 
  828    const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
 
  829    if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
 
  831      const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
 
  832      const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
 
  833      if ( !mCurrentXPathWithinFeature.isEmpty() )
 
  834        mCurrentXPathWithinFeature.append( 
'/' );
 
  835      if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
 
  837        mCurrentXPathWithinFeature.append( *nsIter );
 
  838        mCurrentXPathWithinFeature.append( 
':' );
 
  840      mCurrentXPathWithinFeature.append( localName );
 
  841      const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( mCurrentXPathWithinFeature );
 
  842      mAttributeValIsNested = 
false;
 
  843      if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
 
  845        mParseModeStack.push( QgsGmlStreamingParser::Attribute );
 
  846        mAttributeDepth = mParseDepth;
 
  847        mAttributeName = xpathIter->first;
 
  848        mAttributeValIsNested = xpathIter->second;
 
  849        if ( mAttributeValIsNested )
 
  851          mAttributeJson = json::object();
 
  852          mAttributeJsonCurrentStack.clear();
 
  853          mAttributeJsonCurrentStack.push( &mAttributeJson );
 
  858    else if ( mThematicAttributes.contains( localName ) )
 
  860      mParseModeStack.push( QgsGmlStreamingParser::Attribute );
 
  861      mAttributeDepth = mParseDepth;
 
  862      mAttributeName = localName;
 
  869      if ( localName.compare( QLatin1String( 
"attribute" ), Qt::CaseInsensitive ) == 0 )
 
  871        const QString name = readAttribute( QStringLiteral( 
"name" ), attr );
 
  872        if ( mThematicAttributes.contains( name ) )
 
  874          const QString value = readAttribute( QStringLiteral( 
"value" ), attr );
 
  875          setAttribute( name, value );
 
  880  else if ( parseMode == Attribute && mAttributeValIsNested )
 
  882    const std::string localName( pszLocalName, localNameLen );
 
  883    const QString nsURI( nsLen ? QString::fromUtf8( el, nsLen ) : QString() );
 
  884    const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
 
  885    const std::string nodeName = nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() ? ( *nsIter ).toStdString() + 
':' + localName : localName;
 
  887    addStringContentToJson();
 
  889    auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
 
  890    auto iter = jsonParent.find( nodeName );
 
  891    if ( iter != jsonParent.end() )
 
  893      if ( iter->type() != json::value_t::array )
 
  895        auto array = json::array();
 
  896        array.emplace_back( std::move( *iter ) );
 
  899      iter->push_back( json::object() );
 
  900      mAttributeJsonCurrentStack.push( &( iter->back() ) );
 
  904      auto res = jsonParent.emplace( nodeName, json::object() );
 
  908      nlohmann::json *ptr = &( *( res.first ) );
 
  910      mAttributeJsonCurrentStack.push( ptr );
 
  915    QString 
numberReturned = readAttribute( QStringLiteral( 
"numberReturned" ), attr ); 
 
  917      numberReturned = readAttribute( QStringLiteral( 
"numberOfFeatures" ), attr ); 
 
  921      mNumberReturned = -1;
 
  923    const QString 
numberMatched = readAttribute( QStringLiteral( 
"numberMatched" ), attr ); 
 
  931    mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
 
  936    mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
 
  941    mTruncatedResponse = 
true;
 
  943  else if ( !mGeometryString.empty() &&
 
  959    mFoundUnhandledGeometryElement = 
true;
 
  963  if ( !mParseModeStack.isEmpty() &&
 
  964       ( mParseModeStack.back() == Feature ||
 
  965         mParseModeStack.back() == Attribute ) &&
 
  966       !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
 
  968    for ( 
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
 
  970      const char *questionMark = strchr( attrIter[0], 
'?' );
 
  974        const QString nsURI( QString::fromUtf8( attrIter[0], 
static_cast<int>( questionMark - attrIter[0] ) ) );
 
  975        const QString localName( QString::fromUtf8( questionMark + 1 ) );
 
  976        const auto nsIter = mMapNamespaceURIToNamespacePrefix.constFind( nsURI );
 
  977        if ( nsIter != mMapNamespaceURIToNamespacePrefix.constEnd() )
 
  979          key.append( *nsIter );
 
  982        key.append( localName );
 
  986        const QString localName( QString::fromUtf8( attrIter[0] ) );
 
  987        key.append( localName );
 
  990      if ( mAttributeValIsNested && mParseModeStack.back() == Attribute )
 
  992        mAttributeJsonCurrentStack.top()->emplace(
 
  994          jsonFromString( QString::fromUtf8( attrIter[1] ) ) );
 
  998        QString xpath( mCurrentXPathWithinFeature );
 
  999        if ( !xpath.isEmpty() )
 
 1000          xpath.append( 
'/' );
 
 1001        xpath.append( key );
 
 1002        const auto xpathIter = mMapXPathToFieldNameAndIsNestedContent.constFind( xpath );
 
 1003        if ( xpathIter != mMapXPathToFieldNameAndIsNestedContent.end() )
 
 1005          setAttribute( xpathIter->first, QString::fromUtf8( attrIter[1] ) );
 
 1011  if ( !mGeometryString.empty() )
 
 1014  if ( elDimension == 0 && isGeom )
 
 1018    const QString srsDimension = readAttribute( QStringLiteral( 
"srsDimension" ), attr );
 
 1020    const int dimension = srsDimension.toInt( &ok );
 
 1023      elDimension = dimension;
 
 1027  if ( elDimension != 0 || mDimensionStack.isEmpty() )
 
 1029    mDimensionStack.push( elDimension );
 
 1033    mDimensionStack.push( mDimensionStack.back() );
 
 1036  if ( mEpsg == 0 && isGeom )
 
 1038    if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
 
 1040      QgsDebugError( QStringLiteral( 
"error, could not get epsg id" ) );
 
 1051void QgsGmlStreamingParser::endElement( 
const XML_Char *el )
 
 1055  const int elLen = 
static_cast<int>( strlen( el ) );
 
 1056  const char *pszSep = strchr( el, NS_SEPARATOR );
 
 1057  const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
 
 1058  const int nsLen = ( pszSep ) ? ( 
int )( pszSep - el ) : 0;
 
 1059  const int localNameLen = ( pszSep ) ? ( 
int )( elLen - nsLen ) - 1 : elLen;
 
 1060  const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
 
 1062  const int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
 
 1064  const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
 
 1066  if ( parseMode == Feature || ( parseMode == Attribute && mAttributeDepth == mParseDepth ) )
 
 1068    if ( !mMapXPathToFieldNameAndIsNestedContent.isEmpty() )
 
 1070      const auto nPos = mCurrentXPathWithinFeature.lastIndexOf( 
'/' );
 
 1072        mCurrentXPathWithinFeature.clear();
 
 1074        mCurrentXPathWithinFeature.resize( nPos );
 
 1078  if ( parseMode == Attribute && mAttributeValIsNested )
 
 1080    if ( !mStringCash.isEmpty() )
 
 1082      auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
 
 1083      if ( jsonParent.type() == json::value_t::object && jsonParent.empty() )
 
 1085        jsonParent = jsonFromString( mStringCash );
 
 1087      else if ( jsonParent.type() == json::value_t::object )
 
 1089        addStringContentToJson();
 
 1091      mStringCash.clear();
 
 1094    mAttributeJsonCurrentStack.pop();
 
 1097  if ( parseMode == Coordinate && isGMLNS && 
LOCALNAME_EQUALS( 
"coordinates" ) )
 
 1099    mParseModeStack.pop();
 
 1101  else if ( parseMode == PosList && isGMLNS &&
 
 1104    mDimension = lastDimension;
 
 1105    mParseModeStack.pop();
 
 1107  else if ( parseMode == AttributeTuple &&
 
 1108            mCurrentTypename + 
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName ) 
 
 1110    mParseModeStack.pop();
 
 1112    setAttribute( mAttributeName, mStringCash );
 
 1114  else if ( parseMode == Attribute && mAttributeDepth == mParseDepth ) 
 
 1116    mParseModeStack.pop();
 
 1119    if ( mAttributeValIsNested )
 
 1121      mAttributeValIsNested = 
false;
 
 1122      auto iter = mMapFieldNameToJSONContent.find( mAttributeName );
 
 1123      if ( iter == mMapFieldNameToJSONContent.end() )
 
 1125        mMapFieldNameToJSONContent[mAttributeName] = QString::fromStdString( mAttributeJson.dump() );
 
 1129        QString &
str = iter.value();
 
 1130        if ( 
str[0] == 
'[' && 
str.back() == 
']' )
 
 1136          str.insert( 0, 
'[' );
 
 1139        str.append( QString::fromStdString( mAttributeJson.dump() ) );
 
 1145      setAttribute( mAttributeName, mStringCash );
 
 1148  else if ( parseMode == Geometry &&
 
 1149            localNameLen == 
static_cast<int>( mGeometryAttributeUTF8Len ) &&
 
 1150            memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
 
 1152    mParseModeStack.pop();
 
 1153    if ( mFoundUnhandledGeometryElement )
 
 1159        const int wkbSize = OGR_G_WkbSize( hGeom.get() );
 
 1160        unsigned char *pabyBuffer = 
new unsigned char[ wkbSize ];
 
 1161        OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
 
 1163        g.
fromWkb( pabyBuffer, wkbSize );
 
 1164        if ( mInvertAxisOrientation )
 
 1166          g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
 
 1168        Q_ASSERT( mCurrentFeature );
 
 1172    mGeometryString.clear();
 
 1174  else if ( parseMode == BoundingBox && isGMLNS && 
LOCALNAME_EQUALS( 
"boundedBy" ) )
 
 1177    if ( mCurrentExtent.
isNull() &&
 
 1178         !mBoundedByNullFound &&
 
 1179         !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
 
 1181      QgsDebugError( QStringLiteral( 
"creation of bounding box failed" ) );
 
 1183    if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
 
 1184         !mCurrentFeature && mFeatureCount == 0 )
 
 1186      mLayerExtent = mCurrentExtent;
 
 1190    mParseModeStack.pop();
 
 1194    mParseModeStack.pop();
 
 1196  else if ( parseMode == Envelope && isGMLNS && 
LOCALNAME_EQUALS( 
"Envelope" ) )
 
 1198    mParseModeStack.pop();
 
 1200  else if ( parseMode == LowerCorner && isGMLNS && 
LOCALNAME_EQUALS( 
"lowerCorner" ) )
 
 1202    QList<QgsPointXY> points;
 
 1203    pointsFromPosListString( points, mStringCash, 2 );
 
 1204    if ( points.size() == 1 )
 
 1209    mParseModeStack.pop();
 
 1211  else if ( parseMode == UpperCorner && isGMLNS && 
LOCALNAME_EQUALS( 
"upperCorner" ) )
 
 1213    QList<QgsPointXY> points;
 
 1214    pointsFromPosListString( points, mStringCash, 2 );
 
 1215    if ( points.size() == 1 )
 
 1220    mParseModeStack.pop();
 
 1222  else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
 
 1224    mParseModeStack.pop();
 
 1225    mFeatureTupleDepth = 0;
 
 1227  else if ( ( parseMode == Tuple && !mTypeNamePtr &&
 
 1229            ( parseMode == Feature &&
 
 1230              localNameLen == 
static_cast<int>( mTypeNameUTF8Len ) &&
 
 1231              memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
 
 1233    Q_ASSERT( mCurrentFeature );
 
 1236      if ( mCurrentWKB.
size() > 0 )
 
 1243      else if ( !mCurrentExtent.
isEmpty() )
 
 1250    for ( 
auto iter = mMapFieldNameToJSONContent.constBegin(); iter != mMapFieldNameToJSONContent.constEnd(); ++iter )
 
 1252      const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( iter.key() );
 
 1253      const int attrIndex = att_it.value().first;
 
 1254      mCurrentFeature->
setAttribute( attrIndex, iter.value() );
 
 1256    mMapFieldNameToJSONContent.clear();
 
 1260    mCurrentFeature = 
nullptr;
 
 1262    mParseModeStack.pop();
 
 1264  else if ( !mAttributeValIsNested && isGMLNS && 
LOCALNAME_EQUALS( 
"Point" ) )
 
 1266    QList<QgsPointXY> pointList;
 
 1267    if ( pointsFromString( pointList, mStringCash ) != 0 )
 
 1272    if ( pointList.isEmpty() )
 
 1275    if ( parseMode == QgsGmlStreamingParser::Geometry )
 
 1278      if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
 
 1291      if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
 
 1295      if ( !mCurrentWKBFragments.isEmpty() )
 
 1297        mCurrentWKBFragments.last().push_back( wkbPtr );
 
 1306  else if ( !mAttributeValIsNested &&
 
 1311    QList<QgsPointXY> pointList;
 
 1312    if ( pointsFromString( pointList, mStringCash ) != 0 )
 
 1316    if ( parseMode == QgsGmlStreamingParser::Geometry )
 
 1318      if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
 
 1331      if ( getLineWKB( wkbPtr, pointList ) != 0 )
 
 1335      if ( !mCurrentWKBFragments.isEmpty() )
 
 1337        mCurrentWKBFragments.last().push_back( wkbPtr );
 
 1346  else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
 
 1349    QList<QgsPointXY> pointList;
 
 1350    if ( pointsFromString( pointList, mStringCash ) != 0 )
 
 1356    if ( getRingWKB( wkbPtr, pointList ) != 0 )
 
 1361    if ( !mCurrentWKBFragments.isEmpty() )
 
 1363      mCurrentWKBFragments.last().push_back( wkbPtr );
 
 1371  else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
 
 1379    if ( parseMode == Geometry )
 
 1381      createPolygonFromFragments();
 
 1384  else if ( parseMode == MultiPoint &&  isGMLNS &&
 
 1388    mParseModeStack.pop();
 
 1389    createMultiPointFromFragments();
 
 1391  else if ( parseMode == MultiLine && isGMLNS &&
 
 1395    mParseModeStack.pop();
 
 1396    createMultiLineFromFragments();
 
 1398  else if ( parseMode == MultiPolygon && isGMLNS &&
 
 1402    mParseModeStack.pop();
 
 1403    createMultiPolygonFromFragments();
 
 1407    mParseModeStack.pop();
 
 1409  else if ( parseMode == ExceptionText && 
LOCALNAME_EQUALS( 
"ExceptionText" ) )
 
 1411    mExceptionText = mStringCash;
 
 1412    mParseModeStack.pop();
 
 1415  if ( !mGeometryString.empty() )
 
 1417    mGeometryString.append( 
"</", 2 );
 
 1418    mGeometryString.append( pszLocalName, localNameLen );
 
 1419    mGeometryString.append( 
">", 1 );
 
 1424void QgsGmlStreamingParser::characters( 
const XML_Char *chars, 
int len )
 
 1427  if ( mParseModeStack.isEmpty() )
 
 1432  if ( !mGeometryString.empty() )
 
 1434    mGeometryString.append( chars, len );
 
 1437  const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
 
 1438  if ( parseMode == QgsGmlStreamingParser::Attribute ||
 
 1439       parseMode == QgsGmlStreamingParser::AttributeTuple ||
 
 1440       parseMode == QgsGmlStreamingParser::Coordinate ||
 
 1441       parseMode == QgsGmlStreamingParser::PosList ||
 
 1442       parseMode == QgsGmlStreamingParser::LowerCorner ||
 
 1443       parseMode == QgsGmlStreamingParser::UpperCorner ||
 
 1444       parseMode == QgsGmlStreamingParser::ExceptionText )
 
 1446    mStringCash.append( QString::fromUtf8( chars, len ) );
 
 1450void QgsGmlStreamingParser::addStringContentToJson()
 
 1452  const QString s( mStringCash.trimmed() );
 
 1455    auto &jsonParent = *( mAttributeJsonCurrentStack.top() );
 
 1456    auto textIter = jsonParent.find( 
"_text" );
 
 1457    if ( textIter != jsonParent.end() )
 
 1459      if ( textIter->type() != json::value_t::array )
 
 1461        auto array = json::array();
 
 1462        array.emplace_back( std::move( *textIter ) );
 
 1465      textIter->emplace_back( jsonFromString( s ) );
 
 1469      jsonParent.emplace( 
"_text", jsonFromString( s ) );
 
 1472  mStringCash.clear();
 
 1475void QgsGmlStreamingParser::setAttribute( 
const QString &name, 
const QString &value )
 
 1478  const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
 
 1479  bool conversionOk = 
true;
 
 1480  if ( att_it != mThematicAttributes.constEnd() )
 
 1483    switch ( att_it.value().second.type() )
 
 1485      case QMetaType::Type::Double:
 
 1486        var = QVariant( value.toDouble( &conversionOk ) );
 
 1488      case QMetaType::Type::Int:
 
 1489        var = QVariant( value.toInt( &conversionOk ) );
 
 1491      case QMetaType::Type::LongLong:
 
 1492        var = QVariant( value.toLongLong( &conversionOk ) );
 
 1494      case QMetaType::Type::QDateTime:
 
 1495        var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
 
 1498        var = QVariant( value );
 
 1501    if ( ! conversionOk )  
 
 1505    Q_ASSERT( mCurrentFeature );
 
 1506    mCurrentFeature->
setAttribute( att_it.value().first, var );
 
 1510int QgsGmlStreamingParser::readEpsgFromAttribute( 
int &epsgNr, 
const XML_Char **attr )
 
 1515    if ( strcmp( attr[i], 
"srsName" ) == 0 )
 
 1517      const QString 
srsName( attr[i + 1] );
 
 1529      const int eNr = code.toInt( &conversionOk );
 
 1530      if ( !conversionOk )
 
 1543          mInvertAxisOrientation = !mInvertAxisOrientationRequest;
 
 1554QString QgsGmlStreamingParser::readAttribute( 
const QString &attributeName, 
const XML_Char **attr )
 const 
 1559    if ( attributeName.compare( attr[i] ) == 0 )
 
 1561      return QString::fromUtf8( attr[i + 1] );
 
 1568bool QgsGmlStreamingParser::createBBoxFromCoordinateString( 
QgsRectangle &r, 
const QString &coordString )
 const 
 1570  QList<QgsPointXY> points;
 
 1571  if ( pointsFromCoordinateString( points, coordString ) != 0 )
 
 1576  if ( points.size() < 2 )
 
 1581  r.
set( points[0], points[1] );
 
 1586int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points, 
const QString &coordString )
 const 
 1589  const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
 
 1590  QStringList tuples_coordinates;
 
 1592  bool conversionSuccess;
 
 1594  QStringList::const_iterator tupleIterator;
 
 1595  for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
 
 1597    tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
 
 1598    if ( tuples_coordinates.size() < 2 )
 
 1602    x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
 
 1603    if ( !conversionSuccess )
 
 1607    y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
 
 1608    if ( !conversionSuccess )
 
 1617int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points, 
const QString &coordString, 
int dimension )
 const 
 1620  const QStringList coordinates = coordString.split( 
' ', Qt::SkipEmptyParts );
 
 1622  if ( coordinates.size() % dimension != 0 )
 
 1624    QgsDebugError( QStringLiteral( 
"Wrong number of coordinates" ) );
 
 1627  const int ncoor = coordinates.size() / dimension;
 
 1628  for ( 
int i = 0; i < ncoor; i++ )
 
 1630    bool conversionSuccess;
 
 1631    const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
 
 1632    if ( !conversionSuccess )
 
 1636    const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
 
 1637    if ( !conversionSuccess )
 
 1646int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points, 
const QString &coordString )
 const 
 1648  if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
 
 1650    return pointsFromCoordinateString( points, coordString );
 
 1652  else if ( mCoorMode == QgsGmlStreamingParser::PosList )
 
 1654    return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
 
 1661  const int wkbSize = 1 + 
sizeof( int ) + 2 * 
sizeof( 
double );
 
 1662  wkbPtr = 
QgsWkbPtr( 
new unsigned char[wkbSize], wkbSize );
 
 1670int QgsGmlStreamingParser::getLineWKB( 
QgsWkbPtr &wkbPtr, 
const QList<QgsPointXY> &lineCoordinates )
 const 
 1672  const int wkbSize = 1 + 2 * 
sizeof( int ) + lineCoordinates.size() * 2 * 
sizeof( double );
 
 1673  wkbPtr = 
QgsWkbPtr( 
new unsigned char[wkbSize], wkbSize );
 
 1679  QList<QgsPointXY>::const_iterator iter;
 
 1680  for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
 
 1682    fillPtr << iter->x() << iter->y();
 
 1688int QgsGmlStreamingParser::getRingWKB( 
QgsWkbPtr &wkbPtr, 
const QList<QgsPointXY> &ringCoordinates )
 const 
 1690  const int wkbSize = 
sizeof( int ) + ringCoordinates.size() * 2 * 
sizeof( double );
 
 1691  wkbPtr = 
QgsWkbPtr( 
new unsigned char[wkbSize], wkbSize );
 
 1695  fillPtr << ringCoordinates.size();
 
 1697  QList<QgsPointXY>::const_iterator iter;
 
 1698  for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
 
 1700    fillPtr << iter->x() << iter->y();
 
 1706int QgsGmlStreamingParser::createMultiLineFromFragments()
 
 1708  const int size = 1 + 2 * 
sizeof( int ) + totalWKBFragmentSize();
 
 1709  mCurrentWKB = 
QgsWkbPtr( 
new unsigned char[size], size );
 
 1716  QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
 
 1717  for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
 
 1719    memcpy( wkbPtr, *wkbIt, wkbIt->size() );
 
 1720    wkbPtr += wkbIt->
size();
 
 1724  mCurrentWKBFragments.clear();
 
 1729int QgsGmlStreamingParser::createMultiPointFromFragments()
 
 1731  const int size = 1 + 2 * 
sizeof( int ) + totalWKBFragmentSize();
 
 1732  mCurrentWKB = 
QgsWkbPtr( 
new unsigned char[size], size );
 
 1737  QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
 
 1738  for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
 
 1740    memcpy( wkbPtr, *wkbIt, wkbIt->size() );
 
 1741    wkbPtr += wkbIt->
size();
 
 1745  mCurrentWKBFragments.clear();
 
 1751int QgsGmlStreamingParser::createPolygonFromFragments()
 
 1753  const int size = 1 + 2 * 
sizeof( int ) + totalWKBFragmentSize();
 
 1754  mCurrentWKB = 
QgsWkbPtr( 
new unsigned char[size], size );
 
 1759  QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
 
 1760  for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
 
 1762    memcpy( wkbPtr, *wkbIt, wkbIt->size() );
 
 1763    wkbPtr += wkbIt->
size();
 
 1767  mCurrentWKBFragments.clear();
 
 1772int QgsGmlStreamingParser::createMultiPolygonFromFragments()
 
 1775  size += 1 + 2 * 
sizeof( int );
 
 1776  size += totalWKBFragmentSize();
 
 1777  size += mCurrentWKBFragments.size() * ( 1 + 2 * 
sizeof( int ) ); 
 
 1779  mCurrentWKB = 
QgsWkbPtr( 
new unsigned char[size], size );
 
 1785  QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
 
 1787  for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
 
 1792    QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
 
 1793    for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
 
 1795      memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
 
 1796      wkbPtr += innerWkbIt->
size();
 
 1797      delete[] *innerWkbIt;
 
 1801  mCurrentWKBFragments.clear();
 
 1806int QgsGmlStreamingParser::totalWKBFragmentSize()
 const 
 1809  const auto constMCurrentWKBFragments = mCurrentWKBFragments;
 
 1810  for ( 
const QList<QgsWkbPtr> &list : constMCurrentWKBFragments )
 
 1812    const auto constList = list;
 
 1821void QgsGmlStreamingParser::createParser( 
const QByteArray &encoding )
 
 1823  Q_ASSERT( !mParser );
 
 1825  mParser = XML_ParserCreateNS( encoding.isEmpty() ? 
nullptr : encoding.data(), NS_SEPARATOR );
 
 1826  XML_SetUserData( mParser, 
this );
 
 1827  XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
 
 1828  XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
 
The Qgis class provides global constants 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.
 
This class 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)
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 class to represent a 2D point.
 
A rectangle specified with double values.
 
void setYMinimum(double y)
Set the minimum y value.
 
void setXMinimum(double x)
Set the minimum x value.
 
bool isNull() const
Test if the rectangle is null (holding no spatial information).
 
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.
 
bool isEmpty() const
Returns true if the rectangle has no area.
 
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