mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-15 00:02:52 -04:00
[FEATURE]: Add WFS support for QGIS server. Provided by René-Luc D'Hont
This commit is contained in:
parent
a2ee769957
commit
c27c89045c
@ -175,7 +175,7 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa
|
||||
twIdentifyLayers->setCellWidget( i, 2, cb );
|
||||
}
|
||||
|
||||
grpWMSServiceCapabilities->setChecked( QgsProject::instance()->readBoolEntry( "WMSServiceCapabilities", "/", false ) );
|
||||
grpOWSServiceCapabilities->setChecked( QgsProject::instance()->readBoolEntry( "WMSServiceCapabilities", "/", false ) );
|
||||
mWMSTitle->setText( QgsProject::instance()->readEntry( "WMSServiceTitle", "/" ) );
|
||||
mWMSContactOrganization->setText( QgsProject::instance()->readEntry( "WMSContactOrganization", "/", "" ) );
|
||||
mWMSContactPerson->setText( QgsProject::instance()->readEntry( "WMSContactPerson", "/", "" ) );
|
||||
@ -229,6 +229,38 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa
|
||||
bool addWktGeometry = QgsProject::instance()->readBoolEntry( "WMSAddWktGeometry", "/" );
|
||||
mAddWktGeometryCheckBox->setChecked( addWktGeometry );
|
||||
|
||||
QStringList wfsLayerIdList = QgsProject::instance()->readListEntry( "WFSLayers", "/" );
|
||||
|
||||
twWFSLayers->setColumnCount( 2 );
|
||||
twWFSLayers->horizontalHeader()->setVisible( true );
|
||||
twWFSLayers->setRowCount( mapLayers.size() );
|
||||
|
||||
i = 0;
|
||||
int j = 0;
|
||||
for ( QMap<QString, QgsMapLayer*>::const_iterator it = mapLayers.constBegin(); it != mapLayers.constEnd(); it++, i++ )
|
||||
{
|
||||
currentLayer = it.value();
|
||||
if ( currentLayer->type() == QgsMapLayer::VectorLayer )
|
||||
{
|
||||
|
||||
QTableWidgetItem *twi = new QTableWidgetItem( QString::number( j ) );
|
||||
twWFSLayers->setVerticalHeaderItem( j, twi );
|
||||
|
||||
twi = new QTableWidgetItem( currentLayer->name() );
|
||||
twi->setData( Qt::UserRole, it.key() );
|
||||
twi->setFlags( twi->flags() & ~Qt::ItemIsEditable );
|
||||
twWFSLayers->setItem( j, 0, twi );
|
||||
|
||||
QCheckBox *cb = new QCheckBox();
|
||||
cb->setChecked( wfsLayerIdList.contains( currentLayer->id() ) );
|
||||
twWFSLayers->setCellWidget( j, 1, cb );
|
||||
j++;
|
||||
|
||||
}
|
||||
}
|
||||
twWFSLayers->setRowCount( j );
|
||||
twWFSLayers->verticalHeader()->setResizeMode( QHeaderView::ResizeToContents );
|
||||
|
||||
restoreState();
|
||||
}
|
||||
|
||||
@ -380,7 +412,7 @@ void QgsProjectProperties::apply()
|
||||
|
||||
QgsProject::instance()->writeEntry( "Identify", "/disabledLayers", noIdentifyLayerList );
|
||||
|
||||
QgsProject::instance()->writeEntry( "WMSServiceCapabilities", "/", grpWMSServiceCapabilities->isChecked() );
|
||||
QgsProject::instance()->writeEntry( "WMSServiceCapabilities", "/", grpOWSServiceCapabilities->isChecked() );
|
||||
QgsProject::instance()->writeEntry( "WMSServiceTitle", "/", mWMSTitle->text() );
|
||||
QgsProject::instance()->writeEntry( "WMSContactOrganization", "/", mWMSContactOrganization->text() );
|
||||
QgsProject::instance()->writeEntry( "WMSContactPerson", "/", mWMSContactPerson->text() );
|
||||
@ -428,6 +460,18 @@ void QgsProjectProperties::apply()
|
||||
|
||||
QgsProject::instance()->writeEntry( "WMSAddWktGeometry", "/", mAddWktGeometryCheckBox->isChecked() );
|
||||
|
||||
QStringList wfsLayerList;
|
||||
for ( int i = 0; i < twWFSLayers->rowCount(); i++ )
|
||||
{
|
||||
QCheckBox *cb = qobject_cast<QCheckBox *>( twWFSLayers->cellWidget( i, 1 ) );
|
||||
if ( cb && cb->isChecked() )
|
||||
{
|
||||
QString id = twWFSLayers->item( i, 0 )->data( Qt::UserRole ).toString();
|
||||
wfsLayerList << id;
|
||||
}
|
||||
}
|
||||
QgsProject::instance()->writeEntry( "WFSLayers", "/", wfsLayerList );
|
||||
|
||||
//todo XXX set canvas color
|
||||
emit refresh();
|
||||
}
|
||||
|
@ -4185,6 +4185,296 @@ QString QgsGeometry::exportToWkt()
|
||||
}
|
||||
}
|
||||
|
||||
QString QgsGeometry::exportToGeoJSON()
|
||||
{
|
||||
QgsDebugMsg( "entered." );
|
||||
|
||||
// TODO: implement with GEOS
|
||||
if ( mDirtyWkb )
|
||||
{
|
||||
exportGeosToWkb();
|
||||
}
|
||||
|
||||
if ( !mGeometry )
|
||||
{
|
||||
QgsDebugMsg( "WKB geometry not available!" );
|
||||
return QString::null;
|
||||
}
|
||||
|
||||
QGis::WkbType wkbType;
|
||||
bool hasZValue = false;
|
||||
double *x, *y;
|
||||
|
||||
QString mWkt; // TODO: rename
|
||||
|
||||
// Will this really work when mGeometry[0] == 0 ???? I (gavin) think not.
|
||||
//wkbType = (mGeometry[0] == 1) ? mGeometry[1] : mGeometry[4];
|
||||
memcpy( &wkbType, &( mGeometry[1] ), sizeof( int ) );
|
||||
|
||||
switch ( wkbType )
|
||||
{
|
||||
case QGis::WKBPoint25D:
|
||||
case QGis::WKBPoint:
|
||||
{
|
||||
mWkt += "{ \"type\": \"Point\", \"coordinates\": [";
|
||||
x = ( double * )( mGeometry + 5 );
|
||||
mWkt += QString::number( *x, 'f', 6 );
|
||||
mWkt += ", ";
|
||||
y = ( double * )( mGeometry + 5 + sizeof( double ) );
|
||||
mWkt += QString::number( *y, 'f', 6 );
|
||||
mWkt += "] }";
|
||||
return mWkt;
|
||||
}
|
||||
|
||||
case QGis::WKBLineString25D:
|
||||
hasZValue = true;
|
||||
case QGis::WKBLineString:
|
||||
{
|
||||
QgsDebugMsg( "LINESTRING found" );
|
||||
unsigned char *ptr;
|
||||
int *nPoints;
|
||||
int idx;
|
||||
|
||||
mWkt += "{ \"type\": \"LineString\", \"coordinates\": [ ";
|
||||
// get number of points in the line
|
||||
ptr = mGeometry + 5;
|
||||
nPoints = ( int * ) ptr;
|
||||
ptr = mGeometry + 1 + 2 * sizeof( int );
|
||||
for ( idx = 0; idx < *nPoints; ++idx )
|
||||
{
|
||||
if ( idx != 0 )
|
||||
{
|
||||
mWkt += ", ";
|
||||
}
|
||||
mWkt += "[";
|
||||
x = ( double * ) ptr;
|
||||
mWkt += QString::number( *x, 'f', 6 );
|
||||
mWkt += ", ";
|
||||
ptr += sizeof( double );
|
||||
y = ( double * ) ptr;
|
||||
mWkt += QString::number( *y, 'f', 6 );
|
||||
ptr += sizeof( double );
|
||||
if ( hasZValue )
|
||||
{
|
||||
ptr += sizeof( double );
|
||||
}
|
||||
mWkt += "]";
|
||||
}
|
||||
mWkt += " ] }";
|
||||
return mWkt;
|
||||
}
|
||||
|
||||
case QGis::WKBPolygon25D:
|
||||
hasZValue = true;
|
||||
case QGis::WKBPolygon:
|
||||
{
|
||||
QgsDebugMsg( "POLYGON found" );
|
||||
unsigned char *ptr;
|
||||
int idx, jdx;
|
||||
int *numRings, *nPoints;
|
||||
|
||||
mWkt += "{ \"type\": \"Polygon\", \"coordinates\": [ ";
|
||||
// get number of rings in the polygon
|
||||
numRings = ( int * )( mGeometry + 1 + sizeof( int ) );
|
||||
if ( !( *numRings ) ) // sanity check for zero rings in polygon
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
int *ringStart; // index of first point for each ring
|
||||
int *ringNumPoints; // number of points in each ring
|
||||
ringStart = new int[*numRings];
|
||||
ringNumPoints = new int[*numRings];
|
||||
ptr = mGeometry + 1 + 2 * sizeof( int ); // set pointer to the first ring
|
||||
for ( idx = 0; idx < *numRings; idx++ )
|
||||
{
|
||||
if ( idx != 0 )
|
||||
{
|
||||
mWkt += ", ";
|
||||
}
|
||||
mWkt += "[ ";
|
||||
// get number of points in the ring
|
||||
nPoints = ( int * ) ptr;
|
||||
ringNumPoints[idx] = *nPoints;
|
||||
ptr += 4;
|
||||
|
||||
for ( jdx = 0; jdx < *nPoints; jdx++ )
|
||||
{
|
||||
if ( jdx != 0 )
|
||||
{
|
||||
mWkt += ", ";
|
||||
}
|
||||
mWkt += "[";
|
||||
x = ( double * ) ptr;
|
||||
mWkt += QString::number( *x, 'f', 6 );
|
||||
mWkt += ", ";
|
||||
ptr += sizeof( double );
|
||||
y = ( double * ) ptr;
|
||||
mWkt += QString::number( *y, 'f', 6 );
|
||||
ptr += sizeof( double );
|
||||
if ( hasZValue )
|
||||
{
|
||||
ptr += sizeof( double );
|
||||
}
|
||||
mWkt += "]";
|
||||
}
|
||||
mWkt += " ]";
|
||||
}
|
||||
mWkt += " ] }";
|
||||
delete [] ringStart;
|
||||
delete [] ringNumPoints;
|
||||
return mWkt;
|
||||
}
|
||||
|
||||
case QGis::WKBMultiPoint25D:
|
||||
hasZValue = true;
|
||||
case QGis::WKBMultiPoint:
|
||||
{
|
||||
unsigned char *ptr;
|
||||
int idx;
|
||||
int *nPoints;
|
||||
|
||||
mWkt += "{ \"type\": \"MultiPoint\", \"coordinates\": [ ";
|
||||
nPoints = ( int* )( mGeometry + 5 );
|
||||
ptr = mGeometry + 5 + sizeof( int );
|
||||
for ( idx = 0; idx < *nPoints; ++idx )
|
||||
{
|
||||
ptr += ( 1 + sizeof( int ) );
|
||||
if ( idx != 0 )
|
||||
{
|
||||
mWkt += ", ";
|
||||
}
|
||||
mWkt += "[";
|
||||
x = ( double * )( ptr );
|
||||
mWkt += QString::number( *x, 'f', 6 );
|
||||
mWkt += ", ";
|
||||
ptr += sizeof( double );
|
||||
y = ( double * )( ptr );
|
||||
mWkt += QString::number( *y, 'f', 6 );
|
||||
ptr += sizeof( double );
|
||||
if ( hasZValue )
|
||||
{
|
||||
ptr += sizeof( double );
|
||||
}
|
||||
mWkt += "]";
|
||||
}
|
||||
mWkt += " ] }";
|
||||
return mWkt;
|
||||
}
|
||||
|
||||
case QGis::WKBMultiLineString25D:
|
||||
hasZValue = true;
|
||||
case QGis::WKBMultiLineString:
|
||||
{
|
||||
QgsDebugMsg( "MULTILINESTRING found" );
|
||||
unsigned char *ptr;
|
||||
int idx, jdx, numLineStrings;
|
||||
int *nPoints;
|
||||
|
||||
mWkt += "{ \"type\": \"MultiLineString\", \"coordinates\": [ ";
|
||||
numLineStrings = ( int )( mGeometry[5] );
|
||||
ptr = mGeometry + 9;
|
||||
for ( jdx = 0; jdx < numLineStrings; jdx++ )
|
||||
{
|
||||
if ( jdx != 0 )
|
||||
{
|
||||
mWkt += ", ";
|
||||
}
|
||||
mWkt += "[ ";
|
||||
ptr += 5; // skip type since we know its 2
|
||||
nPoints = ( int * ) ptr;
|
||||
ptr += sizeof( int );
|
||||
for ( idx = 0; idx < *nPoints; idx++ )
|
||||
{
|
||||
if ( idx != 0 )
|
||||
{
|
||||
mWkt += ", ";
|
||||
}
|
||||
mWkt += "[";
|
||||
x = ( double * ) ptr;
|
||||
mWkt += QString::number( *x, 'f', 6 );
|
||||
ptr += sizeof( double );
|
||||
mWkt += ", ";
|
||||
y = ( double * ) ptr;
|
||||
mWkt += QString::number( *y, 'f', 6 );
|
||||
ptr += sizeof( double );
|
||||
if ( hasZValue )
|
||||
{
|
||||
ptr += sizeof( double );
|
||||
}
|
||||
mWkt += "]";
|
||||
}
|
||||
mWkt += " ]";
|
||||
}
|
||||
mWkt += " ] }";
|
||||
return mWkt;
|
||||
}
|
||||
|
||||
case QGis::WKBMultiPolygon25D:
|
||||
hasZValue = true;
|
||||
case QGis::WKBMultiPolygon:
|
||||
{
|
||||
QgsDebugMsg( "MULTIPOLYGON found" );
|
||||
unsigned char *ptr;
|
||||
int idx, jdx, kdx;
|
||||
int *numPolygons, *numRings, *nPoints;
|
||||
|
||||
mWkt += "{ \"type\": \"MultiPolygon\", \"coordinates\": [ ";
|
||||
ptr = mGeometry + 5;
|
||||
numPolygons = ( int * ) ptr;
|
||||
ptr = mGeometry + 9;
|
||||
for ( kdx = 0; kdx < *numPolygons; kdx++ )
|
||||
{
|
||||
if ( kdx != 0 )
|
||||
{
|
||||
mWkt += ", ";
|
||||
}
|
||||
mWkt += "[ ";
|
||||
ptr += 5;
|
||||
numRings = ( int * ) ptr;
|
||||
ptr += 4;
|
||||
for ( idx = 0; idx < *numRings; idx++ )
|
||||
{
|
||||
if ( idx != 0 )
|
||||
{
|
||||
mWkt += ", ";
|
||||
}
|
||||
mWkt += "[ ";
|
||||
nPoints = ( int * ) ptr;
|
||||
ptr += 4;
|
||||
for ( jdx = 0; jdx < *nPoints; jdx++ )
|
||||
{
|
||||
if ( jdx != 0 )
|
||||
{
|
||||
mWkt += ", ";
|
||||
}
|
||||
mWkt += "[";
|
||||
x = ( double * ) ptr;
|
||||
mWkt += QString::number( *x, 'f', 6 );
|
||||
ptr += sizeof( double );
|
||||
mWkt += ", ";
|
||||
y = ( double * ) ptr;
|
||||
mWkt += QString::number( *y, 'f', 6 );
|
||||
ptr += sizeof( double );
|
||||
if ( hasZValue )
|
||||
{
|
||||
ptr += sizeof( double );
|
||||
}
|
||||
mWkt += "]";
|
||||
}
|
||||
mWkt += " ]";
|
||||
}
|
||||
mWkt += " ]";
|
||||
}
|
||||
mWkt += " ] }";
|
||||
return mWkt;
|
||||
}
|
||||
|
||||
default:
|
||||
QgsDebugMsg( "error: mGeometry type not recognized" );
|
||||
return QString::null;
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsGeometry::exportWkbToGeos()
|
||||
{
|
||||
QgsDebugMsgLevel( "entered.", 3 );
|
||||
|
@ -361,6 +361,11 @@ class CORE_EXPORT QgsGeometry
|
||||
*/
|
||||
QString exportToWkt();
|
||||
|
||||
/** Exports the geometry to mGeoJSON
|
||||
@return true in case of success and false else
|
||||
*/
|
||||
QString exportToGeoJSON();
|
||||
|
||||
/* Accessor functions for getting geometry data */
|
||||
|
||||
/** return contents of the geometry as a point
|
||||
|
@ -28,6 +28,7 @@ SET ( qgis_mapserv_SRCS
|
||||
qgssldparser.cpp
|
||||
qgssldrenderer.cpp
|
||||
qgswmsserver.cpp
|
||||
qgswfsserver.cpp
|
||||
qgsmapserviceexception.cpp
|
||||
qgsmslayercache.cpp
|
||||
qgsfilter.cpp
|
||||
|
@ -26,6 +26,7 @@ map service syntax for SOAP/HTTP POST
|
||||
#include "qgsproviderregistry.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgswmsserver.h"
|
||||
#include "qgswfsserver.h"
|
||||
#include "qgsmaprenderer.h"
|
||||
#include "qgsmapserviceexception.h"
|
||||
#include "qgsprojectparser.h"
|
||||
@ -264,24 +265,124 @@ int main( int argc, char * argv[] )
|
||||
|
||||
//request to WMS?
|
||||
QString serviceString;
|
||||
#ifndef QGISDEBUG
|
||||
serviceString = parameterMap.value( "SERVICE", "WMS" );
|
||||
#else
|
||||
paramIt = parameterMap.find( "SERVICE" );
|
||||
if ( paramIt == parameterMap.constEnd() )
|
||||
{
|
||||
#ifndef QGISDEBUG
|
||||
serviceString = parameterMap.value( "SERVICE", "WMS" );
|
||||
#else
|
||||
QgsDebugMsg( "unable to find 'SERVICE' parameter, exiting..." );
|
||||
theRequestHandler->sendServiceException( QgsMapServiceException( "ServiceNotSpecified", "Service not specified. The SERVICE parameter is mandatory" ) );
|
||||
delete theRequestHandler;
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
serviceString = paramIt.value();
|
||||
}
|
||||
#endif
|
||||
|
||||
QgsWMSServer* theServer = 0;
|
||||
if ( serviceString == "WFS" )
|
||||
{
|
||||
delete theServer;
|
||||
QgsWFSServer* theServer = 0;
|
||||
try
|
||||
{
|
||||
theServer = new QgsWFSServer( parameterMap );
|
||||
}
|
||||
catch ( QgsMapServiceException e ) //admin.sld may be invalid
|
||||
{
|
||||
theRequestHandler->sendServiceException( e );
|
||||
continue;
|
||||
}
|
||||
|
||||
theServer->setAdminConfigParser( adminConfigParser );
|
||||
|
||||
|
||||
//request type
|
||||
QString request = parameterMap.value( "REQUEST" );
|
||||
if ( request.isEmpty() )
|
||||
{
|
||||
//do some error handling
|
||||
QgsDebugMsg( "unable to find 'REQUEST' parameter, exiting..." );
|
||||
theRequestHandler->sendServiceException( QgsMapServiceException( "OperationNotSupported", "Please check the value of the REQUEST parameter" ) );
|
||||
delete theRequestHandler;
|
||||
delete theServer;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( request == "GetCapabilities" )
|
||||
{
|
||||
QDomDocument capabilitiesDocument;
|
||||
try
|
||||
{
|
||||
capabilitiesDocument = theServer->getCapabilities();
|
||||
}
|
||||
catch ( QgsMapServiceException& ex )
|
||||
{
|
||||
theRequestHandler->sendServiceException( ex );
|
||||
delete theRequestHandler;
|
||||
delete theServer;
|
||||
continue;
|
||||
}
|
||||
QgsDebugMsg( "sending GetCapabilities response" );
|
||||
theRequestHandler->sendGetCapabilitiesResponse( capabilitiesDocument );
|
||||
delete theRequestHandler;
|
||||
delete theServer;
|
||||
continue;
|
||||
}
|
||||
else if ( request == "DescribeFeatureType" )
|
||||
{
|
||||
QDomDocument describeDocument;
|
||||
try
|
||||
{
|
||||
describeDocument = theServer->describeFeatureType();
|
||||
}
|
||||
catch ( QgsMapServiceException& ex )
|
||||
{
|
||||
theRequestHandler->sendServiceException( ex );
|
||||
delete theRequestHandler;
|
||||
delete theServer;
|
||||
continue;
|
||||
}
|
||||
QgsDebugMsg( "sending GetCapabilities response" );
|
||||
theRequestHandler->sendGetCapabilitiesResponse( describeDocument );
|
||||
delete theRequestHandler;
|
||||
delete theServer;
|
||||
continue;
|
||||
}
|
||||
else if ( request == "GetFeature" )
|
||||
{
|
||||
//output format for GetFeature
|
||||
QString outputFormat = parameterMap.value( "OUTPUTFORMAT" );
|
||||
try
|
||||
{
|
||||
if ( theServer->getFeature( *theRequestHandler, outputFormat ) != 0 )
|
||||
{
|
||||
delete theRequestHandler;
|
||||
delete theServer;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete theRequestHandler;
|
||||
delete theServer;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch ( QgsMapServiceException& ex )
|
||||
{
|
||||
theRequestHandler->sendServiceException( ex );
|
||||
delete theRequestHandler;
|
||||
delete theServer;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
theServer = new QgsWMSServer( parameterMap, theMapRenderer );
|
||||
|
@ -42,6 +42,8 @@ class QgsConfigParser
|
||||
/**Adds layer and style specific capabilities elements to the parent node. This includes the individual layers and styles, their description, native CRS, bounding boxes, etc.*/
|
||||
virtual void layersAndStylesCapabilities( QDomElement& parentElement, QDomDocument& doc ) const = 0;
|
||||
|
||||
virtual void featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const = 0;
|
||||
|
||||
/**Returns one or possibly several maplayers for a given layer name and style. If there are several layers, the layers should be drawn in inverse list order.
|
||||
If no layers/style are found, an empty list is returned
|
||||
@param allowCache true if layer can be read from / written to cache*/
|
||||
@ -87,6 +89,8 @@ class QgsConfigParser
|
||||
|
||||
/**Returns an ID-list of layers which are not queryable*/
|
||||
virtual QStringList identifyDisabledLayers() const { return QStringList(); }
|
||||
/**Returns an ID-list of layers which queryable in WFS service*/
|
||||
virtual QStringList wfsLayers() const { return QStringList(); }
|
||||
|
||||
/**Returns a set of supported epsg codes for the capabilities document. An empty list means
|
||||
that all possible CRS should be advertised (which could result in very long capabilities documents)*/
|
||||
|
@ -288,6 +288,56 @@ void QgsHttpRequestHandler::sendGetPrintResponse( QByteArray* ba ) const
|
||||
sendHttpResponse( ba, formatToMimeType( mFormat ) );
|
||||
}
|
||||
|
||||
bool QgsHttpRequestHandler::startGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const
|
||||
{
|
||||
if ( !ba )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ba->size() < 1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QString format;
|
||||
if ( infoFormat == "GeoJSON" )
|
||||
format = "text/plain";
|
||||
else
|
||||
format = "text/xml";
|
||||
|
||||
printf( "Content-Type: " );
|
||||
printf( format.toLocal8Bit() );
|
||||
printf( "\n" );
|
||||
printf( "\n" );
|
||||
fwrite( ba->data(), ba->size(), 1, FCGI_stdout );
|
||||
return true;
|
||||
}
|
||||
|
||||
void QgsHttpRequestHandler::sendGetFeatureResponse( QByteArray* ba ) const
|
||||
{
|
||||
if ( !ba )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ba->size() < 1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
fwrite( ba->data(), ba->size(), 1, FCGI_stdout );
|
||||
}
|
||||
|
||||
void QgsHttpRequestHandler::endGetFeatureResponse( QByteArray* ba ) const
|
||||
{
|
||||
if ( !ba )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite( ba->data(), ba->size(), 1, FCGI_stdout );
|
||||
}
|
||||
|
||||
void QgsHttpRequestHandler::requestStringToParameterMap( const QString& request, QMap<QString, QString>& parameters )
|
||||
{
|
||||
parameters.clear();
|
||||
|
@ -34,6 +34,9 @@ class QgsHttpRequestHandler: public QgsRequestHandler
|
||||
virtual void sendServiceException( const QgsMapServiceException& ex ) const;
|
||||
virtual void sendGetStyleResponse( const QDomDocument& doc ) const;
|
||||
virtual void sendGetPrintResponse( QByteArray* ba ) const;
|
||||
virtual bool startGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const;
|
||||
virtual void sendGetFeatureResponse( QByteArray* ba ) const;
|
||||
virtual void endGetFeatureResponse( QByteArray* ba ) const;
|
||||
|
||||
protected:
|
||||
void sendHttpResponse( QByteArray* ba, const QString& format ) const;
|
||||
|
@ -138,6 +138,64 @@ void QgsProjectParser::layersAndStylesCapabilities( QDomElement& parentElement,
|
||||
combineExtentAndCrsOfGroupChildren( layerParentElem, doc );
|
||||
}
|
||||
|
||||
void QgsProjectParser::featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const
|
||||
{
|
||||
QStringList wfsLayersId = wfsLayers();
|
||||
|
||||
if ( mProjectLayerElements.size() < 1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QMap<QString, QgsMapLayer *> layerMap;
|
||||
|
||||
foreach( const QDomElement &elem, mProjectLayerElements )
|
||||
{
|
||||
QString type = elem.attribute( "type" );
|
||||
if ( type == "vector" )
|
||||
{
|
||||
//QgsMapLayer *layer = createLayerFromElement( *layerIt );
|
||||
QgsMapLayer *layer = createLayerFromElement( elem );
|
||||
if ( layer && wfsLayersId.contains( layer->id() ) )
|
||||
{
|
||||
QgsDebugMsg( QString( "add layer %1 to map" ).arg( layer->id() ) );
|
||||
layerMap.insert( layer->id(), layer );
|
||||
|
||||
QDomElement layerElem = doc.createElement( "FeatureType" );
|
||||
QDomElement nameElem = doc.createElement( "Name" );
|
||||
//We use the layer name even though it might not be unique.
|
||||
//Because the id sometimes contains user/pw information and the name is more descriptive
|
||||
QDomText nameText = doc.createTextNode( layer->name() );
|
||||
nameElem.appendChild( nameText );
|
||||
layerElem.appendChild( nameElem );
|
||||
|
||||
QDomElement titleElem = doc.createElement( "Title" );
|
||||
QDomText titleText = doc.createTextNode( layer->name() );
|
||||
titleElem.appendChild( titleText );
|
||||
layerElem.appendChild( titleElem );
|
||||
|
||||
//appendExGeographicBoundingBox( layerElem, doc, layer->extent(), layer->crs() );
|
||||
|
||||
QDomElement srsElem = doc.createElement( "SRS" );
|
||||
QDomText srsText = doc.createTextNode( layer->crs().authid() );
|
||||
srsElem.appendChild( srsText );
|
||||
layerElem.appendChild( srsElem );
|
||||
|
||||
QgsRectangle layerExtent = layer->extent();
|
||||
QDomElement bBoxElement = doc.createElement( "LatLongBoundingBox" );
|
||||
bBoxElement.setAttribute( "minx", QString::number( layerExtent.xMinimum() ) );
|
||||
bBoxElement.setAttribute( "miny", QString::number( layerExtent.yMinimum() ) );
|
||||
bBoxElement.setAttribute( "maxx", QString::number( layerExtent.xMaximum() ) );
|
||||
bBoxElement.setAttribute( "maxy", QString::number( layerExtent.yMaximum() ) );
|
||||
layerElem.appendChild( bBoxElement );
|
||||
|
||||
parentElement.appendChild( layerElem );
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void QgsProjectParser::addLayers( QDomDocument &doc,
|
||||
QDomElement &parentElem,
|
||||
const QDomElement &legendElem,
|
||||
@ -584,6 +642,37 @@ QStringList QgsProjectParser::identifyDisabledLayers() const
|
||||
return disabledList;
|
||||
}
|
||||
|
||||
QStringList QgsProjectParser::wfsLayers() const
|
||||
{
|
||||
QStringList wfsList;
|
||||
if ( !mXMLDoc )
|
||||
{
|
||||
return wfsList;
|
||||
}
|
||||
|
||||
QDomElement qgisElem = mXMLDoc->documentElement();
|
||||
if ( qgisElem.isNull() )
|
||||
{
|
||||
return wfsList;
|
||||
}
|
||||
QDomElement propertiesElem = qgisElem.firstChildElement( "properties" );
|
||||
if ( propertiesElem.isNull() )
|
||||
{
|
||||
return wfsList;
|
||||
}
|
||||
QDomElement wfsLayersElem = propertiesElem.firstChildElement( "WFSLayers" );
|
||||
if ( wfsLayersElem.isNull() )
|
||||
{
|
||||
return wfsList;
|
||||
}
|
||||
QDomNodeList valueList = wfsLayersElem.elementsByTagName( "value" );
|
||||
for ( int i = 0; i < valueList.size(); ++i )
|
||||
{
|
||||
wfsList << valueList.at( i ).toElement().text();
|
||||
}
|
||||
return wfsList;
|
||||
}
|
||||
|
||||
QStringList QgsProjectParser::supportedOutputCrsList() const
|
||||
{
|
||||
QStringList crsList;
|
||||
|
@ -38,6 +38,8 @@ class QgsProjectParser: public QgsConfigParser
|
||||
/**Adds layer and style specific capabilities elements to the parent node. This includes the individual layers and styles, their description, native CRS, bounding boxes, etc.*/
|
||||
virtual void layersAndStylesCapabilities( QDomElement& parentElement, QDomDocument& doc ) const;
|
||||
|
||||
virtual void featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const;
|
||||
|
||||
int numberOfLayers() const;
|
||||
|
||||
/**Returns one or possibly several maplayers for a given layer name and style. If no layers/style are found, an empty list is returned*/
|
||||
@ -58,6 +60,9 @@ class QgsProjectParser: public QgsConfigParser
|
||||
/**Returns an ID-list of layers which are not queryable (comes from <properties> -> <Identify> -> <disabledLayers in the project file*/
|
||||
virtual QStringList identifyDisabledLayers() const;
|
||||
|
||||
/**Returns an ID-list of layers queryable for WFS service (comes from <properties> -> <WFSLayers> in the project file*/
|
||||
virtual QStringList wfsLayers() const;
|
||||
|
||||
/**Returns a set of supported epsg codes for the capabilities document. The list comes from the property <WMSEpsgList> in the project file.
|
||||
An empty set means that all possible CRS should be advertised (which could result in very long capabilities documents)
|
||||
Example:
|
||||
|
@ -41,6 +41,9 @@ class QgsRequestHandler
|
||||
virtual void sendServiceException( const QgsMapServiceException& ex ) const = 0;
|
||||
virtual void sendGetStyleResponse( const QDomDocument& doc ) const = 0;
|
||||
virtual void sendGetPrintResponse( QByteArray* ba ) const = 0;
|
||||
virtual bool startGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const = 0;
|
||||
virtual void sendGetFeatureResponse( QByteArray* ba ) const = 0;
|
||||
virtual void endGetFeatureResponse( QByteArray* ba ) const = 0;
|
||||
QString format() const { return mFormat; }
|
||||
protected:
|
||||
/**This is set by the parseInput methods of the subclasses (parameter FORMAT, e.g. 'FORMAT=PNG')*/
|
||||
|
@ -56,6 +56,8 @@ class QgsSLDParser: public QgsConfigParser
|
||||
/**Adds layer and style specific capabilities elements to the parent node. This includes the individual layers and styles, their description, native CRS, bounding boxes, etc.*/
|
||||
void layersAndStylesCapabilities( QDomElement& parentElement, QDomDocument& doc ) const;
|
||||
|
||||
void featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const {};
|
||||
|
||||
/**Returns number of layers in configuration*/
|
||||
int numberOfLayers() const;
|
||||
|
||||
|
946
src/mapserver/qgswfsserver.cpp
Normal file
946
src/mapserver/qgswfsserver.cpp
Normal file
@ -0,0 +1,946 @@
|
||||
#include "qgswfsserver.h"
|
||||
#include "qgsconfigparser.h"
|
||||
#include "qgscrscache.h"
|
||||
#include "qgsfield.h"
|
||||
#include "qgsgeometry.h"
|
||||
#include "qgsmaplayer.h"
|
||||
#include "qgsmaplayerregistry.h"
|
||||
#include "qgsmaprenderer.h"
|
||||
#include "qgsmaptopixel.h"
|
||||
#include "qgspallabeling.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgsrasterlayer.h"
|
||||
#include "qgsscalecalculator.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsfilter.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsmapserviceexception.h"
|
||||
#include "qgssldparser.h"
|
||||
#include "qgssymbol.h"
|
||||
#include "qgssymbolv2.h"
|
||||
#include "qgsrenderer.h"
|
||||
#include "qgslegendmodel.h"
|
||||
#include "qgscomposerlegenditem.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsrequesthandler.h"
|
||||
#include <QImage>
|
||||
#include <QPainter>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include <QDir>
|
||||
|
||||
//for printing
|
||||
#include "qgscomposition.h"
|
||||
#include <QBuffer>
|
||||
#include <QPrinter>
|
||||
#include <QSvgGenerator>
|
||||
#include <QUrl>
|
||||
#include <QPaintEngine>
|
||||
|
||||
QgsWFSServer::QgsWFSServer( QMap<QString, QString> parameters )
|
||||
: mParameterMap( parameters )
|
||||
, mConfigParser( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
QgsWFSServer::~QgsWFSServer()
|
||||
{
|
||||
}
|
||||
|
||||
QgsWFSServer::QgsWFSServer()
|
||||
{
|
||||
}
|
||||
|
||||
QDomDocument QgsWFSServer::getCapabilities()
|
||||
{
|
||||
QgsDebugMsg( "Entering." );
|
||||
QDomDocument doc;
|
||||
//wfs:WFS_Capabilities element
|
||||
QDomElement wfsCapabilitiesElement = doc.createElement( "WFS_Capabilities"/*wms:WFS_Capabilities*/ );
|
||||
wfsCapabilitiesElement.setAttribute( "xmlns", "http://www.opengis.net/wfs" );
|
||||
wfsCapabilitiesElement.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
|
||||
wfsCapabilitiesElement.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" );
|
||||
wfsCapabilitiesElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
|
||||
wfsCapabilitiesElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" );
|
||||
wfsCapabilitiesElement.setAttribute( "xmlns:ows", "http://www.opengis.net/ows" );
|
||||
wfsCapabilitiesElement.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
|
||||
wfsCapabilitiesElement.setAttribute( "version", "1.0.0" );
|
||||
wfsCapabilitiesElement.setAttribute( "updateSequence", "0" );
|
||||
doc.appendChild( wfsCapabilitiesElement );
|
||||
|
||||
if ( mConfigParser )
|
||||
{
|
||||
mConfigParser->serviceCapabilities( wfsCapabilitiesElement, doc );
|
||||
}
|
||||
|
||||
//wfs:Capability element
|
||||
QDomElement capabilityElement = doc.createElement( "Capability"/*wfs:Capability*/ );
|
||||
wfsCapabilitiesElement.appendChild( capabilityElement );
|
||||
|
||||
//wfs:Request element
|
||||
QDomElement requestElement = doc.createElement( "Request"/*wfs:Request*/ );
|
||||
capabilityElement.appendChild( requestElement );
|
||||
//wfs:GetCapabilities
|
||||
QDomElement getCapabilitiesElement = doc.createElement( "GetCapabilities"/*wfs:GetCapabilities*/ );
|
||||
requestElement.appendChild( getCapabilitiesElement );
|
||||
QDomElement capabilitiesFormatElement = doc.createElement( "Format" );/*wfs:Format*/
|
||||
getCapabilitiesElement.appendChild( capabilitiesFormatElement );
|
||||
QDomText capabilitiesFormatText = doc.createTextNode( "text/xml" );
|
||||
capabilitiesFormatElement.appendChild( capabilitiesFormatText );
|
||||
|
||||
QDomElement dcpTypeElement = doc.createElement( "DCPType"/*wfs:DCPType*/ );
|
||||
getCapabilitiesElement.appendChild( dcpTypeElement );
|
||||
QDomElement httpElement = doc.createElement( "HTTP"/*wfs:HTTP*/ );
|
||||
dcpTypeElement.appendChild( httpElement );
|
||||
|
||||
//Prepare url
|
||||
//Some client requests already have http://<SERVER_NAME> in the REQUEST_URI variable
|
||||
QString hrefString;
|
||||
QString requestUrl = getenv( "REQUEST_URI" );
|
||||
QUrl mapUrl( requestUrl );
|
||||
mapUrl.setHost( QString( getenv( "SERVER_NAME" ) ) );
|
||||
mapUrl.removeQueryItem( "REQUEST" );
|
||||
mapUrl.removeQueryItem( "VERSION" );
|
||||
mapUrl.removeQueryItem( "SERVICE" );
|
||||
hrefString = mapUrl.toString();
|
||||
|
||||
//only Get supported for the moment
|
||||
QDomElement getElement = doc.createElement( "Get"/*wfs:Get*/ );
|
||||
httpElement.appendChild( getElement );
|
||||
QDomElement olResourceElement = doc.createElement( "OnlineResource"/*wfs:OnlineResource*/ );
|
||||
olResourceElement.setAttribute( "xlink:type", "simple" );
|
||||
requestUrl.truncate( requestUrl.indexOf( "?" ) + 1 );
|
||||
olResourceElement.setAttribute( "xlink:href", hrefString );
|
||||
getElement.appendChild( olResourceElement );
|
||||
|
||||
//wfs:DescribeFeatureType
|
||||
QDomElement describeFeatureTypeElement = doc.createElement( "DescribeFeatureType"/*wfs:DescribeFeatureType*/ );
|
||||
requestElement.appendChild( describeFeatureTypeElement );
|
||||
QDomElement schemaDescriptionLanguageElement = doc.createElement( "SchemaDescriptionLanguage"/*wfs:SchemaDescriptionLanguage*/ );
|
||||
describeFeatureTypeElement.appendChild( schemaDescriptionLanguageElement );
|
||||
QDomElement xmlSchemaElement = doc.createElement( "XMLSCHEMA"/*wfs:XMLSCHEMA*/ );
|
||||
schemaDescriptionLanguageElement.appendChild( xmlSchemaElement );
|
||||
QDomElement describeFeatureTypeDhcTypeElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities'
|
||||
describeFeatureTypeElement.appendChild( describeFeatureTypeDhcTypeElement );
|
||||
|
||||
//wfs:GetFeature
|
||||
QDomElement getFeatureElement = doc.createElement( "GetFeature"/*wfs:GetFeature*/ );
|
||||
requestElement.appendChild( getFeatureElement );
|
||||
QDomElement getFeatureFormatElement = doc.createElement( "ResultFormat" );/*wfs:ResultFormat*/
|
||||
getFeatureElement.appendChild( getFeatureFormatElement );
|
||||
QDomElement gmlFormatElement = doc.createElement( "GML2" );/*wfs:GML2*/
|
||||
getFeatureFormatElement.appendChild( gmlFormatElement );
|
||||
QDomElement geojsonFormatElement = doc.createElement( "GeoJSON" );/*wfs:GeoJSON*/
|
||||
getFeatureFormatElement.appendChild( geojsonFormatElement );
|
||||
QDomElement getFeatureDhcTypeElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities'
|
||||
getFeatureElement.appendChild( getFeatureDhcTypeElement );
|
||||
|
||||
//wfs:FeatureTypeList element
|
||||
QDomElement featureTypeListElement = doc.createElement( "FeatureTypeList"/*wfs:FeatureTypeList*/ );
|
||||
capabilityElement.appendChild( featureTypeListElement );
|
||||
//wfs:Operations element
|
||||
QDomElement operationsElement = doc.createElement( "Operations"/*wfs:Operations*/ );
|
||||
featureTypeListElement.appendChild( operationsElement );
|
||||
//wfs:Query element
|
||||
QDomElement queryElement = doc.createElement( "Query"/*wfs:Query*/ );
|
||||
operationsElement.appendChild( queryElement );
|
||||
/*
|
||||
* Adding layer liste in featureTypeListElement
|
||||
*/
|
||||
if ( mConfigParser )
|
||||
{
|
||||
mConfigParser->featureTypeList( featureTypeListElement, doc );
|
||||
}
|
||||
|
||||
/*
|
||||
* Adding ogc:Filter_Capabilities in capabilityElement
|
||||
*/
|
||||
//ogc:Filter_Capabilities element
|
||||
QDomElement filterCapabilitiesElement = doc.createElement( "ogc:Filter_Capabilities"/*ogc:Filter_Capabilities*/ );
|
||||
capabilityElement.appendChild( filterCapabilitiesElement );
|
||||
QDomElement spatialCapabilitiesElement = doc.createElement( "ogc:Spatial_Capabilities"/*ogc:Spatial_Capabilities*/ );
|
||||
filterCapabilitiesElement.appendChild( spatialCapabilitiesElement );
|
||||
QDomElement spatialOperatorsElement = doc.createElement( "ogc:Spatial_Operators"/*ogc:Spatial_Operators*/ );
|
||||
spatialCapabilitiesElement.appendChild( spatialOperatorsElement );
|
||||
QDomElement ogcBboxElement = doc.createElement( "ogc:BBOX"/*ogc:BBOX*/ );
|
||||
spatialOperatorsElement.appendChild( ogcBboxElement );
|
||||
QDomElement scalarCapabilitiesElement = doc.createElement( "ogc:Scalar_Capabilities"/*ogc:Scalar_Capabilities*/ );
|
||||
filterCapabilitiesElement.appendChild( scalarCapabilitiesElement );
|
||||
QDomElement comparisonOperatorsElement = doc.createElement( "ogc:Comparison_Operators"/*ogc:Comparison_Operators*/ );
|
||||
scalarCapabilitiesElement.appendChild( comparisonOperatorsElement );
|
||||
QDomElement simpleComparisonsElement = doc.createElement( "ogc:Simple_Comparisons"/*ogc:Simple_Comparisons*/ );
|
||||
comparisonOperatorsElement.appendChild( simpleComparisonsElement );
|
||||
return doc;
|
||||
}
|
||||
|
||||
QDomDocument QgsWFSServer::describeFeatureType()
|
||||
{
|
||||
QgsDebugMsg( "Entering." );
|
||||
QDomDocument doc;
|
||||
//xsd:schema
|
||||
QDomElement schemaElement = doc.createElement( "schema"/*xsd:schema*/ );
|
||||
schemaElement.setAttribute( "xmlns", "http://www.w3.org/2001/XMLSchema" );
|
||||
schemaElement.setAttribute( "xmlns:xsd", "http://www.w3.org/2001/XMLSchema" );
|
||||
schemaElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
|
||||
schemaElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" );
|
||||
schemaElement.setAttribute( "xmlns:qgs", "http://www.qgis.org/gml" );
|
||||
schemaElement.setAttribute( "targetNamespace", "http://www.qgis.org/gml" );
|
||||
doc.appendChild( schemaElement );
|
||||
|
||||
//xsd:import
|
||||
QDomElement importElement = doc.createElement( "import"/*xsd:import*/ );
|
||||
importElement.setAttribute( "namespace", "http://www.opengis.net/gml" );
|
||||
importElement.setAttribute( "schemaLocation", "http://schemas.opengis.net/gml/2.1.2/feature.xsd" );
|
||||
schemaElement.appendChild( importElement );
|
||||
|
||||
//read TYPENAME
|
||||
QString typeName;
|
||||
QMap<QString, QString>::const_iterator type_name_it = mParameterMap.find( "TYPENAME" );
|
||||
if ( type_name_it != mParameterMap.end() )
|
||||
{
|
||||
typeName = type_name_it.value();
|
||||
}
|
||||
else
|
||||
{
|
||||
return doc;
|
||||
}
|
||||
|
||||
QStringList wfsLayersId = mConfigParser->wfsLayers();
|
||||
QMap< QString, QMap< int, QString > > aliasInfo = mConfigParser->layerAliasInfo();
|
||||
QMap< QString, QSet<QString> > hiddenAttributes = mConfigParser->hiddenAttributes();
|
||||
|
||||
QList<QgsMapLayer*> layerList;
|
||||
QgsMapLayer* currentLayer = 0;
|
||||
|
||||
layerList = mConfigParser->mapLayerFromStyle( typeName, "" );
|
||||
currentLayer = layerList.at( 0 );
|
||||
|
||||
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>( currentLayer );
|
||||
if ( layer && wfsLayersId.contains( layer->id() ) )
|
||||
{
|
||||
//is there alias info for this vector layer?
|
||||
QMap< int, QString > layerAliasInfo;
|
||||
QMap< QString, QMap< int, QString > >::const_iterator aliasIt = aliasInfo.find( currentLayer->id() );
|
||||
if ( aliasIt != aliasInfo.constEnd() )
|
||||
{
|
||||
layerAliasInfo = aliasIt.value();
|
||||
}
|
||||
|
||||
//hidden attributes for this layer
|
||||
QSet<QString> layerHiddenAttributes;
|
||||
QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find( currentLayer->id() );
|
||||
if ( hiddenIt != hiddenAttributes.constEnd() )
|
||||
{
|
||||
layerHiddenAttributes = hiddenIt.value();
|
||||
}
|
||||
|
||||
//do a select with searchRect and go through all the features
|
||||
QgsVectorDataProvider* provider = layer->dataProvider();
|
||||
if ( !provider )
|
||||
{
|
||||
return doc;
|
||||
}
|
||||
|
||||
typeName = typeName.replace( QString( " " ), QString( "_" ) );
|
||||
|
||||
//xsd:element
|
||||
QDomElement elementElem = doc.createElement( "element"/*xsd:element*/ );
|
||||
elementElem.setAttribute( "name", typeName );
|
||||
elementElem.setAttribute( "type", "qgs:" + typeName + "Type" );
|
||||
elementElem.setAttribute( "substitutionGroup", "gml:_Feature" );
|
||||
schemaElement.appendChild( elementElem );
|
||||
|
||||
//xsd:complexType
|
||||
QDomElement complexTypeElem = doc.createElement( "complexType"/*xsd:complexType*/ );
|
||||
complexTypeElem.setAttribute( "name", typeName + "Type" );
|
||||
schemaElement.appendChild( complexTypeElem );
|
||||
|
||||
//xsd:complexType
|
||||
QDomElement complexContentElem = doc.createElement( "complexContent"/*xsd:complexContent*/ );
|
||||
complexTypeElem.appendChild( complexContentElem );
|
||||
|
||||
//xsd:extension
|
||||
QDomElement extensionElem = doc.createElement( "extension"/*xsd:extension*/ );
|
||||
extensionElem.setAttribute( "base", "gml:AbstractFeatureType" );
|
||||
complexContentElem.appendChild( extensionElem );
|
||||
|
||||
//xsd:sequence
|
||||
QDomElement sequenceElem = doc.createElement( "sequence"/*xsd:sequence*/ );
|
||||
extensionElem.appendChild( sequenceElem );
|
||||
|
||||
//xsd:element
|
||||
QDomElement geomElem = doc.createElement( "element"/*xsd:element*/ );
|
||||
geomElem.setAttribute( "name", "geometry" );
|
||||
geomElem.setAttribute( "type", "gml:GeometryPropertyType" );
|
||||
geomElem.setAttribute( "minOccurs", "0" );
|
||||
geomElem.setAttribute( "maxOccurs", "1" );
|
||||
sequenceElem.appendChild( geomElem );
|
||||
|
||||
const QgsFieldMap& fields = provider->fields();
|
||||
for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it )
|
||||
{
|
||||
|
||||
QString attributeName = it.value().name();
|
||||
//skip attribute if it has edit type 'hidden'
|
||||
if ( layerHiddenAttributes.contains( attributeName ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//xsd:element
|
||||
QDomElement geomElem = doc.createElement( "element"/*xsd:element*/ );
|
||||
geomElem.setAttribute( "name", attributeName );
|
||||
if ( it.value().type() == 2 )
|
||||
geomElem.setAttribute( "type", "integer" );
|
||||
else if ( it.value().type() == 6 )
|
||||
geomElem.setAttribute( "type", "double" );
|
||||
else
|
||||
geomElem.setAttribute( "type", "string" );
|
||||
|
||||
sequenceElem.appendChild( geomElem );
|
||||
|
||||
//check if the attribute name should be replaced with an alias
|
||||
QMap<int, QString>::const_iterator aliasIt = layerAliasInfo.find( it.key() );
|
||||
if ( aliasIt != layerAliasInfo.constEnd() )
|
||||
{
|
||||
geomElem.setAttribute( "alias", aliasIt.value() );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format )
|
||||
{
|
||||
QgsDebugMsg( "Info format is:" + format );
|
||||
|
||||
//read TYPENAME
|
||||
QMap<QString, QString>::const_iterator type_name_it = mParameterMap.find( "TYPENAME" );
|
||||
if ( type_name_it != mParameterMap.end() )
|
||||
{
|
||||
mTypeName = type_name_it.value();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QStringList wfsLayersId = mConfigParser->wfsLayers();
|
||||
QMap< QString, QMap< int, QString > > aliasInfo = mConfigParser->layerAliasInfo();
|
||||
QMap< QString, QSet<QString> > hiddenAttributes = mConfigParser->hiddenAttributes();
|
||||
|
||||
QList<QgsMapLayer*> layerList;
|
||||
QgsMapLayer* currentLayer = 0;
|
||||
|
||||
layerList = mConfigParser->mapLayerFromStyle( mTypeName, "" );
|
||||
currentLayer = layerList.at( 0 );
|
||||
|
||||
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>( currentLayer );
|
||||
if ( layer && wfsLayersId.contains( layer->id() ) )
|
||||
{
|
||||
//is there alias info for this vector layer?
|
||||
QMap< int, QString > layerAliasInfo;
|
||||
QMap< QString, QMap< int, QString > >::const_iterator aliasIt = aliasInfo.find( currentLayer->id() );
|
||||
if ( aliasIt != aliasInfo.constEnd() )
|
||||
{
|
||||
layerAliasInfo = aliasIt.value();
|
||||
}
|
||||
|
||||
//hidden attributes for this layer
|
||||
QSet<QString> layerHiddenAttributes;
|
||||
QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find( currentLayer->id() );
|
||||
if ( hiddenIt != hiddenAttributes.constEnd() )
|
||||
{
|
||||
layerHiddenAttributes = hiddenIt.value();
|
||||
}
|
||||
|
||||
//do a select with searchRect and go through all the features
|
||||
QgsVectorDataProvider* provider = layer->dataProvider();
|
||||
if ( !provider )
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
QgsFeature feature;
|
||||
QgsAttributeMap featureAttributes;
|
||||
const QgsFieldMap& fields = provider->fields();
|
||||
|
||||
//map extent
|
||||
QgsRectangle searchRect = layer->extent();
|
||||
|
||||
//read FEATUREDID
|
||||
bool fidOk = false;
|
||||
QString fid;
|
||||
QMap<QString, QString>::const_iterator fidIt = mParameterMap.find( "FEATUREID" );
|
||||
if ( fidIt != mParameterMap.end() )
|
||||
{
|
||||
fidOk = true;
|
||||
fid = fidIt.value();
|
||||
}
|
||||
|
||||
//read FILTER
|
||||
bool filterOk = false;
|
||||
QDomDocument filter;
|
||||
QMap<QString, QString>::const_iterator filterIt = mParameterMap.find( "FILTER" );
|
||||
if ( filterIt != mParameterMap.end() )
|
||||
{
|
||||
try
|
||||
{
|
||||
QString errorMsg;
|
||||
if ( !filter.setContent( filterIt.value(), true, &errorMsg ) )
|
||||
{
|
||||
QgsDebugMsg( "soap request parse error" );
|
||||
QgsDebugMsg( "error message: " + errorMsg );
|
||||
QgsDebugMsg( "the xml string was:" );
|
||||
QgsDebugMsg( filterIt.value() );
|
||||
}
|
||||
else
|
||||
{
|
||||
filterOk = true;
|
||||
}
|
||||
}
|
||||
catch ( QgsMapServiceException& e )
|
||||
{
|
||||
filterOk = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool conversionSuccess;
|
||||
double minx, miny, maxx, maxy;
|
||||
bool bboxOk = false;
|
||||
//read BBOX
|
||||
QMap<QString, QString>::const_iterator bbIt = mParameterMap.find( "BBOX" );
|
||||
if ( bbIt == mParameterMap.end() )
|
||||
{
|
||||
minx = 0; miny = 0; maxx = 0; maxy = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bboxOk = true;
|
||||
QString bbString = bbIt.value();
|
||||
minx = bbString.section( ",", 0, 0 ).toDouble( &conversionSuccess );
|
||||
if ( !conversionSuccess ) {bboxOk = false;}
|
||||
miny = bbString.section( ",", 1, 1 ).toDouble( &conversionSuccess );
|
||||
if ( !conversionSuccess ) {bboxOk = false;}
|
||||
maxx = bbString.section( ",", 2, 2 ).toDouble( &conversionSuccess );
|
||||
if ( !conversionSuccess ) {bboxOk = false;}
|
||||
maxy = bbString.section( ",", 3, 3 ).toDouble( &conversionSuccess );
|
||||
if ( !conversionSuccess ) {bboxOk = false;}
|
||||
}
|
||||
|
||||
//read MAXFEATURES
|
||||
long maxFeat = layer->featureCount();
|
||||
long featureCounter = 0;
|
||||
QMap<QString, QString>::const_iterator mfIt = mParameterMap.find( "MAXFEATURES" );
|
||||
if ( mfIt != mParameterMap.end() )
|
||||
{
|
||||
QString mfString = mfIt.value();
|
||||
bool mfOk;
|
||||
maxFeat = mfString.toLong( &mfOk, 10 );
|
||||
if ( !mfOk ) { maxFeat = layer->featureCount(); }
|
||||
}
|
||||
|
||||
//read PROPERTYNAME
|
||||
mWithGeom = true;
|
||||
QgsAttributeList attrIndexes = provider->attributeIndexes();
|
||||
QMap<QString, QString>::const_iterator pnIt = mParameterMap.find( "PROPERTYNAME" );
|
||||
if ( pnIt != mParameterMap.end() )
|
||||
{
|
||||
QStringList attrList = pnIt.value().split( "," );
|
||||
if ( attrList.size() > 0 )
|
||||
{
|
||||
mWithGeom = false;
|
||||
QStringList::const_iterator alstIt;
|
||||
QList<int> idxList;
|
||||
QMap<QString, int> fieldMap = provider->fieldNameMap();
|
||||
QMap<QString, int>::const_iterator fieldIt;
|
||||
QString fieldName;
|
||||
for ( alstIt = attrList.begin(); alstIt != attrList.end(); ++alstIt )
|
||||
{
|
||||
fieldName = *alstIt;
|
||||
fieldIt = fieldMap.find( fieldName );
|
||||
if ( fieldIt != fieldMap.end() )
|
||||
{
|
||||
idxList.append( fieldIt.value() );
|
||||
}
|
||||
else if ( fieldName == "geometry" )
|
||||
{
|
||||
mWithGeom = true;
|
||||
}
|
||||
}
|
||||
if ( idxList.size() > 0 || mWithGeom )
|
||||
{
|
||||
attrIndexes = idxList;
|
||||
}
|
||||
else
|
||||
{
|
||||
mWithGeom = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem layerCrs = layer->crs();
|
||||
|
||||
startGetFeature( request, format );
|
||||
|
||||
if ( fidOk )
|
||||
{
|
||||
provider->featureAtId( fid.toInt(), feature, mWithGeom, attrIndexes );
|
||||
sendGetFeature( request, format, &feature, 0, layerCrs, fields, layerHiddenAttributes );
|
||||
}
|
||||
else if ( filterOk )
|
||||
{
|
||||
provider->select( attrIndexes, searchRect, mWithGeom, true );
|
||||
try
|
||||
{
|
||||
QgsFilter* mFilter = QgsFilter::createFilterFromXml( filter.firstChild().toElement().firstChild().toElement(), layer );
|
||||
while ( provider->nextFeature( feature ) && featureCounter < maxFeat )
|
||||
{
|
||||
if ( mFilter )
|
||||
{
|
||||
if ( mFilter->evaluate( feature ) )
|
||||
{
|
||||
sendGetFeature( request, format, &feature, featureCounter, layerCrs, fields, layerHiddenAttributes );
|
||||
++featureCounter;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sendGetFeature( request, format, &feature, featureCounter, layerCrs, fields, layerHiddenAttributes );
|
||||
++featureCounter;
|
||||
}
|
||||
}
|
||||
delete mFilter;
|
||||
}
|
||||
catch ( QgsMapServiceException& e )
|
||||
{
|
||||
while ( provider->nextFeature( feature ) && featureCounter < maxFeat )
|
||||
{
|
||||
sendGetFeature( request, format, &feature, featureCounter, layerCrs, fields, layerHiddenAttributes );
|
||||
++featureCounter;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( bboxOk )
|
||||
searchRect.set( minx, miny, maxx, maxy );
|
||||
provider->select( attrIndexes, searchRect, mWithGeom, true );
|
||||
while ( provider->nextFeature( feature ) && featureCounter < maxFeat )
|
||||
{
|
||||
sendGetFeature( request, format, &feature, featureCounter, layerCrs, fields, layerHiddenAttributes );
|
||||
++featureCounter;
|
||||
}
|
||||
}
|
||||
|
||||
endGetFeature( request, format );
|
||||
}
|
||||
else
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QgsWFSServer::startGetFeature( QgsRequestHandler& request, const QString& format )
|
||||
{
|
||||
QByteArray result;
|
||||
QString fcString;
|
||||
if ( format == "GeoJSON" )
|
||||
{
|
||||
fcString = "{\"type\": \"FeatureCollection\",\n";
|
||||
fcString += " \"features\": [\n";
|
||||
result = fcString.toUtf8();
|
||||
request.startGetFeatureResponse( &result, format );
|
||||
}
|
||||
else
|
||||
{
|
||||
//wfs:FeatureCollection
|
||||
fcString = "<wfs:FeatureCollection";
|
||||
fcString += " xmlns=\"http://www.opengis.net/wfs\"";
|
||||
fcString += " xmlns:wfs=\"http://www.opengis.net/wfs\"";
|
||||
fcString += " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"";
|
||||
fcString += " xsi:schemaLocation=\"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd\"";
|
||||
fcString += " xmlns:ogc=\"http://www.opengis.net/ogc\"";
|
||||
fcString += " xmlns:gml=\"http://www.opengis.net/gml\"";
|
||||
fcString += " xmlns:ows=\"http://www.opengis.net/ows\"";
|
||||
fcString += " xmlns:xlink=\"http://www.w3.org/1999/xlink\"";
|
||||
fcString += " xmlns:qgs=\"http://www.qgis.org/gml\"";
|
||||
fcString += ">";
|
||||
result = fcString.toUtf8();
|
||||
request.startGetFeatureResponse( &result, format );
|
||||
}
|
||||
fcString = "";
|
||||
}
|
||||
|
||||
void QgsWFSServer::sendGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet<QString> hiddenAttributes ) /*const*/
|
||||
{
|
||||
QByteArray result;
|
||||
if ( format == "GeoJSON" )
|
||||
{
|
||||
QString fcString;
|
||||
if ( featIdx == 0 )
|
||||
fcString += " ";
|
||||
else
|
||||
fcString += " ,";
|
||||
fcString += createFeatureGeoJSON( feat, crs, fields, hiddenAttributes );
|
||||
fcString += "\n";
|
||||
|
||||
result = fcString.toUtf8();
|
||||
request.sendGetFeatureResponse( &result );
|
||||
fcString = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
QDomDocument gmlDoc;
|
||||
QDomElement featureElement = createFeatureElem( feat, gmlDoc, crs, fields, hiddenAttributes );
|
||||
gmlDoc.appendChild( featureElement );
|
||||
|
||||
result = gmlDoc.toByteArray();
|
||||
request.sendGetFeatureResponse( &result );
|
||||
gmlDoc.removeChild( featureElement );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsWFSServer::endGetFeature( QgsRequestHandler& request, const QString& format )
|
||||
{
|
||||
QByteArray result;
|
||||
QString fcString;
|
||||
if ( format == "GeoJSON" )
|
||||
{
|
||||
fcString += " ]\n";
|
||||
fcString += "}";
|
||||
|
||||
result = fcString.toUtf8();
|
||||
request.endGetFeatureResponse( &result );
|
||||
fcString = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
fcString = "</wfs:FeatureCollection>";
|
||||
result = fcString.toUtf8();
|
||||
request.endGetFeatureResponse( &result );
|
||||
fcString = "";
|
||||
}
|
||||
}
|
||||
|
||||
QString QgsWFSServer::createFeatureGeoJSON( QgsFeature* feat, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet<QString> hiddenAttributes ) /*const*/
|
||||
{
|
||||
QString fStr = "{\"type\": \"Feature\",\n";
|
||||
|
||||
fStr += " \"id\": ";
|
||||
fStr += QString::number( feat->id() );
|
||||
fStr += ",\n";
|
||||
|
||||
QgsGeometry* geom = feat->geometry();
|
||||
if ( geom && mWithGeom )
|
||||
{
|
||||
fStr += " \"geometry\": ";
|
||||
fStr += geom->exportToGeoJSON();
|
||||
fStr += ",\n";
|
||||
}
|
||||
|
||||
//read all attribute values from the feature
|
||||
fStr += " \"properties\": {\n";
|
||||
QgsAttributeMap featureAttributes = feat->attributeMap();
|
||||
int attributeCounter = 0;
|
||||
for ( QgsAttributeMap::const_iterator it = featureAttributes.begin(); it != featureAttributes.end(); ++it )
|
||||
{
|
||||
QString attributeName = fields[it.key()].name();
|
||||
//skip attribute if it has edit type 'hidden'
|
||||
if ( hiddenAttributes.contains( attributeName ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( attributeCounter == 0 )
|
||||
fStr += " \"";
|
||||
else
|
||||
fStr += " ,\"";
|
||||
fStr += attributeName;
|
||||
fStr += "\": ";
|
||||
if ( it->type() == 6 || it->type() == 2 )
|
||||
{
|
||||
fStr += it->toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
fStr += "\"";
|
||||
fStr += it->toString().replace( QString( "\"" ), QString( "\\\"" ) );
|
||||
fStr += "\"";
|
||||
}
|
||||
fStr += "\n";
|
||||
++attributeCounter;
|
||||
}
|
||||
|
||||
fStr += " }\n";
|
||||
|
||||
fStr += " }";
|
||||
|
||||
return fStr;
|
||||
}
|
||||
|
||||
QDomElement QgsWFSServer::createFeatureElem( QgsFeature* feat, QDomDocument& doc, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet<QString> hiddenAttributes ) /*const*/
|
||||
{
|
||||
//gml:FeatureMember
|
||||
QDomElement featureElement = doc.createElement( "gml:featureMember"/*wfs:FeatureMember*/ );
|
||||
|
||||
//qgs:%TYPENAME%
|
||||
QDomElement typeNameElement = doc.createElement( "qgs:" + mTypeName.replace( QString( " " ), QString( "_" ) )/*qgs:%TYPENAME%*/ );
|
||||
typeNameElement.setAttribute( "fid", QString::number( feat->id() ) );
|
||||
featureElement.appendChild( typeNameElement );
|
||||
|
||||
if ( mWithGeom )
|
||||
{
|
||||
//add geometry column (as gml)
|
||||
QDomElement geomElem = doc.createElement( "qgs:geometry" );
|
||||
QDomElement gmlElem = createGeometryElem( feat->geometry(), doc );
|
||||
if ( !gmlElem.isNull() )
|
||||
{
|
||||
if ( crs.isValid() )
|
||||
{
|
||||
gmlElem.setAttribute( "srsName", crs.authid() );
|
||||
}
|
||||
geomElem.appendChild( gmlElem );
|
||||
typeNameElement.appendChild( geomElem );
|
||||
}
|
||||
}
|
||||
|
||||
//read all attribute values from the feature
|
||||
QgsAttributeMap featureAttributes = feat->attributeMap();
|
||||
for ( QgsAttributeMap::const_iterator it = featureAttributes.begin(); it != featureAttributes.end(); ++it )
|
||||
{
|
||||
|
||||
QString attributeName = fields[it.key()].name();
|
||||
//skip attribute if it has edit type 'hidden'
|
||||
if ( hiddenAttributes.contains( attributeName ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QDomElement fieldElem = doc.createElement( "qgs:" + attributeName.replace( QString( " " ), QString( "_" ) ) );
|
||||
QDomText fieldText = doc.createTextNode( it->toString() );
|
||||
fieldElem.appendChild( fieldText );
|
||||
typeNameElement.appendChild( fieldElem );
|
||||
}
|
||||
|
||||
return featureElement;
|
||||
}
|
||||
|
||||
QDomElement QgsWFSServer::createGeometryElem( QgsGeometry* geom, QDomDocument& doc ) /*const*/
|
||||
{
|
||||
if ( !geom )
|
||||
{
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
QDomElement geomElement;
|
||||
|
||||
QString geomTypeName;
|
||||
QGis::WkbType wkbType = geom->wkbType();
|
||||
switch ( wkbType )
|
||||
{
|
||||
case QGis::WKBPoint:
|
||||
case QGis::WKBPoint25D:
|
||||
geomElement = createPointElem( geom, doc );
|
||||
break;
|
||||
case QGis::WKBMultiPoint:
|
||||
case QGis::WKBMultiPoint25D:
|
||||
geomElement = createMultiPointElem( geom, doc );
|
||||
break;
|
||||
case QGis::WKBLineString:
|
||||
case QGis::WKBLineString25D:
|
||||
geomElement = createLineStringElem( geom, doc );
|
||||
break;
|
||||
case QGis::WKBMultiLineString:
|
||||
case QGis::WKBMultiLineString25D:
|
||||
geomElement = createMultiLineStringElem( geom, doc );
|
||||
break;
|
||||
case QGis::WKBPolygon:
|
||||
case QGis::WKBPolygon25D:
|
||||
geomElement = createPolygonElem( geom, doc );
|
||||
break;
|
||||
case QGis::WKBMultiPolygon:
|
||||
case QGis::WKBMultiPolygon25D:
|
||||
geomElement = createMultiPolygonElem( geom, doc );
|
||||
break;
|
||||
default:
|
||||
return QDomElement();
|
||||
}
|
||||
return geomElement;
|
||||
}
|
||||
|
||||
QDomElement QgsWFSServer::createLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const
|
||||
{
|
||||
if ( !geom )
|
||||
{
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
QDomElement lineStringElem = doc.createElement( "gml:LineString" );
|
||||
QDomElement coordElem = createCoordinateElem( geom->asPolyline(), doc );
|
||||
lineStringElem.appendChild( coordElem );
|
||||
return lineStringElem;
|
||||
}
|
||||
|
||||
QDomElement QgsWFSServer::createMultiLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const
|
||||
{
|
||||
if ( !geom )
|
||||
{
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
QDomElement multiLineStringElem = doc.createElement( "gml:MultiLineString" );
|
||||
QgsMultiPolyline multiline = geom->asMultiPolyline();
|
||||
|
||||
QgsMultiPolyline::const_iterator multiLineIt = multiline.constBegin();
|
||||
for ( ; multiLineIt != multiline.constEnd(); ++multiLineIt )
|
||||
{
|
||||
QgsGeometry* lineGeom = QgsGeometry::fromPolyline( *multiLineIt );
|
||||
if ( lineGeom )
|
||||
{
|
||||
QDomElement lineStringMemberElem = doc.createElement( "gml:lineStringMember" );
|
||||
QDomElement lineElem = createLineStringElem( lineGeom, doc );
|
||||
lineStringMemberElem.appendChild( lineElem );
|
||||
multiLineStringElem.appendChild( lineStringMemberElem );
|
||||
}
|
||||
delete lineGeom;
|
||||
}
|
||||
|
||||
return multiLineStringElem;
|
||||
}
|
||||
|
||||
QDomElement QgsWFSServer::createPointElem( QgsGeometry* geom, QDomDocument& doc ) const
|
||||
{
|
||||
if ( !geom )
|
||||
{
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
QDomElement pointElem = doc.createElement( "gml:Point" );
|
||||
QgsPoint p = geom->asPoint();
|
||||
QVector<QgsPoint> v;
|
||||
v.append( p );
|
||||
QDomElement coordElem = createCoordinateElem( v, doc );
|
||||
pointElem.appendChild( coordElem );
|
||||
return pointElem;
|
||||
}
|
||||
|
||||
QDomElement QgsWFSServer::createMultiPointElem( QgsGeometry* geom, QDomDocument& doc ) const
|
||||
{
|
||||
if ( !geom )
|
||||
{
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
QDomElement multiPointElem = doc.createElement( "gml:MultiPoint" );
|
||||
QgsMultiPoint multiPoint = geom->asMultiPoint();
|
||||
|
||||
QgsMultiPoint::const_iterator multiPointIt = multiPoint.constBegin();
|
||||
for ( ; multiPointIt != multiPoint.constEnd(); ++multiPointIt )
|
||||
{
|
||||
QgsGeometry* pointGeom = QgsGeometry::fromPoint( *multiPointIt );
|
||||
if ( pointGeom )
|
||||
{
|
||||
QDomElement multiPointMemberElem = doc.createElement( "gml:pointMember" );
|
||||
QDomElement pointElem = createPointElem( pointGeom, doc );
|
||||
multiPointMemberElem.appendChild( pointElem );
|
||||
multiPointElem.appendChild( multiPointMemberElem );
|
||||
}
|
||||
}
|
||||
return multiPointElem;
|
||||
}
|
||||
|
||||
QDomElement QgsWFSServer::createPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const
|
||||
{
|
||||
if ( !geom )
|
||||
{
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
QDomElement polygonElem = doc.createElement( "gml:Polygon" );
|
||||
QgsPolygon poly = geom->asPolygon();
|
||||
for ( int i = 0; i < poly.size(); ++i )
|
||||
{
|
||||
QString boundaryName;
|
||||
if ( i == 0 )
|
||||
{
|
||||
boundaryName = "outerBoundaryIs";
|
||||
}
|
||||
else
|
||||
{
|
||||
boundaryName = "innerBoundaryIs";
|
||||
}
|
||||
QDomElement boundaryElem = doc.createElementNS( "http://www.opengis.net/gml", boundaryName );
|
||||
QDomElement ringElem = doc.createElement( "gml:LinearRing" );
|
||||
QDomElement coordElem = createCoordinateElem( poly.at( i ), doc );
|
||||
ringElem.appendChild( coordElem );
|
||||
boundaryElem.appendChild( ringElem );
|
||||
polygonElem.appendChild( boundaryElem );
|
||||
}
|
||||
return polygonElem;
|
||||
}
|
||||
|
||||
QDomElement QgsWFSServer::createMultiPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const
|
||||
{
|
||||
if ( !geom )
|
||||
{
|
||||
return QDomElement();
|
||||
}
|
||||
QDomElement multiPolygonElem = doc.createElement( "gml:MultiPolygon" );
|
||||
QgsMultiPolygon multipoly = geom->asMultiPolygon();
|
||||
|
||||
QgsMultiPolygon::const_iterator polyIt = multipoly.constBegin();
|
||||
for ( ; polyIt != multipoly.constEnd(); ++polyIt )
|
||||
{
|
||||
QgsGeometry* polygonGeom = QgsGeometry::fromPolygon( *polyIt );
|
||||
if ( polygonGeom )
|
||||
{
|
||||
QDomElement polygonMemberElem = doc.createElement( "gml:polygonMember" );
|
||||
QDomElement polygonElem = createPolygonElem( polygonGeom, doc );
|
||||
delete polygonGeom;
|
||||
polygonMemberElem.appendChild( polygonElem );
|
||||
multiPolygonElem.appendChild( polygonMemberElem );
|
||||
}
|
||||
}
|
||||
return multiPolygonElem;
|
||||
}
|
||||
|
||||
QDomElement QgsWFSServer::createCoordinateElem( const QVector<QgsPoint> points, QDomDocument& doc ) const
|
||||
{
|
||||
QDomElement coordElem = doc.createElement( "gml:coordinates" );
|
||||
coordElem.setAttribute( "cs", "," );
|
||||
coordElem.setAttribute( "ts", " " );
|
||||
|
||||
//precision 4 for meters / feet, precision 8 for degrees
|
||||
int precision = 8;
|
||||
/*
|
||||
if ( mSourceCRS.mapUnits() == QGis::Meters
|
||||
|| mSourceCRS.mapUnits() == QGis::Feet )
|
||||
{
|
||||
precision = 4;
|
||||
}
|
||||
*/
|
||||
|
||||
QString coordString;
|
||||
QVector<QgsPoint>::const_iterator pointIt = points.constBegin();
|
||||
for ( ; pointIt != points.constEnd(); ++pointIt )
|
||||
{
|
||||
if ( pointIt != points.constBegin() )
|
||||
{
|
||||
coordString += " ";
|
||||
}
|
||||
coordString += QString::number( pointIt->x(), 'f', precision );
|
||||
coordString += ",";
|
||||
coordString += QString::number( pointIt->y(), 'f', precision );
|
||||
}
|
||||
|
||||
QDomText coordText = doc.createTextNode( coordString );
|
||||
coordElem.appendChild( coordText );
|
||||
return coordElem;
|
||||
}
|
92
src/mapserver/qgswfsserver.h
Normal file
92
src/mapserver/qgswfsserver.h
Normal file
@ -0,0 +1,92 @@
|
||||
|
||||
#ifndef QGSWFSSERVER_H
|
||||
#define QGSWFSSERVER_H
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <map>
|
||||
|
||||
class QgsCoordinateReferenceSystem;
|
||||
class QgsComposerLayerItem;
|
||||
class QgsComposerLegendItem;
|
||||
class QgsComposition;
|
||||
class QgsMapLayer;
|
||||
class QgsMapRenderer;
|
||||
class QgsPoint;
|
||||
class QgsRasterLayer;
|
||||
class QgsConfigParser;
|
||||
class QgsVectorLayer;
|
||||
class QgsCoordinateReferenceSystem;
|
||||
class QgsField;
|
||||
class QgsFeature;
|
||||
class QgsGeometry;
|
||||
class QgsSymbol;
|
||||
class QgsRequestHandler;
|
||||
class QFile;
|
||||
class QFont;
|
||||
class QImage;
|
||||
class QPaintDevice;
|
||||
class QPainter;
|
||||
|
||||
/**This class handles all the wms server requests. The parameters and values have to be passed in the form of
|
||||
a map<QString, QString>. This map is usually generated by a subclass of QgsWMSRequestHandler, which makes QgsWFSServer
|
||||
independent from any server side technology*/
|
||||
|
||||
class QgsWFSServer
|
||||
{
|
||||
public:
|
||||
/**Constructor. Takes parameter map and a pointer to a renderer object (does not take ownership)*/
|
||||
QgsWFSServer( QMap<QString, QString> parameters );
|
||||
~QgsWFSServer();
|
||||
/**Returns an XML file with the capabilities description (as described in the WFS specs)*/
|
||||
QDomDocument getCapabilities();
|
||||
|
||||
/**Returns an XML file with the describe feature type (as described in the WFS specs)*/
|
||||
QDomDocument describeFeatureType();
|
||||
|
||||
/**Creates a document that describes the result of the getFeature request.
|
||||
@return 0 in case of success*/
|
||||
int getFeature( QgsRequestHandler& request, const QString& format );
|
||||
|
||||
/**Sets configuration parser for administration settings. Does not take ownership*/
|
||||
void setAdminConfigParser( QgsConfigParser* parser ) { mConfigParser = parser; }
|
||||
|
||||
private:
|
||||
/**Don't use the default constructor*/
|
||||
QgsWFSServer();
|
||||
|
||||
/**Map containing the WMS parameters*/
|
||||
QMap<QString, QString> mParameterMap;
|
||||
QgsConfigParser* mConfigParser;
|
||||
QString mTypeName;
|
||||
bool mWithGeom;
|
||||
|
||||
protected:
|
||||
|
||||
void startGetFeature( QgsRequestHandler& request, const QString& format );
|
||||
void sendGetFeature( QgsRequestHandler& request, const QString& format, QgsFeature* feat, int featIdx, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet<QString> hiddenAttributes );
|
||||
void endGetFeature( QgsRequestHandler& request, const QString& format );
|
||||
|
||||
//methods to write GeoJSON
|
||||
QString createFeatureGeoJSON( QgsFeature* feat, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet<QString> hiddenAttributes ) /*const*/;
|
||||
|
||||
//methods to write GML2
|
||||
QDomElement createFeatureElem( QgsFeature* feat, QDomDocument& doc, QgsCoordinateReferenceSystem& crs, QMap< int, QgsField > fields, QSet<QString> hiddenAttributes ) /*const*/;
|
||||
|
||||
QDomElement createGeometryElem( QgsGeometry* g, QDomDocument& doc ) /*const*/;
|
||||
QDomElement createLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const;
|
||||
QDomElement createMultiLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const;
|
||||
QDomElement createPointElem( QgsGeometry* geom, QDomDocument& doc ) const;
|
||||
QDomElement createMultiPointElem( QgsGeometry* geom, QDomDocument& doc ) const;
|
||||
QDomElement createPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const;
|
||||
QDomElement createMultiPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const;
|
||||
|
||||
/**Create a GML coordinate string from a point list.
|
||||
@param points list of data points
|
||||
@param coordString out: GML coord string
|
||||
@return 0 in case of success*/
|
||||
QDomElement createCoordinateElem( const QVector<QgsPoint> points, QDomDocument& doc ) const;
|
||||
};
|
||||
|
||||
#endif
|
@ -363,9 +363,9 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab">
|
||||
<widget class="QWidget" name="tab4">
|
||||
<attribute name="title">
|
||||
<string>WMS Server</string>
|
||||
<string>OWS Server</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0" rowspan="2">
|
||||
@ -384,7 +384,7 @@
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="grpWMSServiceCapabilities">
|
||||
<widget class="QGroupBox" name="grpOWSServiceCapabilities">
|
||||
<property name="title">
|
||||
<string>Service Capabilitities</string>
|
||||
</property>
|
||||
@ -483,6 +483,12 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="grpWMSCapabilities">
|
||||
<property name="title">
|
||||
<string>WMS Capabilitities</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="grpWMSExt">
|
||||
<property name="title">
|
||||
@ -631,6 +637,32 @@
|
||||
<string>Add WKT geometry to feature info response</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="grpWFSCapabilities">
|
||||
<property name="title">
|
||||
<string>WFS Capabilitities</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_8">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTableWidget" name="twWFSLayers">
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Layer</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Published</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
Loading…
x
Reference in New Issue
Block a user