Skip to content
Permalink
Browse files
Fixed GML parsing of GetFeatureInfo from GeoServer, fixes part of #9377
  • Loading branch information
blazek committed Feb 12, 2014
1 parent 9d379f0 commit 4d660d14cfb54e8c8b19fb24109ba7104cfe1073
Showing with 137 additions and 10 deletions.
  1. +91 −5 src/core/qgsgml.cpp
  2. +21 −1 src/core/qgsgml.h
  3. +11 −3 src/core/qgsgmlschema.cpp
  4. +1 −0 src/core/qgsgmlschema.h
  5. +13 −1 src/providers/wms/qgswmsprovider.cpp
@@ -44,6 +44,7 @@ QgsGml::QgsGml(
, mCurrentFeature( 0 )
, mFeatureCount( 0 )
, mCurrentWKBSize( 0 )
, mEpsg( 0 )
{
mThematicAttributes.clear();
for ( int i = 0; i < fields.size(); i++ )
@@ -207,6 +208,7 @@ void QgsGml::startElement( const XML_Char* el, const XML_Char** attr )
if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "coordinates" )
{
mParseModeStack.push( QgsGml::coordinate );
mCoorMode = QgsGml::coordinate;
mStringCash.clear();
mCoordinateSeparator = readAttribute( "cs", attr );
if ( mCoordinateSeparator.isEmpty() )
@@ -219,6 +221,20 @@ void QgsGml::startElement( const XML_Char* el, const XML_Char** attr )
mTupleSeparator = " ";
}
}
if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "pos"
|| elementName == GML_NAMESPACE + NS_SEPARATOR + "posList" )
{
mParseModeStack.push( QgsGml::posList );
mCoorMode = QgsGml::posList;
mStringCash.clear();
QString dimension = readAttribute( "srsDimension", attr );
bool ok;
mDimension = dimension.toInt( &ok );
if ( dimension.isEmpty() || !ok )
{
mDimension = 2;
}
}
else if ( localName == mGeometryAttribute )
{
mParseModeStack.push( QgsGml::geometry );
@@ -276,6 +292,21 @@ void QgsGml::startElement( const XML_Char* el, const XML_Char** attr )
mAttributeName = localName;
mStringCash.clear();
}


if ( mEpsg == 0 && ( localName == "Point" || localName == "MultiPoint" ||
localName == "LineString" || localName == "MultiLineString" ||
localName == "Polygon" || localName == "MultiPolygon" ) )
{
if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
{
QgsDebugMsg( "error, could not get epsg id" );
}
else
{
QgsDebugMsg( QString( "mEpsg = %1" ).arg( mEpsg ) );
}
}
}

void QgsGml::endElement( const XML_Char* el )
@@ -286,7 +317,10 @@ void QgsGml::endElement( const XML_Char* el )
QString localName = splitName.last();
QString ns = splitName.size() > 1 ? splitName.first() : "";

if ( theParseMode == coordinate && elementName == GML_NAMESPACE + NS_SEPARATOR + "coordinates" )
if (( theParseMode == coordinate && elementName == GML_NAMESPACE + NS_SEPARATOR + "coordinates" )
|| ( theParseMode == posList && (
elementName == GML_NAMESPACE + NS_SEPARATOR + "posList"
|| elementName == GML_NAMESPACE + NS_SEPARATOR + "posList" ) ) )
{
mParseModeStack.pop();
}
@@ -361,7 +395,7 @@ void QgsGml::endElement( const XML_Char* el )
else if ( elementName == GML_NAMESPACE + NS_SEPARATOR + "Point" )
{
QList<QgsPoint> pointList;
if ( pointsFromCoordinateString( pointList, mStringCash ) != 0 )
if ( pointsFromString( pointList, mStringCash ) != 0 )
{
//error
}
@@ -405,7 +439,7 @@ void QgsGml::endElement( const XML_Char* el )
//add WKB point to the feature

QList<QgsPoint> pointList;
if ( pointsFromCoordinateString( pointList, mStringCash ) != 0 )
if ( pointsFromString( pointList, mStringCash ) != 0 )
{
//error
}
@@ -445,7 +479,7 @@ void QgsGml::endElement( const XML_Char* el )
else if (( theParseMode == geometry || theParseMode == multiPolygon ) && elementName == GML_NAMESPACE + NS_SEPARATOR + "LinearRing" )
{
QList<QgsPoint> pointList;
if ( pointsFromCoordinateString( pointList, mStringCash ) != 0 )
if ( pointsFromString( pointList, mStringCash ) != 0 )
{
//error
}
@@ -506,7 +540,7 @@ void QgsGml::characters( const XML_Char* chars, int len )
}

QgsGml::ParseMode theParseMode = mParseModeStack.top();
if ( theParseMode == QgsGml::attribute || theParseMode == QgsGml::coordinate )
if ( theParseMode == QgsGml::attribute || theParseMode == QgsGml::coordinate || theParseMode == QgsGml::posList )
{
mStringCash.append( QString::fromUtf8( chars, len ) );
}
@@ -606,6 +640,48 @@ int QgsGml::pointsFromCoordinateString( QList<QgsPoint>& points, const QString&
return 0;
}

int QgsGml::pointsFromPosListString( QList<QgsPoint>& points, const QString& coordString, int dimension ) const
{
// coordinates separated by spaces
QStringList coordinates = coordString.split( " ", QString::SkipEmptyParts );

if ( coordinates.size() % dimension != 0 )
{
QgsDebugMsg( "Wrong number of coordinates" );
}

int ncoor = coordinates.size() / dimension;
for ( int i = 0; i < ncoor; i++ )
{
bool conversionSuccess;
double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
if ( !conversionSuccess )
{
continue;
}
double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
if ( !conversionSuccess )
{
continue;
}
points.append( QgsPoint( x, y ) );
}
return 0;
}

int QgsGml::pointsFromString( QList<QgsPoint>& points, const QString& coordString ) const
{
if ( mCoorMode == QgsGml::coordinate )
{
return pointsFromCoordinateString( points, coordString );
}
else if ( mCoorMode == QgsGml::posList )
{
return pointsFromPosListString( points, coordString, mDimension );
}
return 1;
}

int QgsGml::getPointWKB( unsigned char** wkb, int* size, const QgsPoint& point ) const
{
int wkbSize = 1 + sizeof( int ) + 2 * sizeof( double );
@@ -884,3 +960,13 @@ void QgsGml::calculateExtentFromFeatures()
}
}
}

QgsCoordinateReferenceSystem QgsGml::crs() const
{
QgsCoordinateReferenceSystem crs;
if ( mEpsg != 0 )
{
crs.createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( mEpsg ) );
}
return crs;
}
@@ -18,6 +18,7 @@
#include <expat.h>
#include "qgis.h"
#include "qgsapplication.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsdataprovider.h"
#include "qgsfeature.h"
#include "qgsfield.h"
@@ -32,7 +33,6 @@
#include <QStack>

class QgsRectangle;
class QgsCoordinateReferenceSystem;

/**This class reads data from a WFS server or alternatively from a GML file. It
* uses the expat XML parser and an event based model to keep performance high.
@@ -69,6 +69,10 @@ class CORE_EXPORT QgsGml : public QObject
/** Get feature ids map */
QMap<QgsFeatureId, QString > idsMap() const { return mIdMap; }

/** Returns features spatial reference system
@note Added in QGIS 2.1 */
QgsCoordinateReferenceSystem crs() const;

private slots:

void setFinished();
@@ -92,6 +96,7 @@ class CORE_EXPORT QgsGml : public QObject
attribute,
geometry,
coordinate,
posList,
multiPoint,
multiLine,
multiPolygon
@@ -138,6 +143,15 @@ class CORE_EXPORT QgsGml : public QObject
*/
int pointsFromCoordinateString( QList<QgsPoint>& points, const QString& coordString ) const;

/**Creates a set of points from a gml:posList or gml:pos coordinate string.
@param points list that will contain the created points
@param coordString the text containing the coordinates
@parem dimension number of dimensions
@return 0 in case of success
*/
int pointsFromPosListString( QList<QgsPoint>& points, const QString& coordString, int dimension ) const;

int pointsFromString( QList<QgsPoint>& points, const QString& coordString ) const;
int getPointWKB( unsigned char** wkb, int* size, const QgsPoint& ) const;
int getLineWKB( unsigned char** wkb, int* size, const QList<QgsPoint>& lineCoordinates ) const;
int getRingWKB( unsigned char** wkb, int* size, const QList<QgsPoint>& ringCoordinates ) const;
@@ -215,6 +229,12 @@ class CORE_EXPORT QgsGml : public QObject
QString mCoordinateSeparator;
/**Tuple separator for coordinate strings. Usually " " */
QString mTupleSeparator;
/** Number of dimensions in pos or posList */
int mDimension;
/** Coordinates mode, coordinate or posList */
ParseMode mCoorMode;
/** EPSG of parsed features geometries */
int mEpsg;
};

#endif
@@ -380,6 +380,10 @@ void QgsGmlSchema::startElement( const XML_Char* el, const XML_Char** attr )
// gml:boundedBy in feature or feature collection -> skip
mSkipLevel = mLevel + 1;
}
else if ( localName.compare( "featureMembers", Qt::CaseInsensitive ) == 0 )
{
mParseModeStack.push( QgsGmlSchema::featureMembers );
}
// GML does not specify that gml:FeatureAssociationType elements should end
// with 'Member' apart standard gml:featureMember, but it is quite usual to
// that the names ends with 'Member', e.g.: osgb:topographicMember, cityMember,...
@@ -396,7 +400,8 @@ void QgsGmlSchema::startElement( const XML_Char* el, const XML_Char** attr )
// UMN Mapserver simple GetFeatureInfo response feature element (ends with _feature)
// or featureMember children
else if ( elementName.endsWith( "_feature" )
|| parseMode == QgsGmlSchema::featureMember )
|| parseMode == QgsGmlSchema::featureMember
|| parseMode == QgsGmlSchema::featureMembers )
{
//QgsDebugMsg ( "is feature path = " + path );
if ( mFeatureClassMap.count( localName ) == 0 )
@@ -449,7 +454,11 @@ void QgsGmlSchema::endElement( const XML_Char* el )

QgsGmlSchema::ParseMode parseMode = modeStackTop();

if ( parseMode == QgsGmlSchema::attribute && localName == mAttributeName )
if ( parseMode == QgsGmlSchema::featureMembers )
{
modeStackPop();
}
else if ( parseMode == QgsGmlSchema::attribute && localName == mAttributeName )
{
// End of attribute
//QgsDebugMsg("end attribute");
@@ -500,7 +509,6 @@ void QgsGmlSchema::endElement( const XML_Char* el )
}
else if ( localName.endsWith( "member", Qt::CaseInsensitive ) )
{
mParseModeStack.push( QgsGmlSchema::featureMember );
modeStackPop();
}
mParsePathStack.removeLast();
@@ -108,6 +108,7 @@ class CORE_EXPORT QgsGmlSchema : public QObject
{
none,
boundingBox,
featureMembers, // gml:featureMembers
featureMember, // gml:featureMember
feature, // feature element containint attrs and geo (inside gml:featureMember)
attribute,
@@ -33,6 +33,7 @@
#include "qgscoordinatetransform.h"
#include "qgsdatasourceuri.h"
#include "qgsfeaturestore.h"
#include "qgsgeometry.h"
#include "qgsrasteridentifyresult.h"
#include "qgsrasterlayer.h"
#include "qgsrectangle.h"
@@ -4549,7 +4550,13 @@ QgsRasterIdentifyResult QgsWmsProvider::identify( const QgsPoint & thePoint, Qgs
// the same as this layer, because layerExtentToOutputExtent() may be used
// for results -> verify CRS and reprojects if necessary
QMap<QgsFeatureId, QgsFeature* > features = gml.featuresMap();
QgsDebugMsg( QString( "%1 features read" ).arg( features.size() ) );
QgsCoordinateReferenceSystem featuresCrs = gml.crs();
QgsDebugMsg( QString( "%1 features read, crs: %2 %3" ).arg( features.size() ).arg( featuresCrs.authid() ).arg( featuresCrs.description() ) );
QgsCoordinateTransform *coordinateTransform = 0;
if ( featuresCrs.isValid() && featuresCrs != crs() )
{
coordinateTransform = new QgsCoordinateTransform( featuresCrs, crs() );
}
QgsFeatureStore featureStore( fields, crs() );
QMap<QString, QVariant> params;
params.insert( "sublayer", *layers );
@@ -4562,9 +4569,14 @@ QgsRasterIdentifyResult QgsWmsProvider::identify( const QgsPoint & thePoint, Qgs

QgsDebugMsg( QString( "feature id = %1 : %2 attributes" ).arg( id ).arg( feature->attributes().size() ) );

if ( coordinateTransform && feature->geometry() )
{
feature->geometry()->transform( *coordinateTransform );
}
featureStore.features().append( QgsFeature( *feature ) );
}
featureStoreList.append( featureStore );
delete coordinateTransform;
}
results.insert( count, qVariantFromValue( featureStoreList ) );
}

0 comments on commit 4d660d1

Please sign in to comment.