LCOV - code coverage report
Current view: top level - core - qgsgmlschema.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 298 0.0 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :      qgsgmlschema.cpp
       3                 :            :      --------------------------------------
       4                 :            :     Date                 : February 2013
       5                 :            :     Copyright            : (C) 2013 by Radim Blazek
       6                 :            :     Email                : radim.blazek@gmail.com
       7                 :            :  ***************************************************************************
       8                 :            :  *                                                                         *
       9                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      10                 :            :  *   it under the terms of the GNU General Public License as published by  *
      11                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      12                 :            :  *   (at your option) any later version.                                   *
      13                 :            :  *                                                                         *
      14                 :            :  ***************************************************************************/
      15                 :            : #include "qgsgmlschema.h"
      16                 :            : #include "qgsrectangle.h"
      17                 :            : #include "qgscoordinatereferencesystem.h"
      18                 :            : #include "qgserror.h"
      19                 :            : #include "qgsgeometry.h"
      20                 :            : #include "qgslogger.h"
      21                 :            : #include "qgsnetworkaccessmanager.h"
      22                 :            : #include <QBuffer>
      23                 :            : #include <QList>
      24                 :            : #include <QNetworkRequest>
      25                 :            : #include <QNetworkReply>
      26                 :            : #include <QProgressDialog>
      27                 :            : #include <QSet>
      28                 :            : #include <QSettings>
      29                 :            : #include <QUrl>
      30                 :            : 
      31                 :            : #include <limits>
      32                 :            : 
      33                 :            : const char NS_SEPARATOR = '?';
      34                 :            : #define GML_NAMESPACE QStringLiteral( "http://www.opengis.net/gml" )
      35                 :            : 
      36                 :            : 
      37                 :          0 : QgsGmlFeatureClass::QgsGmlFeatureClass( const QString &name, const QString &path )
      38                 :          0 :   : mName( name )
      39                 :          0 :   , mPath( path )
      40                 :            : {
      41                 :          0 : }
      42                 :            : 
      43                 :          0 : int QgsGmlFeatureClass::fieldIndex( const QString &name )
      44                 :            : {
      45                 :          0 :   for ( int i = 0; i < mFields.size(); i++ )
      46                 :            :   {
      47                 :          0 :     if ( mFields[i].name() == name ) return i;
      48                 :          0 :   }
      49                 :          0 :   return -1;
      50                 :          0 : }
      51                 :            : 
      52                 :            : // --------------------------- QgsGmlSchema -------------------------------
      53                 :          0 : QgsGmlSchema::QgsGmlSchema()
      54                 :          0 :   : mSkipLevel( std::numeric_limits<int>::max() )
      55                 :          0 : {
      56                 :          0 :   mGeometryTypes << QStringLiteral( "Point" ) << QStringLiteral( "MultiPoint" )
      57                 :          0 :                  << QStringLiteral( "LineString" ) << QStringLiteral( "MultiLineString" )
      58                 :          0 :                  << QStringLiteral( "Polygon" ) << QStringLiteral( "MultiPolygon" );
      59                 :          0 : }
      60                 :            : 
      61                 :          0 : QString QgsGmlSchema::readAttribute( const QString &attributeName, const XML_Char **attr ) const
      62                 :            : {
      63                 :          0 :   int i = 0;
      64                 :          0 :   while ( attr[i] )
      65                 :            :   {
      66                 :          0 :     if ( attributeName.compare( attr[i] ) == 0 )
      67                 :            :     {
      68                 :          0 :       return QString( attr[i + 1] );
      69                 :            :     }
      70                 :          0 :     i += 2;
      71                 :            :   }
      72                 :          0 :   return QString();
      73                 :          0 : }
      74                 :            : 
      75                 :          0 : bool QgsGmlSchema::parseXSD( const QByteArray &xml )
      76                 :            : {
      77                 :          0 :   QDomDocument dom;
      78                 :          0 :   QString errorMsg;
      79                 :            :   int errorLine;
      80                 :            :   int errorColumn;
      81                 :          0 :   if ( !dom.setContent( xml, false, &errorMsg, &errorLine, &errorColumn ) )
      82                 :            :   {
      83                 :            :     // TODO: error
      84                 :          0 :     return false;
      85                 :            :   }
      86                 :            : 
      87                 :          0 :   QDomElement docElem = dom.documentElement();
      88                 :            : 
      89                 :          0 :   QList<QDomElement> elementElements = domElements( docElem, QStringLiteral( "element" ) );
      90                 :            : 
      91                 :            :   //QgsDebugMsg( QStringLiteral( "%1 elements read" ).arg( elementElements.size() ) );
      92                 :            : 
      93                 :          0 :   const auto constElementElements = elementElements;
      94                 :          0 :   for ( const QDomElement &elementElement : constElementElements )
      95                 :            :   {
      96                 :          0 :     QString name = elementElement.attribute( QStringLiteral( "name" ) );
      97                 :          0 :     QString type = elementElement.attribute( QStringLiteral( "type" ) );
      98                 :            : 
      99                 :          0 :     QString gmlBaseType = xsdComplexTypeGmlBaseType( docElem, stripNS( type ) );
     100                 :            :     //QgsDebugMsg( QStringLiteral( "gmlBaseType = %1" ).arg( gmlBaseType ) );
     101                 :            :     //QgsDebugMsg( QStringLiteral( "name = %1 gmlBaseType = %2" ).arg( name ).arg( gmlBaseType ) );
     102                 :            :     // We should only use gml:AbstractFeatureType descendants which have
     103                 :            :     // ancestor listed in gml:FeatureAssociationType (featureMember) descendant
     104                 :            :     // But we could only loose some data if XSD was not correct, I think.
     105                 :            : 
     106                 :          0 :     if ( gmlBaseType == QLatin1String( "AbstractFeatureType" ) )
     107                 :            :     {
     108                 :            :       // Get feature type definition
     109                 :          0 :       QgsGmlFeatureClass featureClass( name, QString() );
     110                 :          0 :       xsdFeatureClass( docElem, stripNS( type ), featureClass );
     111                 :          0 :       mFeatureClassMap.insert( name, featureClass );
     112                 :          0 :     }
     113                 :            :     // A feature may have more geometries, we take just the first one
     114                 :          0 :   }
     115                 :            : 
     116                 :          0 :   return true;
     117                 :          0 : }
     118                 :            : 
     119                 :          0 : bool QgsGmlSchema::xsdFeatureClass( const QDomElement &element, const QString &typeName, QgsGmlFeatureClass &featureClass )
     120                 :            : {
     121                 :            :   //QgsDebugMsg("typeName = " + typeName );
     122                 :          0 :   QDomElement complexTypeElement = domElement( element, QStringLiteral( "complexType" ), QStringLiteral( "name" ), typeName );
     123                 :          0 :   if ( complexTypeElement.isNull() ) return false;
     124                 :            : 
     125                 :            :   // extension or restriction
     126                 :          0 :   QDomElement extrest = domElement( complexTypeElement, QStringLiteral( "complexContent.extension" ) );
     127                 :          0 :   if ( extrest.isNull() )
     128                 :            :   {
     129                 :          0 :     extrest = domElement( complexTypeElement, QStringLiteral( "complexContent.restriction" ) );
     130                 :          0 :   }
     131                 :          0 :   if ( extrest.isNull() ) return false;
     132                 :            : 
     133                 :          0 :   QString extrestName = extrest.attribute( QStringLiteral( "base" ) );
     134                 :          0 :   if ( extrestName == QLatin1String( "gml:AbstractFeatureType" ) )
     135                 :            :   {
     136                 :            :     // In theory we should add gml:AbstractFeatureType default attributes gml:description
     137                 :            :     // and gml:name but it does not seem to be a common practice and we would probably
     138                 :            :     // confuse most users
     139                 :          0 :   }
     140                 :            :   else
     141                 :            :   {
     142                 :            :     // Get attributes from extrest
     143                 :          0 :     if ( !xsdFeatureClass( element, stripNS( extrestName ), featureClass ) ) return false;
     144                 :            :   }
     145                 :            : 
     146                 :            :   // Supported geometry types
     147                 :          0 :   QStringList geometryPropertyTypes;
     148                 :          0 :   const auto constMGeometryTypes = mGeometryTypes;
     149                 :          0 :   for ( const QString &geom : constMGeometryTypes )
     150                 :            :   {
     151                 :          0 :     geometryPropertyTypes << geom + "PropertyType";
     152                 :            :   }
     153                 :            : 
     154                 :          0 :   QStringList geometryAliases;
     155                 :          0 :   geometryAliases << QStringLiteral( "location" ) << QStringLiteral( "centerOf" ) << QStringLiteral( "position" ) << QStringLiteral( "extentOf" )
     156                 :          0 :                   << QStringLiteral( "coverage" ) << QStringLiteral( "edgeOf" ) << QStringLiteral( "centerLineOf" ) << QStringLiteral( "multiLocation" )
     157                 :          0 :                   << QStringLiteral( "multiCenterOf" ) << QStringLiteral( "multiPosition" ) << QStringLiteral( "multiCenterLineOf" )
     158                 :          0 :                   << QStringLiteral( "multiEdgeOf" ) << QStringLiteral( "multiCoverage" ) << QStringLiteral( "multiExtentOf" );
     159                 :            : 
     160                 :            :   // Add attributes from current comple type
     161                 :          0 :   QList<QDomElement> sequenceElements = domElements( extrest, QStringLiteral( "sequence.element" ) );
     162                 :          0 :   const auto constSequenceElements = sequenceElements;
     163                 :          0 :   for ( const QDomElement &sequenceElement : constSequenceElements )
     164                 :            :   {
     165                 :          0 :     QString fieldName = sequenceElement.attribute( QStringLiteral( "name" ) );
     166                 :          0 :     QString fieldTypeName = stripNS( sequenceElement.attribute( QStringLiteral( "type" ) ) );
     167                 :          0 :     QString ref = sequenceElement.attribute( QStringLiteral( "ref" ) );
     168                 :            :     //QgsDebugMsg ( QString("fieldName = %1 fieldTypeName = %2 ref = %3").arg(fieldName).arg(fieldTypeName).arg(ref) );
     169                 :            : 
     170                 :          0 :     if ( !ref.isEmpty() )
     171                 :            :     {
     172                 :          0 :       if ( ref.startsWith( QLatin1String( "gml:" ) ) )
     173                 :            :       {
     174                 :          0 :         if ( geometryAliases.contains( stripNS( ref ) ) )
     175                 :            :         {
     176                 :          0 :           featureClass.geometryAttributes().append( stripNS( ref ) );
     177                 :          0 :         }
     178                 :            :         else
     179                 :            :         {
     180                 :          0 :           QgsDebugMsg( QStringLiteral( "Unknown referenced GML element: %1" ).arg( ref ) );
     181                 :            :         }
     182                 :          0 :       }
     183                 :            :       else
     184                 :            :       {
     185                 :            :         // TODO: get type from referenced element
     186                 :          0 :         QgsDebugMsg( QStringLiteral( "field %1.%2 is referencing %3 - not supported" ).arg( typeName, fieldName ) );
     187                 :            :       }
     188                 :          0 :       continue;
     189                 :            :     }
     190                 :            : 
     191                 :          0 :     if ( fieldName.isEmpty() )
     192                 :            :     {
     193                 :          0 :       QgsDebugMsg( QStringLiteral( "field in %1 without name" ).arg( typeName ) );
     194                 :          0 :       continue;
     195                 :            :     }
     196                 :            : 
     197                 :          0 :     // type is either type attribute
     198                 :          0 :     if ( fieldTypeName.isEmpty() )
     199                 :          0 :     {
     200                 :            :       // or type is inheriting from xs:simpleType
     201                 :          0 :       QDomElement sequenceElementRestriction = domElement( sequenceElement, QStringLiteral( "simpleType.restriction" ) );
     202                 :          0 :       fieldTypeName = stripNS( sequenceElementRestriction.attribute( QStringLiteral( "base" ) ) );
     203                 :          0 :     }
     204                 :            : 
     205                 :          0 :     QVariant::Type fieldType = QVariant::String;
     206                 :          0 :     if ( fieldTypeName.isEmpty() )
     207                 :            :     {
     208                 :          0 :       QgsDebugMsg( QStringLiteral( "Cannot get %1.%2 field type" ).arg( typeName, fieldName ) );
     209                 :          0 :     }
     210                 :            :     else
     211                 :            :     {
     212                 :          0 :       if ( geometryPropertyTypes.contains( fieldTypeName ) )
     213                 :            :       {
     214                 :            :         // Geometry attribute
     215                 :          0 :         featureClass.geometryAttributes().append( fieldName );
     216                 :          0 :         continue;
     217                 :            :       }
     218                 :            : 
     219                 :          0 :       if ( fieldTypeName == QLatin1String( "decimal" ) )
     220                 :            :       {
     221                 :          0 :         fieldType = QVariant::Double;
     222                 :          0 :       }
     223                 :          0 :       else if ( fieldTypeName == QLatin1String( "integer" ) )
     224                 :            :       {
     225                 :          0 :         fieldType = QVariant::Int;
     226                 :          0 :       }
     227                 :            :     }
     228                 :            : 
     229                 :          0 :     QgsField field( fieldName, fieldType, fieldTypeName );
     230                 :          0 :     featureClass.fields().append( field );
     231                 :          0 :   }
     232                 :            : 
     233                 :          0 :   return true;
     234                 :          0 : }
     235                 :            : 
     236                 :          0 : QString QgsGmlSchema::xsdComplexTypeGmlBaseType( const QDomElement &element, const QString &name )
     237                 :            : {
     238                 :            :   //QgsDebugMsg("name = " + name );
     239                 :          0 :   QDomElement complexTypeElement = domElement( element, QStringLiteral( "complexType" ), QStringLiteral( "name" ), name );
     240                 :          0 :   if ( complexTypeElement.isNull() ) return QString();
     241                 :            : 
     242                 :          0 :   QDomElement extrest = domElement( complexTypeElement, QStringLiteral( "complexContent.extension" ) );
     243                 :          0 :   if ( extrest.isNull() )
     244                 :            :   {
     245                 :          0 :     extrest = domElement( complexTypeElement, QStringLiteral( "complexContent.restriction" ) );
     246                 :          0 :   }
     247                 :          0 :   if ( extrest.isNull() ) return QString();
     248                 :            : 
     249                 :          0 :   QString extrestName = extrest.attribute( QStringLiteral( "base" ) );
     250                 :          0 :   if ( extrestName.startsWith( QLatin1String( "gml:" ) ) )
     251                 :            :   {
     252                 :            :     // GML base type found
     253                 :          0 :     return stripNS( extrestName );
     254                 :            :   }
     255                 :            :   // Continue recursively until GML base type is reached
     256                 :          0 :   return xsdComplexTypeGmlBaseType( element, stripNS( extrestName ) );
     257                 :          0 : }
     258                 :            : 
     259                 :          0 : QString QgsGmlSchema::stripNS( const QString &name )
     260                 :            : {
     261                 :          0 :   return name.contains( ':' ) ? name.section( ':', 1 ) : name;
     262                 :            : }
     263                 :            : 
     264                 :          0 : QList<QDomElement> QgsGmlSchema::domElements( const QDomElement &element, const QString &path )
     265                 :            : {
     266                 :          0 :   QList<QDomElement> list;
     267                 :            : 
     268                 :          0 :   QStringList names = path.split( '.' );
     269                 :          0 :   if ( names.isEmpty() ) return list;
     270                 :          0 :   QString name = names.value( 0 );
     271                 :          0 :   names.removeFirst();
     272                 :            : 
     273                 :          0 :   QDomNode n1 = element.firstChild();
     274                 :          0 :   while ( !n1.isNull() )
     275                 :            :   {
     276                 :          0 :     QDomElement el = n1.toElement();
     277                 :          0 :     if ( !el.isNull() )
     278                 :            :     {
     279                 :          0 :       QString tagName = stripNS( el.tagName() );
     280                 :          0 :       if ( tagName == name )
     281                 :            :       {
     282                 :          0 :         if ( names.isEmpty() )
     283                 :            :         {
     284                 :          0 :           list.append( el );
     285                 :          0 :         }
     286                 :            :         else
     287                 :            :         {
     288                 :          0 :           list.append( domElements( el, names.join( QLatin1Char( '.' ) ) ) );
     289                 :            :         }
     290                 :          0 :       }
     291                 :          0 :     }
     292                 :          0 :     n1 = n1.nextSibling();
     293                 :          0 :   }
     294                 :            : 
     295                 :          0 :   return list;
     296                 :          0 : }
     297                 :            : 
     298                 :          0 : QDomElement QgsGmlSchema::domElement( const QDomElement &element, const QString &path )
     299                 :            : {
     300                 :          0 :   return domElements( element, path ).value( 0 );
     301                 :          0 : }
     302                 :            : 
     303                 :          0 : QList<QDomElement> QgsGmlSchema::domElements( QList<QDomElement> &elements, const QString &attr, const QString &attrVal )
     304                 :            : {
     305                 :          0 :   QList<QDomElement> list;
     306                 :          0 :   const auto constElements = elements;
     307                 :          0 :   for ( const QDomElement &el : constElements )
     308                 :            :   {
     309                 :          0 :     if ( el.attribute( attr ) == attrVal )
     310                 :            :     {
     311                 :          0 :       list << el;
     312                 :          0 :     }
     313                 :            :   }
     314                 :          0 :   return list;
     315                 :          0 : }
     316                 :            : 
     317                 :          0 : QDomElement QgsGmlSchema::domElement( const QDomElement &element, const QString &path, const QString &attr, const QString &attrVal )
     318                 :            : {
     319                 :          0 :   QList<QDomElement> list = domElements( element, path );
     320                 :          0 :   return domElements( list, attr, attrVal ).value( 0 );
     321                 :          0 : }
     322                 :            : 
     323                 :          0 : bool QgsGmlSchema::guessSchema( const QByteArray &data )
     324                 :            : {
     325                 :          0 :   mLevel = 0;
     326                 :          0 :   mSkipLevel = std::numeric_limits<int>::max();
     327                 :          0 :   XML_Parser p = XML_ParserCreateNS( nullptr, NS_SEPARATOR );
     328                 :          0 :   XML_SetUserData( p, this );
     329                 :          0 :   XML_SetElementHandler( p, QgsGmlSchema::start, QgsGmlSchema::end );
     330                 :          0 :   XML_SetCharacterDataHandler( p, QgsGmlSchema::chars );
     331                 :          0 :   int atEnd = 1;
     332                 :          0 :   int res = XML_Parse( p, data.constData(), data.size(), atEnd );
     333                 :            : 
     334                 :          0 :   if ( res == 0 )
     335                 :            :   {
     336                 :          0 :     QString err = QString( XML_ErrorString( XML_GetErrorCode( p ) ) );
     337                 :          0 :     QgsDebugMsg( QStringLiteral( "XML_Parse returned %1 error %2" ).arg( res ).arg( err ) );
     338                 :          0 :     mError = QgsError( err, QStringLiteral( "GML schema" ) );
     339                 :          0 :     mError.append( tr( "Cannot guess schema" ) );
     340                 :          0 :   }
     341                 :            : 
     342                 :          0 :   return res != 0;
     343                 :          0 : }
     344                 :            : 
     345                 :          0 : void QgsGmlSchema::startElement( const XML_Char *el, const XML_Char **attr )
     346                 :            : {
     347                 :            :   Q_UNUSED( attr )
     348                 :          0 :   mLevel++;
     349                 :            : 
     350                 :          0 :   QString elementName = QString::fromUtf8( el );
     351                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "-> %1 %2 %3" ).arg( mLevel ).arg( elementName, mLevel >= mSkipLevel ? "skip" : "" ), 5 );
     352                 :            : 
     353                 :          0 :   if ( mLevel >= mSkipLevel )
     354                 :            :   {
     355                 :            :     //QgsDebugMsg( QStringLiteral("skip level %1").arg( mLevel ) );
     356                 :          0 :     return;
     357                 :            :   }
     358                 :            : 
     359                 :          0 :   mParsePathStack.append( elementName );
     360                 :          0 :   QString path = mParsePathStack.join( QLatin1Char( '.' ) );
     361                 :            : 
     362                 :          0 :   QStringList splitName = elementName.split( NS_SEPARATOR );
     363                 :          0 :   QString localName = splitName.last();
     364                 :          0 :   QString ns = splitName.size() > 1 ? splitName.first() : QString();
     365                 :            :   //QgsDebugMsg( "ns = " + ns + " localName = " + localName );
     366                 :            : 
     367                 :          0 :   ParseMode parseMode = modeStackTop();
     368                 :            :   //QgsDebugMsg ( QString("localName = %1 parseMode = %2").arg(localName).arg(parseMode) );
     369                 :            : 
     370                 :          0 :   if ( ns == GML_NAMESPACE && localName == QLatin1String( "boundedBy" ) )
     371                 :            :   {
     372                 :            :     // gml:boundedBy in feature or feature collection -> skip
     373                 :          0 :     mSkipLevel = mLevel + 1;
     374                 :          0 :   }
     375                 :          0 :   else if ( localName.compare( QLatin1String( "featureMembers" ), Qt::CaseInsensitive ) == 0 )
     376                 :            :   {
     377                 :          0 :     mParseModeStack.push( QgsGmlSchema::FeatureMembers );
     378                 :          0 :   }
     379                 :            :   // GML does not specify that gml:FeatureAssociationType elements should end
     380                 :            :   // with 'Member' apart standard gml:featureMember, but it is quite usual to
     381                 :            :   // that the names ends with 'Member', e.g.: osgb:topographicMember, cityMember,...
     382                 :            :   // so this is really fail if the name does not contain 'Member'
     383                 :            : 
     384                 :          0 :   else if ( localName.endsWith( QLatin1String( "member" ), Qt::CaseInsensitive ) )
     385                 :            :   {
     386                 :          0 :     mParseModeStack.push( QgsGmlSchema::FeatureMember );
     387                 :          0 :   }
     388                 :            :   // UMN Mapserver simple GetFeatureInfo response layer element (ends with _layer)
     389                 :          0 :   else if ( elementName.endsWith( QLatin1String( "_layer" ) ) )
     390                 :            :   {
     391                 :            :     // do nothing, we catch _feature children
     392                 :          0 :   }
     393                 :            :   // UMN Mapserver simple GetFeatureInfo response feature element (ends with _feature)
     394                 :            :   // or featureMember children.
     395                 :            :   // QGIS mapserver 2.2 GetFeatureInfo is using <Feature id="###"> for feature member,
     396                 :            :   // without any feature class distinction.
     397                 :          0 :   else if ( elementName.endsWith( QLatin1String( "_feature" ) )
     398                 :          0 :             || parseMode == QgsGmlSchema::FeatureMember
     399                 :          0 :             || parseMode == QgsGmlSchema::FeatureMembers
     400                 :          0 :             || localName.compare( QLatin1String( "feature" ), Qt::CaseInsensitive ) == 0 )
     401                 :            :   {
     402                 :          0 :     QgsDebugMsg( "is feature path = " + path );
     403                 :          0 :     if ( mFeatureClassMap.count( localName ) == 0 )
     404                 :            :     {
     405                 :          0 :       mFeatureClassMap.insert( localName, QgsGmlFeatureClass( localName, path ) );
     406                 :          0 :     }
     407                 :          0 :     mCurrentFeatureName = localName;
     408                 :          0 :     mParseModeStack.push( QgsGmlSchema::Feature );
     409                 :          0 :   }
     410                 :          0 :   else if ( parseMode == QgsGmlSchema::Attribute && ns == GML_NAMESPACE && mGeometryTypes.indexOf( localName ) >= 0 )
     411                 :            :   {
     412                 :            :     // Geometry (Point,MultiPoint,...) in geometry attribute
     413                 :          0 :     QStringList &geometryAttributes = mFeatureClassMap[mCurrentFeatureName].geometryAttributes();
     414                 :          0 :     if ( geometryAttributes.count( mAttributeName ) == 0 )
     415                 :            :     {
     416                 :          0 :       geometryAttributes.append( mAttributeName );
     417                 :          0 :     }
     418                 :          0 :     mSkipLevel = mLevel + 1; // no need to parse children
     419                 :          0 :   }
     420                 :          0 :   else if ( parseMode == QgsGmlSchema::Feature )
     421                 :            :   {
     422                 :            :     // An element in feature should be ordinary or geometry attribute
     423                 :            :     //QgsDebugMsg( "is attribute");
     424                 :            : 
     425                 :            :     // Usually localName is attribute name, e.g.
     426                 :            :     // <gml:desc>My description</gml:desc>
     427                 :            :     // but QGIS server (2.2) is using:
     428                 :            :     // <Attribute value="My description" name="desc"/>
     429                 :          0 :     QString name = readAttribute( QStringLiteral( "name" ), attr );
     430                 :            :     //QgsDebugMsg ( "attribute name = " + name );
     431                 :          0 :     if ( localName.compare( QLatin1String( "attribute" ), Qt::CaseInsensitive ) == 0
     432                 :          0 :          && !name.isEmpty() )
     433                 :            :     {
     434                 :          0 :       QString value = readAttribute( QStringLiteral( "value" ), attr );
     435                 :            :       //QgsDebugMsg ( "attribute value = " + value );
     436                 :          0 :       addAttribute( name, value );
     437                 :          0 :     }
     438                 :            :     else
     439                 :            :     {
     440                 :          0 :       mAttributeName = localName;
     441                 :          0 :       mParseModeStack.push( QgsGmlSchema::Attribute );
     442                 :          0 :       mStringCash.clear();
     443                 :            :     }
     444                 :          0 :   }
     445                 :          0 : }
     446                 :            : 
     447                 :          0 : void QgsGmlSchema::endElement( const XML_Char *el )
     448                 :            : {
     449                 :          0 :   QString elementName = QString::fromUtf8( el );
     450                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "<- %1 %2" ).arg( mLevel ).arg( elementName ), 5 );
     451                 :            : 
     452                 :          0 :   if ( mLevel >= mSkipLevel )
     453                 :            :   {
     454                 :            :     //QgsDebugMsg( QStringLiteral("skip level %1").arg( mLevel ) );
     455                 :          0 :     mLevel--;
     456                 :          0 :     return;
     457                 :            :   }
     458                 :            :   else
     459                 :            :   {
     460                 :            :     // clear possible skip level
     461                 :          0 :     mSkipLevel = std::numeric_limits<int>::max();
     462                 :            :   }
     463                 :            : 
     464                 :          0 :   QStringList splitName = elementName.split( NS_SEPARATOR );
     465                 :          0 :   QString localName = splitName.last();
     466                 :          0 :   QString ns = splitName.size() > 1 ? splitName.first() : QString();
     467                 :            : 
     468                 :          0 :   QgsGmlSchema::ParseMode parseMode = modeStackTop();
     469                 :            : 
     470                 :          0 :   if ( parseMode == QgsGmlSchema::FeatureMembers )
     471                 :            :   {
     472                 :          0 :     modeStackPop();
     473                 :          0 :   }
     474                 :          0 :   else if ( parseMode == QgsGmlSchema::Attribute && localName == mAttributeName )
     475                 :            :   {
     476                 :            :     // End of attribute
     477                 :            :     //QgsDebugMsg("end attribute");
     478                 :          0 :     modeStackPop(); // go up to feature
     479                 :            : 
     480                 :          0 :     if ( mFeatureClassMap[mCurrentFeatureName].geometryAttributes().count( mAttributeName ) == 0 )
     481                 :            :     {
     482                 :          0 :       addAttribute( mAttributeName, mStringCash );
     483                 :          0 :     }
     484                 :          0 :   }
     485                 :          0 :   else if ( ns == GML_NAMESPACE && localName == QLatin1String( "boundedBy" ) )
     486                 :            :   {
     487                 :            :     // was skipped
     488                 :          0 :   }
     489                 :          0 :   else if ( localName.endsWith( QLatin1String( "member" ), Qt::CaseInsensitive ) )
     490                 :            :   {
     491                 :          0 :     modeStackPop();
     492                 :          0 :   }
     493                 :          0 :   mParsePathStack.removeLast();
     494                 :          0 :   mLevel--;
     495                 :          0 : }
     496                 :            : 
     497                 :          0 : void QgsGmlSchema::characters( const XML_Char *chars, int len )
     498                 :            : {
     499                 :            :   //QgsDebugMsg( QStringLiteral("level %1 : %2").arg( mLevel ).arg( QString::fromUtf8( chars, len ) ) );
     500                 :          0 :   if ( mLevel >= mSkipLevel )
     501                 :            :   {
     502                 :            :     //QgsDebugMsg( QStringLiteral("skip level %1").arg( mLevel ) );
     503                 :          0 :     return;
     504                 :            :   }
     505                 :            : 
     506                 :            :   //save chars in mStringCash attribute mode for value type analysis
     507                 :          0 :   if ( modeStackTop() == QgsGmlSchema::Attribute )
     508                 :            :   {
     509                 :          0 :     mStringCash.append( QString::fromUtf8( chars, len ) );
     510                 :          0 :   }
     511                 :          0 : }
     512                 :            : 
     513                 :          0 : void QgsGmlSchema::addAttribute( const QString &name, const QString &value )
     514                 :            : {
     515                 :            :   // It is not geometry attribute -> analyze value
     516                 :            :   bool ok;
     517                 :          0 :   ( void ) value.toInt( &ok );
     518                 :          0 :   QVariant::Type type = QVariant::String;
     519                 :          0 :   if ( ok )
     520                 :            :   {
     521                 :          0 :     type = QVariant::Int;
     522                 :          0 :   }
     523                 :            :   else
     524                 :            :   {
     525                 :          0 :     ( void ) value.toDouble( &ok );
     526                 :          0 :     if ( ok )
     527                 :            :     {
     528                 :          0 :       type = QVariant::Double;
     529                 :          0 :     }
     530                 :            :   }
     531                 :            :   //QgsDebugMsg( "mStringCash = " + mStringCash + " type = " + QVariant::typeToName( type )  );
     532                 :            :   //QMap<QString, QgsField> & fields = mFeatureClassMap[mCurrentFeatureName].fields();
     533                 :          0 :   QList<QgsField> &fields = mFeatureClassMap[mCurrentFeatureName].fields();
     534                 :          0 :   int fieldIndex = mFeatureClassMap[mCurrentFeatureName].fieldIndex( name );
     535                 :          0 :   if ( fieldIndex == -1 )
     536                 :            :   {
     537                 :          0 :     QgsField field( name, type );
     538                 :          0 :     fields.append( field );
     539                 :          0 :   }
     540                 :            :   else
     541                 :            :   {
     542                 :          0 :     QgsField &field = fields[fieldIndex];
     543                 :            :     // check if type is sufficient
     544                 :          0 :     if ( ( field.type() == QVariant::Int && ( type == QVariant::String || type == QVariant::Double ) ) ||
     545                 :          0 :          ( field.type() == QVariant::Double && type == QVariant::String ) )
     546                 :            :     {
     547                 :          0 :       field.setType( type );
     548                 :          0 :     }
     549                 :            :   }
     550                 :          0 : }
     551                 :            : 
     552                 :          0 : QStringList QgsGmlSchema::typeNames() const
     553                 :            : {
     554                 :          0 :   return mFeatureClassMap.keys();
     555                 :            : }
     556                 :            : 
     557                 :          0 : QList<QgsField> QgsGmlSchema::fields( const QString &typeName )
     558                 :            : {
     559                 :          0 :   if ( mFeatureClassMap.count( typeName ) == 0 ) return QList<QgsField>();
     560                 :          0 :   return mFeatureClassMap[typeName].fields();
     561                 :          0 : }
     562                 :            : 
     563                 :          0 : QStringList QgsGmlSchema::geometryAttributes( const QString &typeName )
     564                 :            : {
     565                 :          0 :   if ( mFeatureClassMap.count( typeName ) == 0 ) return QStringList();
     566                 :          0 :   return mFeatureClassMap[typeName].geometryAttributes();
     567                 :          0 : }

Generated by: LCOV version 1.14