wfs-server-V3.patch
src/core/qgsgeometry.cpp | ||
---|---|---|
4167 | 4167 |
} |
4168 | 4168 |
} |
4169 | 4169 | |
4170 |
QString QgsGeometry::exportToGeoJSON() |
|
4171 |
{ |
|
4172 |
QgsDebugMsg( "entered." ); |
|
4173 | ||
4174 |
// TODO: implement with GEOS |
|
4175 |
if ( mDirtyWkb ) |
|
4176 |
{ |
|
4177 |
exportGeosToWkb(); |
|
4178 |
} |
|
4179 | ||
4180 |
if ( !mGeometry ) |
|
4181 |
{ |
|
4182 |
QgsDebugMsg( "WKB geometry not available!" ); |
|
4183 |
return QString::null; |
|
4184 |
} |
|
4185 | ||
4186 |
QGis::WkbType wkbType; |
|
4187 |
bool hasZValue = false; |
|
4188 |
double *x, *y; |
|
4189 | ||
4190 |
QString mWkt; // TODO: rename |
|
4191 | ||
4192 |
// Will this really work when mGeometry[0] == 0 ???? I (gavin) think not. |
|
4193 |
//wkbType = (mGeometry[0] == 1) ? mGeometry[1] : mGeometry[4]; |
|
4194 |
memcpy( &wkbType, &( mGeometry[1] ), sizeof( int ) ); |
|
4195 | ||
4196 |
switch ( wkbType ) |
|
4197 |
{ |
|
4198 |
case QGis::WKBPoint25D: |
|
4199 |
case QGis::WKBPoint: |
|
4200 |
{ |
|
4201 |
mWkt += "{ \"type\": \"Point\", \"coordinates\": ["; |
|
4202 |
x = ( double * )( mGeometry + 5 ); |
|
4203 |
mWkt += QString::number( *x, 'f', 6 ); |
|
4204 |
mWkt += ", "; |
|
4205 |
y = ( double * )( mGeometry + 5 + sizeof( double ) ); |
|
4206 |
mWkt += QString::number( *y, 'f', 6 ); |
|
4207 |
mWkt += "] }"; |
|
4208 |
return mWkt; |
|
4209 |
} |
|
4210 | ||
4211 |
case QGis::WKBLineString25D: |
|
4212 |
hasZValue = true; |
|
4213 |
case QGis::WKBLineString: |
|
4214 |
{ |
|
4215 |
QgsDebugMsg( "LINESTRING found" ); |
|
4216 |
unsigned char *ptr; |
|
4217 |
int *nPoints; |
|
4218 |
int idx; |
|
4219 | ||
4220 |
mWkt += "{ \"type\": \"LineString\", \"coordinates\": [ "; |
|
4221 |
// get number of points in the line |
|
4222 |
ptr = mGeometry + 5; |
|
4223 |
nPoints = ( int * ) ptr; |
|
4224 |
ptr = mGeometry + 1 + 2 * sizeof( int ); |
|
4225 |
for ( idx = 0; idx < *nPoints; ++idx ) |
|
4226 |
{ |
|
4227 |
if ( idx != 0 ) |
|
4228 |
{ |
|
4229 |
mWkt += ", "; |
|
4230 |
} |
|
4231 |
mWkt += "["; |
|
4232 |
x = ( double * ) ptr; |
|
4233 |
mWkt += QString::number( *x, 'f', 6 ); |
|
4234 |
mWkt += ", "; |
|
4235 |
ptr += sizeof( double ); |
|
4236 |
y = ( double * ) ptr; |
|
4237 |
mWkt += QString::number( *y, 'f', 6 ); |
|
4238 |
ptr += sizeof( double ); |
|
4239 |
if ( hasZValue ) |
|
4240 |
{ |
|
4241 |
ptr += sizeof( double ); |
|
4242 |
} |
|
4243 |
mWkt += "]"; |
|
4244 |
} |
|
4245 |
mWkt += " ] }"; |
|
4246 |
return mWkt; |
|
4247 |
} |
|
4248 | ||
4249 |
case QGis::WKBPolygon25D: |
|
4250 |
hasZValue = true; |
|
4251 |
case QGis::WKBPolygon: |
|
4252 |
{ |
|
4253 |
QgsDebugMsg( "POLYGON found" ); |
|
4254 |
unsigned char *ptr; |
|
4255 |
int idx, jdx; |
|
4256 |
int *numRings, *nPoints; |
|
4257 | ||
4258 |
mWkt += "{ \"type\": \"Polygon\", \"coordinates\": [ "; |
|
4259 |
// get number of rings in the polygon |
|
4260 |
numRings = ( int * )( mGeometry + 1 + sizeof( int ) ); |
|
4261 |
if ( !( *numRings ) ) // sanity check for zero rings in polygon |
|
4262 |
{ |
|
4263 |
return QString(); |
|
4264 |
} |
|
4265 |
int *ringStart; // index of first point for each ring |
|
4266 |
int *ringNumPoints; // number of points in each ring |
|
4267 |
ringStart = new int[*numRings]; |
|
4268 |
ringNumPoints = new int[*numRings]; |
|
4269 |
ptr = mGeometry + 1 + 2 * sizeof( int ); // set pointer to the first ring |
|
4270 |
for ( idx = 0; idx < *numRings; idx++ ) |
|
4271 |
{ |
|
4272 |
if ( idx != 0 ) |
|
4273 |
{ |
|
4274 |
mWkt += ", "; |
|
4275 |
} |
|
4276 |
mWkt += "[ "; |
|
4277 |
// get number of points in the ring |
|
4278 |
nPoints = ( int * ) ptr; |
|
4279 |
ringNumPoints[idx] = *nPoints; |
|
4280 |
ptr += 4; |
|
4281 | ||
4282 |
for ( jdx = 0; jdx < *nPoints; jdx++ ) |
|
4283 |
{ |
|
4284 |
if ( jdx != 0 ) |
|
4285 |
{ |
|
4286 |
mWkt += ", "; |
|
4287 |
} |
|
4288 |
mWkt += "["; |
|
4289 |
x = ( double * ) ptr; |
|
4290 |
mWkt += QString::number( *x, 'f', 6 ); |
|
4291 |
mWkt += ", "; |
|
4292 |
ptr += sizeof( double ); |
|
4293 |
y = ( double * ) ptr; |
|
4294 |
mWkt += QString::number( *y, 'f', 6 ); |
|
4295 |
ptr += sizeof( double ); |
|
4296 |
if ( hasZValue ) |
|
4297 |
{ |
|
4298 |
ptr += sizeof( double ); |
|
4299 |
} |
|
4300 |
mWkt += "]"; |
|
4301 |
} |
|
4302 |
mWkt += " ]"; |
|
4303 |
} |
|
4304 |
mWkt += " ] }"; |
|
4305 |
delete [] ringStart; |
|
4306 |
delete [] ringNumPoints; |
|
4307 |
return mWkt; |
|
4308 |
} |
|
4309 | ||
4310 |
case QGis::WKBMultiPoint25D: |
|
4311 |
hasZValue = true; |
|
4312 |
case QGis::WKBMultiPoint: |
|
4313 |
{ |
|
4314 |
unsigned char *ptr; |
|
4315 |
int idx; |
|
4316 |
int *nPoints; |
|
4317 | ||
4318 |
mWkt += "{ \"type\": \"MultiPoint\", \"coordinates\": [ "; |
|
4319 |
nPoints = ( int* )( mGeometry + 5 ); |
|
4320 |
ptr = mGeometry + 5 + sizeof( int ); |
|
4321 |
for ( idx = 0; idx < *nPoints; ++idx ) |
|
4322 |
{ |
|
4323 |
ptr += ( 1 + sizeof( int ) ); |
|
4324 |
if ( idx != 0 ) |
|
4325 |
{ |
|
4326 |
mWkt += ", "; |
|
4327 |
} |
|
4328 |
mWkt += "["; |
|
4329 |
x = ( double * )( ptr ); |
|
4330 |
mWkt += QString::number( *x, 'f', 6 ); |
|
4331 |
mWkt += ", "; |
|
4332 |
ptr += sizeof( double ); |
|
4333 |
y = ( double * )( ptr ); |
|
4334 |
mWkt += QString::number( *y, 'f', 6 ); |
|
4335 |
ptr += sizeof( double ); |
|
4336 |
if ( hasZValue ) |
|
4337 |
{ |
|
4338 |
ptr += sizeof( double ); |
|
4339 |
} |
|
4340 |
mWkt += "]"; |
|
4341 |
} |
|
4342 |
mWkt += " ] }"; |
|
4343 |
return mWkt; |
|
4344 |
} |
|
4345 | ||
4346 |
case QGis::WKBMultiLineString25D: |
|
4347 |
hasZValue = true; |
|
4348 |
case QGis::WKBMultiLineString: |
|
4349 |
{ |
|
4350 |
QgsDebugMsg( "MULTILINESTRING found" ); |
|
4351 |
unsigned char *ptr; |
|
4352 |
int idx, jdx, numLineStrings; |
|
4353 |
int *nPoints; |
|
4354 | ||
4355 |
mWkt += "{ \"type\": \"MultiLineString\", \"coordinates\": [ "; |
|
4356 |
numLineStrings = ( int )( mGeometry[5] ); |
|
4357 |
ptr = mGeometry + 9; |
|
4358 |
for ( jdx = 0; jdx < numLineStrings; jdx++ ) |
|
4359 |
{ |
|
4360 |
if ( jdx != 0 ) |
|
4361 |
{ |
|
4362 |
mWkt += ", "; |
|
4363 |
} |
|
4364 |
mWkt += "[ "; |
|
4365 |
ptr += 5; // skip type since we know its 2 |
|
4366 |
nPoints = ( int * ) ptr; |
|
4367 |
ptr += sizeof( int ); |
|
4368 |
for ( idx = 0; idx < *nPoints; idx++ ) |
|
4369 |
{ |
|
4370 |
if ( idx != 0 ) |
|
4371 |
{ |
|
4372 |
mWkt += ", "; |
|
4373 |
} |
|
4374 |
mWkt += "["; |
|
4375 |
x = ( double * ) ptr; |
|
4376 |
mWkt += QString::number( *x, 'f', 6 ); |
|
4377 |
ptr += sizeof( double ); |
|
4378 |
mWkt += ", "; |
|
4379 |
y = ( double * ) ptr; |
|
4380 |
mWkt += QString::number( *y, 'f', 6 ); |
|
4381 |
ptr += sizeof( double ); |
|
4382 |
if ( hasZValue ) |
|
4383 |
{ |
|
4384 |
ptr += sizeof( double ); |
|
4385 |
} |
|
4386 |
mWkt += "]"; |
|
4387 |
} |
|
4388 |
mWkt += " ]"; |
|
4389 |
} |
|
4390 |
mWkt += " ] }"; |
|
4391 |
return mWkt; |
|
4392 |
} |
|
4393 | ||
4394 |
case QGis::WKBMultiPolygon25D: |
|
4395 |
hasZValue = true; |
|
4396 |
case QGis::WKBMultiPolygon: |
|
4397 |
{ |
|
4398 |
QgsDebugMsg( "MULTIPOLYGON found" ); |
|
4399 |
unsigned char *ptr; |
|
4400 |
int idx, jdx, kdx; |
|
4401 |
int *numPolygons, *numRings, *nPoints; |
|
4402 | ||
4403 |
mWkt += "{ \"type\": \"MultiPolygon\", \"coordinates\": [ "; |
|
4404 |
ptr = mGeometry + 5; |
|
4405 |
numPolygons = ( int * ) ptr; |
|
4406 |
ptr = mGeometry + 9; |
|
4407 |
for ( kdx = 0; kdx < *numPolygons; kdx++ ) |
|
4408 |
{ |
|
4409 |
if ( kdx != 0 ) |
|
4410 |
{ |
|
4411 |
mWkt += ", "; |
|
4412 |
} |
|
4413 |
mWkt += "[ "; |
|
4414 |
ptr += 5; |
|
4415 |
numRings = ( int * ) ptr; |
|
4416 |
ptr += 4; |
|
4417 |
for ( idx = 0; idx < *numRings; idx++ ) |
|
4418 |
{ |
|
4419 |
if ( idx != 0 ) |
|
4420 |
{ |
|
4421 |
mWkt += ", "; |
|
4422 |
} |
|
4423 |
mWkt += "[ "; |
|
4424 |
nPoints = ( int * ) ptr; |
|
4425 |
ptr += 4; |
|
4426 |
for ( jdx = 0; jdx < *nPoints; jdx++ ) |
|
4427 |
{ |
|
4428 |
if ( jdx != 0 ) |
|
4429 |
{ |
|
4430 |
mWkt += ", "; |
|
4431 |
} |
|
4432 |
mWkt += "["; |
|
4433 |
x = ( double * ) ptr; |
|
4434 |
mWkt += QString::number( *x, 'f', 6 ); |
|
4435 |
ptr += sizeof( double ); |
|
4436 |
mWkt += ", "; |
|
4437 |
y = ( double * ) ptr; |
|
4438 |
mWkt += QString::number( *y, 'f', 6 ); |
|
4439 |
ptr += sizeof( double ); |
|
4440 |
if ( hasZValue ) |
|
4441 |
{ |
|
4442 |
ptr += sizeof( double ); |
|
4443 |
} |
|
4444 |
mWkt += "]"; |
|
4445 |
} |
|
4446 |
mWkt += " ]"; |
|
4447 |
} |
|
4448 |
mWkt += " ]"; |
|
4449 |
} |
|
4450 |
mWkt += " ] }"; |
|
4451 |
return mWkt; |
|
4452 |
} |
|
4453 | ||
4454 |
default: |
|
4455 |
QgsDebugMsg( "error: mGeometry type not recognized" ); |
|
4456 |
return QString::null; |
|
4457 |
} |
|
4458 |
} |
|
4459 | ||
4170 | 4460 |
bool QgsGeometry::exportWkbToGeos() |
4171 | 4461 |
{ |
4172 | 4462 |
QgsDebugMsgLevel( "entered.", 3 ); |
src/core/qgsgeometry.h | ||
---|---|---|
360 | 360 |
*/ |
361 | 361 |
QString exportToWkt(); |
362 | 362 | |
363 |
/** Exports the geometry to mGeoJSON |
|
364 |
@return true in case of success and false else |
|
365 |
*/ |
|
366 |
QString exportToGeoJSON(); |
|
367 | ||
363 | 368 |
/* Accessor functions for getting geometry data */ |
364 | 369 | |
365 | 370 |
/** return contents of the geometry as a point |
src/mapserver/CMakeLists.txt | ||
---|---|---|
28 | 28 |
qgssldparser.cpp |
29 | 29 |
qgssldrenderer.cpp |
30 | 30 |
qgswmsserver.cpp |
31 |
qgswfsserver.cpp |
|
31 | 32 |
qgsmapserviceexception.cpp |
32 | 33 |
qgsmslayercache.cpp |
33 | 34 |
qgsfilter.cpp |
src/mapserver/qgis_map_serv.cpp | ||
---|---|---|
26 | 26 |
#include "qgsproviderregistry.h" |
27 | 27 |
#include "qgslogger.h" |
28 | 28 |
#include "qgswmsserver.h" |
29 |
#include "qgswfsserver.h" |
|
29 | 30 |
#include "qgsmaprenderer.h" |
30 | 31 |
#include "qgsmapserviceexception.h" |
31 | 32 |
#include "qgsprojectparser.h" |
... | ... | |
264 | 265 | |
265 | 266 |
//request to WMS? |
266 | 267 |
QString serviceString; |
267 |
#ifndef QGISDEBUG |
|
268 |
serviceString = parameterMap.value( "SERVICE", "WMS" ); |
|
269 |
#else |
|
270 | 268 |
paramIt = parameterMap.find( "SERVICE" ); |
271 | 269 |
if ( paramIt == parameterMap.constEnd() ) |
272 | 270 |
{ |
271 |
#ifndef QGISDEBUG |
|
272 |
serviceString = parameterMap.value( "SERVICE", "WMS" ); |
|
273 |
#else |
|
273 | 274 |
QgsDebugMsg( "unable to find 'SERVICE' parameter, exiting..." ); |
274 | 275 |
theRequestHandler->sendServiceException( QgsMapServiceException( "ServiceNotSpecified", "Service not specified. The SERVICE parameter is mandatory" ) ); |
275 | 276 |
delete theRequestHandler; |
276 | 277 |
continue; |
278 |
#endif |
|
277 | 279 |
} |
278 | 280 |
else |
279 | 281 |
{ |
280 | 282 |
serviceString = paramIt.value(); |
281 | 283 |
} |
282 |
#endif |
|
283 | 284 | |
284 | 285 |
QgsWMSServer* theServer = 0; |
286 |
if ( serviceString == "WFS" ) |
|
287 |
{ |
|
288 |
delete theServer; |
|
289 |
QgsWFSServer* theServer = 0; |
|
290 |
try |
|
291 |
{ |
|
292 |
theServer = new QgsWFSServer( parameterMap ); |
|
293 |
} |
|
294 |
catch ( QgsMapServiceException e ) //admin.sld may be invalid |
|
295 |
{ |
|
296 |
theRequestHandler->sendServiceException( e ); |
|
297 |
continue; |
|
298 |
} |
|
299 | ||
300 |
theServer->setAdminConfigParser( adminConfigParser ); |
|
301 | ||
302 | ||
303 |
//request type |
|
304 |
QString request = parameterMap.value( "REQUEST" ); |
|
305 |
if ( request.isEmpty() ) |
|
306 |
{ |
|
307 |
//do some error handling |
|
308 |
QgsDebugMsg( "unable to find 'REQUEST' parameter, exiting..." ); |
|
309 |
theRequestHandler->sendServiceException( QgsMapServiceException( "OperationNotSupported", "Please check the value of the REQUEST parameter" ) ); |
|
310 |
delete theRequestHandler; |
|
311 |
delete theServer; |
|
312 |
continue; |
|
313 |
} |
|
314 | ||
315 |
if ( request == "GetCapabilities" ) |
|
316 |
{ |
|
317 |
QDomDocument capabilitiesDocument; |
|
318 |
try |
|
319 |
{ |
|
320 |
capabilitiesDocument = theServer->getCapabilities(); |
|
321 |
} |
|
322 |
catch ( QgsMapServiceException& ex ) |
|
323 |
{ |
|
324 |
theRequestHandler->sendServiceException( ex ); |
|
325 |
delete theRequestHandler; |
|
326 |
delete theServer; |
|
327 |
continue; |
|
328 |
} |
|
329 |
QgsDebugMsg( "sending GetCapabilities response" ); |
|
330 |
theRequestHandler->sendGetCapabilitiesResponse( capabilitiesDocument ); |
|
331 |
delete theRequestHandler; |
|
332 |
delete theServer; |
|
333 |
continue; |
|
334 |
} |
|
335 |
else if ( request == "DescribeFeatureType" ) |
|
336 |
{ |
|
337 |
QDomDocument describeDocument; |
|
338 |
try |
|
339 |
{ |
|
340 |
describeDocument = theServer->describeFeatureType(); |
|
341 |
} |
|
342 |
catch ( QgsMapServiceException& ex ) |
|
343 |
{ |
|
344 |
theRequestHandler->sendServiceException( ex ); |
|
345 |
delete theRequestHandler; |
|
346 |
delete theServer; |
|
347 |
continue; |
|
348 |
} |
|
349 |
QgsDebugMsg( "sending GetCapabilities response" ); |
|
350 |
theRequestHandler->sendGetCapabilitiesResponse( describeDocument ); |
|
351 |
delete theRequestHandler; |
|
352 |
delete theServer; |
|
353 |
continue; |
|
354 |
} |
|
355 |
else if ( request == "GetFeature" ) |
|
356 |
{ |
|
357 |
//output format for GetFeature |
|
358 |
QString outputFormat = parameterMap.value( "OUTPUTFORMAT" ); |
|
359 |
try |
|
360 |
{ |
|
361 |
if ( theServer->getFeature( *theRequestHandler, outputFormat ) != 0 ) |
|
362 |
{ |
|
363 |
delete theRequestHandler; |
|
364 |
delete theServer; |
|
365 |
continue; |
|
366 |
} else { |
|
367 |
delete theRequestHandler; |
|
368 |
delete theServer; |
|
369 |
continue; |
|
370 |
} |
|
371 |
} |
|
372 |
catch ( QgsMapServiceException& ex ) |
|
373 |
{ |
|
374 |
theRequestHandler->sendServiceException( ex ); |
|
375 |
delete theRequestHandler; |
|
376 |
delete theServer; |
|
377 |
continue; |
|
378 |
} |
|
379 |
} |
|
380 | ||
381 |
return 0; |
|
382 |
} |
|
383 | ||
285 | 384 |
try |
286 | 385 |
{ |
287 | 386 |
theServer = new QgsWMSServer( parameterMap, theMapRenderer ); |
src/mapserver/qgsconfigparser.h | ||
---|---|---|
41 | 41 |
/**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.*/ |
42 | 42 |
virtual void layersAndStylesCapabilities( QDomElement& parentElement, QDomDocument& doc ) const = 0; |
43 | 43 | |
44 |
virtual void featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const = 0; |
|
45 | ||
44 | 46 |
/**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. |
45 | 47 |
If no layers/style are found, an empty list is returned |
46 | 48 |
@param allowCache true if layer can be read from / written to cache*/ |
src/mapserver/qgshttprequesthandler.cpp | ||
---|---|---|
277 | 277 |
sendHttpResponse( ba, formatToMimeType( mFormat ) ); |
278 | 278 |
} |
279 | 279 | |
280 |
bool QgsHttpRequestHandler::startGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const |
|
281 |
{ |
|
282 |
if ( !ba ) |
|
283 |
{ |
|
284 |
return false; |
|
285 |
} |
|
286 | ||
287 |
if ( ba->size() < 1 ) |
|
288 |
{ |
|
289 |
return false; |
|
290 |
} |
|
291 | ||
292 |
QString format; |
|
293 |
if (infoFormat == "GeoJSON") |
|
294 |
format = "text/plain"; |
|
295 |
else |
|
296 |
format = "text/xml"; |
|
297 | ||
298 |
printf( "Content-Type: " ); |
|
299 |
printf( format.toLocal8Bit() ); |
|
300 |
printf( "\n" ); |
|
301 |
printf( "\n" ); |
|
302 |
fwrite( ba->data(), ba->size(), 1, FCGI_stdout ); |
|
303 |
return true; |
|
304 |
} |
|
305 | ||
306 |
void QgsHttpRequestHandler::sendGetFeatureResponse( QByteArray* ba ) const |
|
307 |
{ |
|
308 |
if ( !ba ) |
|
309 |
{ |
|
310 |
return; |
|
311 |
} |
|
312 | ||
313 |
if ( ba->size() < 1 ) |
|
314 |
{ |
|
315 |
return; |
|
316 |
} |
|
317 |
fwrite( ba->data(), ba->size(), 1, FCGI_stdout ); |
|
318 |
} |
|
319 | ||
320 |
void QgsHttpRequestHandler::endGetFeatureResponse( QByteArray* ba ) const |
|
321 |
{ |
|
322 |
if ( !ba ) |
|
323 |
{ |
|
324 |
return; |
|
325 |
} |
|
326 | ||
327 |
fwrite( ba->data(), ba->size(), 1, FCGI_stdout ); |
|
328 |
} |
|
329 | ||
280 | 330 |
void QgsHttpRequestHandler::requestStringToParameterMap( const QString& request, QMap<QString, QString>& parameters ) |
281 | 331 |
{ |
282 | 332 |
parameters.clear(); |
src/mapserver/qgshttprequesthandler.h | ||
---|---|---|
34 | 34 |
virtual void sendServiceException( const QgsMapServiceException& ex ) const; |
35 | 35 |
virtual void sendGetStyleResponse( const QDomDocument& doc ) const; |
36 | 36 |
virtual void sendGetPrintResponse( QByteArray* ba ) const; |
37 |
virtual bool startGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const; |
|
38 |
virtual void sendGetFeatureResponse( QByteArray* ba ) const; |
|
39 |
virtual void endGetFeatureResponse( QByteArray* ba ) const; |
|
37 | 40 | |
38 | 41 |
protected: |
39 | 42 |
void sendHttpResponse( QByteArray* ba, const QString& format ) const; |
src/mapserver/qgsprojectparser.cpp | ||
---|---|---|
138 | 138 |
combineExtentAndCrsOfGroupChildren( layerParentElem, doc ); |
139 | 139 |
} |
140 | 140 | |
141 |
void QgsProjectParser::featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const |
|
142 |
{ |
|
143 |
QStringList nonIdentifiableLayers = identifyDisabledLayers(); |
|
144 | ||
145 |
if ( mProjectLayerElements.size() < 1 ) |
|
146 |
{ |
|
147 |
return; |
|
148 |
} |
|
149 | ||
150 |
QMap<QString, QgsMapLayer *> layerMap; |
|
151 | ||
152 |
foreach( const QDomElement &elem, mProjectLayerElements ) |
|
153 |
{ |
|
154 |
QString type = elem.attribute( "type" ); |
|
155 |
if ( type == "vector" ) |
|
156 |
{ |
|
157 |
//QgsMapLayer *layer = createLayerFromElement( *layerIt ); |
|
158 |
QgsMapLayer *layer = createLayerFromElement( elem ); |
|
159 |
if ( layer ) |
|
160 |
{ |
|
161 |
QgsDebugMsg( QString( "add layer %1 to map" ).arg( layer->id() ) ); |
|
162 |
layerMap.insert( layer->id(), layer ); |
|
163 | ||
164 |
QDomElement layerElem = doc.createElement( "FeatureType" ); |
|
165 |
QDomElement nameElem = doc.createElement( "Name" ); |
|
166 |
//We use the layer name even though it might not be unique. |
|
167 |
//Because the id sometimes contains user/pw information and the name is more descriptive |
|
168 |
QDomText nameText = doc.createTextNode( layer->name() ); |
|
169 |
nameElem.appendChild( nameText ); |
|
170 |
layerElem.appendChild( nameElem ); |
|
171 | ||
172 |
QDomElement titleElem = doc.createElement( "Title" ); |
|
173 |
QDomText titleText = doc.createTextNode( layer->name() ); |
|
174 |
titleElem.appendChild( titleText ); |
|
175 |
layerElem.appendChild( titleElem ); |
|
176 | ||
177 |
//appendExGeographicBoundingBox( layerElem, doc, layer->extent(), layer->crs() ); |
|
178 | ||
179 |
QDomElement srsElem = doc.createElement( "SRS" ); |
|
180 |
QDomText srsText = doc.createTextNode( layer->crs().authid() ); |
|
181 |
srsElem.appendChild( srsText ); |
|
182 |
layerElem.appendChild( srsElem ); |
|
183 | ||
184 |
QgsRectangle layerExtent = layer->extent(); |
|
185 |
QDomElement bBoxElement = doc.createElement( "LatLongBoundingBox" ); |
|
186 |
bBoxElement.setAttribute( "minx", QString::number( layerExtent.xMinimum() ) ); |
|
187 |
bBoxElement.setAttribute( "miny", QString::number( layerExtent.yMinimum() ) ); |
|
188 |
bBoxElement.setAttribute( "maxx", QString::number( layerExtent.xMaximum() ) ); |
|
189 |
bBoxElement.setAttribute( "maxy", QString::number( layerExtent.yMaximum() ) ); |
|
190 |
layerElem.appendChild( bBoxElement ); |
|
191 | ||
192 |
parentElement.appendChild(layerElem); |
|
193 |
} |
|
194 |
#if QGSMSDEBUG |
|
195 |
else |
|
196 |
{ |
|
197 |
QString buf; |
|
198 |
QTextStream s( &buf ); |
|
199 |
layerIt->save( s, 0 ); |
|
200 |
QgsMSDebugMsg( QString( "layer %1 not found" ).arg( buf ) ); |
|
201 |
} |
|
202 |
#endif |
|
203 |
} |
|
204 |
} |
|
205 |
return; |
|
206 |
} |
|
207 | ||
141 | 208 |
void QgsProjectParser::addLayers( QDomDocument &doc, |
142 | 209 |
QDomElement &parentElem, |
143 | 210 |
const QDomElement &legendElem, |
src/mapserver/qgsprojectparser.h | ||
---|---|---|
38 | 38 |
/**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.*/ |
39 | 39 |
virtual void layersAndStylesCapabilities( QDomElement& parentElement, QDomDocument& doc ) const; |
40 | 40 | |
41 |
virtual void featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const; |
|
42 | ||
41 | 43 |
int numberOfLayers() const; |
42 | 44 | |
43 | 45 |
/**Returns one or possibly several maplayers for a given layer name and style. If no layers/style are found, an empty list is returned*/ |
src/mapserver/qgsrequesthandler.h | ||
---|---|---|
41 | 41 |
virtual void sendServiceException( const QgsMapServiceException& ex ) const = 0; |
42 | 42 |
virtual void sendGetStyleResponse( const QDomDocument& doc ) const = 0; |
43 | 43 |
virtual void sendGetPrintResponse( QByteArray* ba ) const = 0; |
44 |
virtual bool startGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const = 0; |
|
45 |
virtual void sendGetFeatureResponse( QByteArray* ba ) const = 0; |
|
46 |
virtual void endGetFeatureResponse( QByteArray* ba ) const = 0; |
|
44 | 47 |
QString format() const { return mFormat; } |
45 | 48 |
protected: |
46 | 49 |
/**This is set by the parseInput methods of the subclasses (parameter FORMAT, e.g. 'FORMAT=PNG')*/ |
src/mapserver/qgssldparser.h | ||
---|---|---|
56 | 56 |
/**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.*/ |
57 | 57 |
void layersAndStylesCapabilities( QDomElement& parentElement, QDomDocument& doc ) const; |
58 | 58 | |
59 |
void featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const {}; |
|
60 | ||
59 | 61 |
/**Returns number of layers in configuration*/ |
60 | 62 |
int numberOfLayers() const; |
61 | 63 |
src/mapserver/qgswfsserver.cpp | ||
---|---|---|
1 |
#include "qgswfsserver.h" |
|
2 |
#include "qgsconfigparser.h" |
|
3 |
#include "qgscrscache.h" |
|
4 |
#include "qgsfield.h" |
|
5 |
#include "qgsgeometry.h" |
|
6 |
#include "qgsmaplayer.h" |
|
7 |
#include "qgsmaplayerregistry.h" |
|
8 |
#include "qgsmaprenderer.h" |
|
9 |
#include "qgsmaptopixel.h" |
|
10 |
#include "qgspallabeling.h" |
|
11 |
#include "qgsproject.h" |
|
12 |
#include "qgsrasterlayer.h" |
|
13 |
#include "qgsscalecalculator.h" |
|
14 |
#include "qgscoordinatereferencesystem.h" |
|
15 |
#include "qgsvectordataprovider.h" |
|
16 |
#include "qgsvectorlayer.h" |
|
17 |
#include "qgsfilter.h" |
|
18 |
#include "qgslogger.h" |
|
19 |
#include "qgsmapserviceexception.h" |
|
20 |
#include "qgssldparser.h" |
|
21 |
#include "qgssymbol.h" |
|
22 |
#include "qgssymbolv2.h" |
|
23 |
#include "qgsrenderer.h" |
|
24 |
#include "qgslegendmodel.h" |
|
25 |
#include "qgscomposerlegenditem.h" |
|
26 |
#include "qgslogger.h" |
|
27 |
#include "qgsrequesthandler.h" |
|
28 |
#include <QImage> |
|
29 |
#include <QPainter> |
|
30 |
#include <QStringList> |
|
31 |
#include <QTextStream> |
|
32 |
#include <QDir> |
|
33 | ||
34 |
//for printing |
|
35 |
#include "qgscomposition.h" |
|
36 |
#include <QBuffer> |
|
37 |
#include <QPrinter> |
|
38 |
#include <QSvgGenerator> |
|
39 |
#include <QUrl> |
|
40 |
#include <QPaintEngine> |
|
41 | ||
42 |
QgsWFSServer::QgsWFSServer( QMap<QString, QString> parameters ) |
|
43 |
: mParameterMap( parameters ) |
|
44 |
, mConfigParser( 0 ) |
|
45 |
{ |
|
46 |
} |
|
47 | ||
48 |
QgsWFSServer::~QgsWFSServer() |
|
49 |
{ |
|
50 |
} |
|
51 | ||
52 |
QgsWFSServer::QgsWFSServer() |
|
53 |
{ |
|
54 |
} |
|
55 | ||
56 |
QDomDocument QgsWFSServer::getCapabilities() |
|
57 |
{ |
|
58 |
QgsDebugMsg( "Entering." ); |
|
59 |
QDomDocument doc; |
|
60 |
//wfs:WFS_Capabilities element |
|
61 |
QDomElement wfsCapabilitiesElement = doc.createElement( "WFS_Capabilities"/*wms:WFS_Capabilities*/ ); |
|
62 |
wfsCapabilitiesElement.setAttribute( "xmlns", "http://www.opengis.net/wfs" ); |
|
63 |
wfsCapabilitiesElement.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" ); |
|
64 |
wfsCapabilitiesElement.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" ); |
|
65 |
wfsCapabilitiesElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" ); |
|
66 |
wfsCapabilitiesElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" ); |
|
67 |
wfsCapabilitiesElement.setAttribute( "xmlns:ows", "http://www.opengis.net/ows" ); |
|
68 |
wfsCapabilitiesElement.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" ); |
|
69 |
wfsCapabilitiesElement.setAttribute( "version", "1.0.0" ); |
|
70 |
wfsCapabilitiesElement.setAttribute( "updateSequence", "0" ); |
|
71 |
doc.appendChild( wfsCapabilitiesElement ); |
|
72 | ||
73 |
if ( mConfigParser ) |
|
74 |
{ |
|
75 |
mConfigParser->serviceCapabilities( wfsCapabilitiesElement, doc ); |
|
76 |
} |
|
77 | ||
78 |
//wfs:Capability element |
|
79 |
QDomElement capabilityElement = doc.createElement( "Capability"/*wfs:Capability*/ ); |
|
80 |
wfsCapabilitiesElement.appendChild( capabilityElement ); |
|
81 |
|
|
82 |
//wfs:Request element |
|
83 |
QDomElement requestElement = doc.createElement( "Request"/*wfs:Request*/ ); |
|
84 |
capabilityElement.appendChild( requestElement ); |
|
85 |
//wfs:GetCapabilities |
|
86 |
QDomElement getCapabilitiesElement = doc.createElement( "GetCapabilities"/*wfs:GetCapabilities*/ ); |
|
87 |
requestElement.appendChild( getCapabilitiesElement ); |
|
88 |
QDomElement capabilitiesFormatElement = doc.createElement( "Format" );/*wfs:Format*/ |
|
89 |
getCapabilitiesElement.appendChild( capabilitiesFormatElement ); |
|
90 |
QDomText capabilitiesFormatText = doc.createTextNode( "text/xml" ); |
|
91 |
capabilitiesFormatElement.appendChild( capabilitiesFormatText ); |
|
92 | ||
93 |
QDomElement dcpTypeElement = doc.createElement( "DCPType"/*wfs:DCPType*/ ); |
|
94 |
getCapabilitiesElement.appendChild( dcpTypeElement ); |
|
95 |
QDomElement httpElement = doc.createElement( "HTTP"/*wfs:HTTP*/ ); |
|
96 |
dcpTypeElement.appendChild( httpElement ); |
|
97 | ||
98 |
//Prepare url |
|
99 |
//Some client requests already have http://<SERVER_NAME> in the REQUEST_URI variable |
|
100 |
QString hrefString; |
|
101 |
QString requestUrl = getenv( "REQUEST_URI" ); |
|
102 |
QUrl mapUrl( requestUrl ); |
|
103 |
mapUrl.setHost( QString( getenv( "SERVER_NAME" ) ) ); |
|
104 |
mapUrl.removeQueryItem( "REQUEST" ); |
|
105 |
mapUrl.removeQueryItem( "VERSION" ); |
|
106 |
mapUrl.removeQueryItem( "SERVICE" ); |
|
107 |
hrefString = mapUrl.toString(); |
|
108 | ||
109 |
//only Get supported for the moment |
|
110 |
QDomElement getElement = doc.createElement( "Get"/*wfs:Get*/ ); |
|
111 |
httpElement.appendChild( getElement ); |
|
112 |
QDomElement olResourceElement = doc.createElement( "OnlineResource"/*wfs:OnlineResource*/ ); |
|
113 |
olResourceElement.setAttribute( "xlink:type", "simple" ); |
|
114 |
requestUrl.truncate( requestUrl.indexOf( "?" ) + 1 ); |
|
115 |
olResourceElement.setAttribute( "xlink:href", hrefString ); |
|
116 |
getElement.appendChild( olResourceElement ); |
|
117 | ||
118 |
//wfs:DescribeFeatureType |
|
119 |
QDomElement describeFeatureTypeElement = doc.createElement( "DescribeFeatureType"/*wfs:DescribeFeatureType*/ ); |
|
120 |
requestElement.appendChild( describeFeatureTypeElement ); |
|
121 |
QDomElement schemaDescriptionLanguageElement = doc.createElement( "SchemaDescriptionLanguage"/*wfs:SchemaDescriptionLanguage*/ ); |
|
122 |
describeFeatureTypeElement.appendChild( schemaDescriptionLanguageElement ); |
|
123 |
QDomElement xmlSchemaElement = doc.createElement( "XMLSCHEMA"/*wfs:XMLSCHEMA*/ ); |
|
124 |
schemaDescriptionLanguageElement.appendChild( xmlSchemaElement ); |
|
125 |
QDomElement describeFeatureTypeDhcTypeElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities' |
|
126 |
describeFeatureTypeElement.appendChild( describeFeatureTypeDhcTypeElement ); |
|
127 | ||
128 |
//wfs:GetFeature |
|
129 |
QDomElement getFeatureElement = doc.createElement( "GetFeature"/*wfs:GetFeature*/ ); |
|
130 |
requestElement.appendChild( getFeatureElement ); |
|
131 |
QDomElement getFeatureFormatElement = doc.createElement( "ResultFormat" );/*wfs:ResultFormat*/ |
|
132 |
getFeatureElement.appendChild( getFeatureFormatElement ); |
|
133 |
QDomElement gmlFormatElement = doc.createElement( "GML2" );/*wfs:GML2*/ |
|
134 |
getFeatureFormatElement.appendChild( gmlFormatElement ); |
|
135 |
QDomElement geojsonFormatElement = doc.createElement( "GeoJSON" );/*wfs:GeoJSON*/ |
|
136 |
getFeatureFormatElement.appendChild( geojsonFormatElement ); |
|
137 |
QDomElement getFeatureDhcTypeElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities' |
|
138 |
getFeatureElement.appendChild( getFeatureDhcTypeElement ); |
|
139 | ||
140 |
//wfs:FeatureTypeList element |
|
141 |
QDomElement featureTypeListElement = doc.createElement( "FeatureTypeList"/*wfs:FeatureTypeList*/ ); |
|
142 |
capabilityElement.appendChild( featureTypeListElement ); |
|
143 |
//wfs:Operations element |
|
144 |
QDomElement operationsElement = doc.createElement( "Operations"/*wfs:Operations*/ ); |
|
145 |
featureTypeListElement.appendChild( operationsElement ); |
|
146 |
//wfs:Query element |
|
147 |
QDomElement queryElement = doc.createElement( "Query"/*wfs:Query*/ ); |
|
148 |
operationsElement.appendChild( queryElement ); |
|
149 |
/* |
|
150 |
* Adding layer liste in featureTypeListElement |
|
151 |
*/ |
|
152 |
if ( mConfigParser ) |
|
153 |
{ |
|
154 |
mConfigParser->featureTypeList( featureTypeListElement, doc ); |
|
155 |
} |
|
156 | ||
157 |
/* |
|
158 |
* Adding ogc:Filter_Capabilities in capabilityElement |
|
159 |
*/ |
|
160 |
//ogc:Filter_Capabilities element |
|
161 |
QDomElement filterCapabilitiesElement = doc.createElement( "ogc:Filter_Capabilities"/*ogc:Filter_Capabilities*/ ); |
|
162 |
capabilityElement.appendChild( filterCapabilitiesElement ); |
|
163 |
QDomElement spatialCapabilitiesElement = doc.createElement( "ogc:Spatial_Capabilities"/*ogc:Spatial_Capabilities*/ ); |
|
164 |
filterCapabilitiesElement.appendChild( spatialCapabilitiesElement ); |
|
165 |
QDomElement spatialOperatorsElement = doc.createElement( "ogc:Spatial_Operators"/*ogc:Spatial_Operators*/ ); |
|
166 |
spatialCapabilitiesElement.appendChild( spatialOperatorsElement ); |
|
167 |
QDomElement ogcBboxElement = doc.createElement( "ogc:BBOX"/*ogc:BBOX*/ ); |
|
168 |
spatialOperatorsElement.appendChild( ogcBboxElement ); |
|
169 |
QDomElement scalarCapabilitiesElement = doc.createElement( "ogc:Scalar_Capabilities"/*ogc:Scalar_Capabilities*/ ); |
|
170 |
filterCapabilitiesElement.appendChild( scalarCapabilitiesElement ); |
|
171 |
QDomElement comparisonOperatorsElement = doc.createElement( "ogc:Comparison_Operators"/*ogc:Comparison_Operators*/ ); |
|
172 |
scalarCapabilitiesElement.appendChild( comparisonOperatorsElement ); |
|
173 |
QDomElement simpleComparisonsElement = doc.createElement( "ogc:Simple_Comparisons"/*ogc:Simple_Comparisons*/ ); |
|
174 |
comparisonOperatorsElement.appendChild( simpleComparisonsElement ); |
|
175 |
return doc; |
|
176 |
} |
|
177 | ||
178 |
QDomDocument QgsWFSServer::describeFeatureType() |
|
179 |
{ |
|
180 |
QgsDebugMsg( "Entering." ); |
|
181 |
QDomDocument doc; |
|
182 |
//xsd:schema |
|
183 |
QDomElement schemaElement = doc.createElement( "schema"/*xsd:schema*/ ); |
|
184 |
schemaElement.setAttribute( "xmlns", "http://www.w3.org/2001/XMLSchema" ); |
|
185 |
schemaElement.setAttribute( "xmlns:xsd", "http://www.w3.org/2001/XMLSchema" ); |
|
186 |
schemaElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" ); |
|
187 |
schemaElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" ); |
|
188 |
schemaElement.setAttribute( "xmlns:qgs", "http://www.qgis.org/gml" ); |
|
189 |
schemaElement.setAttribute( "targetNamespace", "http://www.qgis.org/gml" ); |
|
190 |
doc.appendChild( schemaElement ); |
|
191 | ||
192 |
//xsd:import |
|
193 |
QDomElement importElement = doc.createElement( "import"/*xsd:import*/ ); |
|
194 |
importElement.setAttribute( "namespace", "http://www.opengis.net/gml" ); |
|
195 |
importElement.setAttribute( "schemaLocation", "http://schemas.opengis.net/gml/2.1.2/feature.xsd" ); |
|
196 |
schemaElement.appendChild( importElement ); |
|
197 | ||
198 |
//read TYPENAME |
|
199 |
QString typeName; |
|
200 |
QMap<QString, QString>::const_iterator type_name_it = mParameterMap.find( "TYPENAME" ); |
|
201 |
if ( type_name_it != mParameterMap.end() ) |
|
202 |
{ |
|
203 |
typeName = type_name_it.value(); |
|
204 |
} |
|
205 |
else |
|
206 |
{ |
|
207 |
return doc; |
|
208 |
} |
|
209 | ||
210 |
QStringList nonIdentifiableLayers = mConfigParser->identifyDisabledLayers(); |
|
211 |
QMap< QString, QMap< int, QString > > aliasInfo = mConfigParser->layerAliasInfo(); |
|
212 |
QMap< QString, QSet<QString> > hiddenAttributes = mConfigParser->hiddenAttributes(); |
|
213 |
|
|
214 |
QList<QgsMapLayer*> layerList; |
|
215 |
QgsMapLayer* currentLayer = 0; |
|
216 | ||
217 |
layerList = mConfigParser->mapLayerFromStyle( typeName, "" ); |
|
218 |
currentLayer = layerList.at( 0 ); |
|
219 |
|
|
220 |
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>( currentLayer ); |
|
221 |
if ( layer ) |
|
222 |
{ |
|
223 |
//is there alias info for this vector layer? |
|
224 |
QMap< int, QString > layerAliasInfo; |
|
225 |
QMap< QString, QMap< int, QString > >::const_iterator aliasIt = aliasInfo.find( currentLayer->id() ); |
|
226 |
if ( aliasIt != aliasInfo.constEnd() ) |
|
227 |
{ |
|
228 |
layerAliasInfo = aliasIt.value(); |
|
229 |
} |
|
230 | ||
231 |
//hidden attributes for this layer |
|
232 |
QSet<QString> layerHiddenAttributes; |
|
233 |
QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find( currentLayer->id() ); |
|
234 |
if ( hiddenIt != hiddenAttributes.constEnd() ) |
|
235 |
{ |
|
236 |
layerHiddenAttributes = hiddenIt.value(); |
|
237 |
} |
|
238 |
|
|
239 |
//do a select with searchRect and go through all the features |
|
240 |
QgsVectorDataProvider* provider = layer->dataProvider(); |
|
241 |
if ( !provider ) |
|
242 |
{ |
|
243 |
return doc; |
|
244 |
} |
|
245 | ||
246 |
typeName = typeName.replace( QString(" "), QString("_") ); |
|
247 |
|
|
248 |
//xsd:element |
|
249 |
QDomElement elementElem = doc.createElement( "element"/*xsd:element*/ ); |
|
250 |
elementElem.setAttribute( "name", typeName ); |
|
251 |
elementElem.setAttribute( "type", "qgs:" + typeName + "Type" ); |
|
252 |
elementElem.setAttribute( "substitutionGroup", "gml:_Feature" ); |
|
253 |
schemaElement.appendChild( elementElem ); |
|
254 | ||
255 |
//xsd:complexType |
|
256 |
QDomElement complexTypeElem = doc.createElement( "complexType"/*xsd:complexType*/ ); |
|
257 |
complexTypeElem.setAttribute( "name", typeName + "Type" ); |
|
258 |
schemaElement.appendChild( complexTypeElem ); |
|
259 | ||
260 |
//xsd:complexType |
|
261 |
QDomElement complexContentElem = doc.createElement( "complexContent"/*xsd:complexContent*/ ); |
|
262 |
complexTypeElem.appendChild( complexContentElem ); |
|
263 | ||
264 |
//xsd:extension |
|
265 |
QDomElement extensionElem = doc.createElement( "extension"/*xsd:extension*/ ); |
|
266 |
extensionElem.setAttribute( "base", "gml:AbstractFeatureType" ); |
|
267 |
complexContentElem.appendChild( extensionElem ); |
|
268 | ||
269 |
//xsd:sequence |
|
270 |
QDomElement sequenceElem = doc.createElement( "sequence"/*xsd:sequence*/ ); |
|
271 |
extensionElem.appendChild( sequenceElem ); |
|
272 | ||
273 |
//xsd:element |
|
274 |
QDomElement geomElem = doc.createElement( "element"/*xsd:element*/ ); |
|
275 |
geomElem.setAttribute( "name", "geometry" ); |
|
276 |
geomElem.setAttribute( "type", "gml:GeometryPropertyType" ); |
|
277 |
geomElem.setAttribute( "minOccurs", "0" ); |
|
278 |
geomElem.setAttribute( "maxOccurs", "1" ); |
|
279 |
sequenceElem.appendChild( geomElem ); |
|
280 | ||
281 |
const QgsFieldMap& fields = provider->fields(); |
|
282 |
for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it ) |
|
283 |
{ |
|
284 | ||
285 |
QString attributeName = it.value().name(); |
|
286 |
//skip attribute if it has edit type 'hidden' |
|
287 |
if ( layerHiddenAttributes.contains( attributeName ) ) |
|
288 |
{ |
|
289 |
continue; |
|
290 |
} |
|
291 | ||
292 |
//check if the attribute name should be replaced with an alias |
|
293 |
QMap<int, QString>::const_iterator aliasIt = layerAliasInfo.find( it.key() ); |
|
294 |
if ( aliasIt != layerAliasInfo.constEnd() ) |
|
295 |
{ |
|
296 |
attributeName = aliasIt.value(); |
|
297 |
} |
|
298 | ||
299 |
//xsd:element |
|
300 |
QDomElement geomElem = doc.createElement( "element"/*xsd:element*/ ); |
|
301 |
geomElem.setAttribute( "name", attributeName ); |
|
302 |
if ( it.value().type() == 2 ) |
|
303 |
geomElem.setAttribute( "type", "integer" ); |
|
304 |
else if ( it.value().type() == 6 ) |
|
305 |
geomElem.setAttribute( "type", "double" ); |
|
306 |
else |
|
307 |
geomElem.setAttribute( "type", "string" ); |
|
308 | ||
309 |
sequenceElem.appendChild( geomElem ); |
|
310 | ||
311 |
} |
|
312 |
} |
|
313 | ||
314 |
return doc; |
|
315 |
} |
|
316 | ||
317 |
int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format ) |
|
318 |
{ |
|
319 |
QByteArray result; |
|
320 |
QgsDebugMsg( "Info format is:" + infoFormat ); |
|
321 | ||
322 |
//read TYPENAME |
|
323 |
QString typeName; |
|
324 |
QMap<QString, QString>::const_iterator type_name_it = mParameterMap.find( "TYPENAME" ); |
|
325 |
if ( type_name_it != mParameterMap.end() ) |
|
326 |
{ |
|
327 |
typeName = type_name_it.value(); |
|
328 |
} |
|
329 |
else |
|
330 |
{ |
|
331 |
return 1; |
|
332 |
} |
|
333 | ||
334 |
QStringList nonIdentifiableLayers = mConfigParser->identifyDisabledLayers(); |
|
335 |
QMap< QString, QMap< int, QString > > aliasInfo = mConfigParser->layerAliasInfo(); |
|
336 |
QMap< QString, QSet<QString> > hiddenAttributes = mConfigParser->hiddenAttributes(); |
|
337 |
|
|
338 |
QList<QgsMapLayer*> layerList; |
|
339 |
QgsMapLayer* currentLayer = 0; |
|
340 | ||
341 |
layerList = mConfigParser->mapLayerFromStyle( typeName, "" ); |
|
342 |
currentLayer = layerList.at( 0 ); |
|
343 |
|
|
344 |
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>( currentLayer ); |
|
345 |
if ( layer ) |
|
346 |
{ |
|
347 |
//is there alias info for this vector layer? |
|
348 |
QMap< int, QString > layerAliasInfo; |
|
349 |
QMap< QString, QMap< int, QString > >::const_iterator aliasIt = aliasInfo.find( currentLayer->id() ); |
|
350 |
if ( aliasIt != aliasInfo.constEnd() ) |
|
351 |
{ |
|
352 |
layerAliasInfo = aliasIt.value(); |
|
353 |
} |
|
354 | ||
355 |
//hidden attributes for this layer |
|
356 |
QSet<QString> layerHiddenAttributes; |
|
357 |
QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find( currentLayer->id() ); |
|
358 |
if ( hiddenIt != hiddenAttributes.constEnd() ) |
|
359 |
{ |
|
360 |
layerHiddenAttributes = hiddenIt.value(); |
|
361 |
} |
|
362 |
|
|
363 |
//do a select with searchRect and go through all the features |
|
364 |
QgsVectorDataProvider* provider = layer->dataProvider(); |
|
365 |
if ( !provider ) |
|
366 |
{ |
|
367 |
return 2; |
|
368 |
} |
|
369 | ||
370 |
QgsFeature feature; |
|
371 |
QgsAttributeMap featureAttributes; |
|
372 |
const QgsFieldMap& fields = provider->fields(); |
|
373 | ||
374 |
//map extent |
|
375 |
QgsRectangle searchRect = layer->extent(); |
|
376 | ||
377 |
//read FEATUREDID |
|
378 |
bool fidOk = false; |
|
379 |
QString fid; |
|
380 |
QMap<QString, QString>::const_iterator fidIt = mParameterMap.find( "FEATUREID" ); |
|
381 |
if ( fidIt != mParameterMap.end() ) { |
|
382 |
fidOk = true; |
|
383 |
fid = fidIt.value(); |
|
384 |
} |
|
385 | ||
386 |
//read FILTER |
|
387 |
bool filterOk = false; |
|
388 |
QDomDocument filter; |
|
389 |
QMap<QString, QString>::const_iterator filterIt = mParameterMap.find( "FILTER" ); |
|
390 |
if ( filterIt != mParameterMap.end() ) { |
|
391 |
try { |
|
392 |
QString errorMsg; |
|
393 |
if ( !filter.setContent( filterIt.value(), true, &errorMsg ) ) |
|
394 |
{ |
|
395 |
QgsDebugMsg( "soap request parse error" ); |
|
396 |
QgsDebugMsg( "error message: " + errorMsg ); |
|
397 |
QgsDebugMsg( "the xml string was:" ); |
|
398 |
QgsDebugMsg( filterIt.value() ); |
|
399 |
} |
|
400 |
else |
|
401 |
{ |
|
402 |
filterOk = true; |
|
403 |
} |
|
404 |
} catch(QgsMapServiceException& e ) { |
|
405 |
filterOk = false; |
|
406 |
} |
|
407 |
} |
|
408 | ||
409 | ||
410 |
bool conversionSuccess; |
|
411 |
double minx, miny, maxx, maxy; |
|
412 |
bool bboxOk = false; |
|
413 |
//read BBOX |
|
414 |
QMap<QString, QString>::const_iterator bbIt = mParameterMap.find( "BBOX" ); |
|
415 |
if ( bbIt == mParameterMap.end() ) |
|
416 |
{ |
|
417 |
minx = 0; miny = 0; maxx = 0; maxy = 0; |
|
418 |
} |
|
419 |
else |
|
420 |
{ |
|
421 |
bboxOk = true; |
|
422 |
QString bbString = bbIt.value(); |
|
423 |
minx = bbString.section( ",", 0, 0 ).toDouble( &conversionSuccess ); |
|
424 |
if ( !conversionSuccess ) {bboxOk = false;} |
|
425 |
miny = bbString.section( ",", 1, 1 ).toDouble( &conversionSuccess ); |
|
426 |
if ( !conversionSuccess ) {bboxOk = false;} |
|
427 |
maxx = bbString.section( ",", 2, 2 ).toDouble( &conversionSuccess ); |
|
428 |
if ( !conversionSuccess ) {bboxOk = false;} |
|
429 |
maxy = bbString.section( ",", 3, 3 ).toDouble( &conversionSuccess ); |
|
430 |
if ( !conversionSuccess ) {bboxOk = false;} |
|
431 |
} |
|
432 | ||
433 |
//read MAXFEATURES |
|
434 |
long maxFeat = layer->featureCount(); |
|
435 |
long featureCounter = 0; |
|
436 |
QMap<QString, QString>::const_iterator mfIt = mParameterMap.find( "MAXFEATURES" ); |
|
437 |
if ( mfIt != mParameterMap.end() ) |
|
438 |
{ |
|
439 |
QString mfString = mfIt.value(); |
|
440 |
bool mfOk; |
|
441 |
maxFeat = mfString.toLong(&mfOk, 10); |
|
442 |
if ( !mfOk ) { maxFeat = layer->featureCount(); } |
|
443 |
} |
|
444 | ||
445 |
//read PROPERTYNAME |
|
446 |
bool withGeom = true; |
|
447 |
QgsAttributeList attrIndexes = provider->attributeIndexes(); |
|
448 |
QMap<QString, QString>::const_iterator pnIt = mParameterMap.find( "PROPERTYNAME" ); |
|
449 |
if ( pnIt != mParameterMap.end() ) |
|
450 |
{ |
|
451 |
QStringList attrList = pnIt.value().split( "," ); |
|
452 |
if ( attrList.size() > 0 ) |
|
453 |
{ |
|
454 |
withGeom = false; |
|
455 |
QStringList::const_iterator alstIt; |
|
456 |
QList<int> idxList; |
|
457 |
QMap<QString, int> fieldMap = provider->fieldNameMap(); |
|
458 |
QMap<QString, int>::const_iterator fieldIt; |
|
459 |
QString fieldName; |
|
460 |
for ( alstIt = attrList.begin(); alstIt != attrList.end(); ++alstIt ) |
|
461 |
{ |
|
462 |
fieldName = *alstIt; |
|
463 |
fieldIt = fieldMap.find( fieldName ); |
|
464 |
if ( fieldIt != fieldMap.end() ) |
|
465 |
{ |
|
466 |
idxList.append( fieldIt.value() ); |
|
467 |
} |
|
468 |
else if ( fieldName == "geometry" ) |
|
469 |
{ |
|
470 |
withGeom = true; |
|
471 |
} |
|
472 |
} |
|
473 |
if ( idxList.size() > 0 || withGeom) |
|
474 |
{ |
|
475 |
attrIndexes = idxList; |
|
476 |
} |
|
477 |
else |
|
478 |
{ |
|
479 |
withGeom = true; |
|
480 |
} |
|
481 |
} |
|
482 |
} |
|
483 | ||
484 |
QList<QgsFeature> featureList; |
|
485 |
if ( fidOk ) |
|
486 |
{ |
|
487 |
provider->featureAtId( fid.toInt(), feature, withGeom, attrIndexes ); |
|
488 |
featureList.append(feature); |
|
489 |
} |
|
490 |
else if ( filterOk ) |
|
491 |
{ |
|
492 |
provider->select( attrIndexes, searchRect, withGeom, true ); |
|
493 |
try { |
|
494 |
QgsFilter* mFilter = QgsFilter::createFilterFromXml( filter.firstChild().toElement().firstChild().toElement(), layer ); |
|
495 |
while ( provider->nextFeature( feature ) && featureCounter < maxFeat ) |
|
496 |
{ |
|
497 |
if ( mFilter ) |
|
498 |
{ |
|
499 |
if ( mFilter->evaluate( feature ) ) |
|
500 |
{ |
|
501 |
featureList.append(feature); |
|
502 |
++featureCounter; |
|
503 |
} |
|
504 |
} |
|
505 |
else |
|
506 |
{ |
|
507 |
featureList.append(feature); |
|
508 |
++featureCounter; |
|
509 |
} |
|
510 |
} |
|
511 |
delete mFilter; |
|
512 |
} catch(QgsMapServiceException& e ) { |
|
513 |
while ( provider->nextFeature( feature ) && featureCounter < maxFeat ) |
|
514 |
{ |
|
515 |
featureList.append(feature); |
|
516 |
++featureCounter; |
|
517 |
} |
|
518 |
} |
|
519 |
} |
|
520 |
else |
|
521 |
{ |
|
522 |
if ( bboxOk ) |
|
523 |
searchRect.set( minx, miny, maxx, maxy ); |
|
524 |
provider->select( attrIndexes, searchRect, withGeom, true ); |
|
525 |
while ( provider->nextFeature( feature ) && featureCounter < maxFeat ) |
|
526 |
{ |
|
527 |
featureList.append(feature); |
|
528 |
++featureCounter; |
|
529 |
} |
|
530 |
} |
|
531 |
QList<QgsFeature>::const_iterator featureIt = featureList.constBegin(); |
|
532 | ||
533 |
QString fcString; |
|
534 |
if ( format == "GeoJSON" ) |
|
535 |
{ |
|
536 |
featureCounter = 0; |
|
537 | ||
538 |
fcString = "{\"type\": \"FeatureCollection\",\n"; |
|
539 |
fcString += " \"features\": [\n"; |
|
540 |
result = fcString.toUtf8(); |
|
541 |
request.startGetFeatureResponse(&result, format); |
|
542 |
fcString = ""; |
|
543 | ||
544 |
for ( ; featureIt != featureList.constEnd(); ++featureIt ) |
|
545 |
{ |
|
546 |
feature = *featureIt; |
|
547 |
if (featureCounter == 0) |
|
548 |
fcString += " {\"type\": \"Feature\",\n"; |
|
549 |
else |
|
550 |
fcString += " ,{\"type\": \"Feature\",\n"; |
|
551 | ||
552 |
fcString += " \"id\": "; |
|
553 |
fcString += QString::number( feature.id() ); |
|
554 |
fcString += ",\n"; |
|
555 | ||
556 |
QgsGeometry* geom = feature.geometry(); |
|
557 |
if ( geom && withGeom) |
|
558 |
{ |
|
559 |
fcString += " \"geometry\": "; |
|
560 |
fcString += geom->exportToGeoJSON(); |
|
561 |
fcString += ",\n"; |
|
562 |
} |
|
563 | ||
564 |
fcString += " \"properties\": {\n"; |
|
565 | ||
566 |
//read all attribute values from the feature |
|
567 |
featureAttributes = feature.attributeMap(); |
|
568 |
int attributeCounter = 0; |
|
569 |
for ( QgsAttributeMap::const_iterator it = featureAttributes.begin(); it != featureAttributes.end(); ++it ) |
|
570 |
{ |
|
571 | ||
572 |
QString attributeName = fields[it.key()].name(); |
|
573 |
//skip attribute if it has edit type 'hidden' |
|
574 |
if ( layerHiddenAttributes.contains( attributeName ) ) |
|
575 |
{ |
|
576 |
continue; |
|
577 |
} |
|
578 | ||
579 |
//check if the attribute name should be replaced with an alias |
|
580 |
QMap<int, QString>::const_iterator aliasIt = layerAliasInfo.find( it.key() ); |
|
581 |
if ( aliasIt != layerAliasInfo.constEnd() ) |
|
582 |
{ |
|
583 |
attributeName = aliasIt.value(); |
|
584 |
} |
|
585 | ||
586 |
if (attributeCounter == 0) |
|
587 |
fcString += " \""; |
|
588 |
else |
|
589 |
fcString += " ,\""; |
|
590 |
fcString += attributeName; |
|
591 |
fcString += "\": "; |
|
592 |
if (it->type() == 6 || it->type() == 2) |
|
593 |
{ |
|
594 |
fcString += it->toString(); |
|
595 |
} |
|
596 |
else |
|
597 |
{ |
|
598 |
fcString += "\""; |
|
599 |
fcString += it->toString().replace( QString( "\"" ), QString( "\\\"" ) ); |
|
600 |
fcString += "\""; |
|
601 |
} |
|
602 |
fcString += "\n"; |
|
603 |
++attributeCounter; |
|
604 |
} |
|
605 | ||
606 |
fcString += " }\n"; |
|
607 | ||
608 |
fcString += " }"; |
|
609 |
fcString += "\n"; |
|
610 | ||
611 |
result = fcString.toUtf8(); |
|
612 |
request.sendGetFeatureResponse( &result ); |
|
613 |
fcString = ""; |
|
614 | ||
615 |
++featureCounter; |
|
616 |
} |
|
617 |
fcString = ""; |
|
618 |
fcString += " ]\n"; |
|
619 |
fcString += "}"; |
|
620 | ||
621 |
result = fcString.toUtf8(); |
|
622 |
request.endGetFeatureResponse( &result ); |
|
623 |
fcString = ""; |
|
624 |
} |
|
625 |
else |
|
626 |
{ |
|
627 |
QDomDocument gmlDoc; |
|
628 |
//wfs:FeatureCollection |
|
629 |
fcString = "<wfs:FeatureCollection"; |
|
630 |
fcString += " xmlns=\"http://www.opengis.net/wfs\""; |
|
631 |
fcString += " xmlns:wfs=\"http://www.opengis.net/wfs\""; |
|
632 |
fcString += " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""; |
|
633 |
fcString += " xsi:schemaLocation=\"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd\""; |
|
634 |
fcString += " xmlns:ogc=\"http://www.opengis.net/ogc\""; |
|
635 |
fcString += " xmlns:gml=\"http://www.opengis.net/gml\""; |
|
636 |
fcString += " xmlns:ows=\"http://www.opengis.net/ows\""; |
|
637 |
fcString += " xmlns:xlink=\"http://www.w3.org/1999/xlink\""; |
|
638 |
fcString += " xmlns:qgs=\"http://www.qgis.org/gml\""; |
|
639 |
fcString += ">"; |
|
640 |
result = fcString.toUtf8(); |
|
641 |
request.startGetFeatureResponse(&result, format); |
|
642 |
fcString = ""; |
|
643 | ||
644 |
for ( ; featureIt != featureList.constEnd(); ++featureIt ) |
|
645 |
{ |
|
646 |
feature = *featureIt; |
|
647 |
//gml:FeatureMember |
|
648 |
QDomElement featureElement = gmlDoc.createElement( "gml:featureMember"/*wfs:FeatureMember*/ ); |
|
649 |
gmlDoc.appendChild(featureElement); |
|
650 | ||
651 |
//qgs:%TYPENAME% |
|
652 |
QDomElement typeNameElement = gmlDoc.createElement( "qgs:"+typeName.replace( QString(" "), QString("_") )/*qgs:%TYPENAME%*/ ); |
|
653 |
typeNameElement.setAttribute( "fid", QString::number( feature.id() ) ); |
|
654 |
featureElement.appendChild(typeNameElement); |
|
655 | ||
656 |
//read all attribute values from the feature |
|
657 |
featureAttributes = feature.attributeMap(); |
|
658 |
for ( QgsAttributeMap::const_iterator it = featureAttributes.begin(); it != featureAttributes.end(); ++it ) |
|
659 |
{ |
|
660 | ||
661 |
QString attributeName = fields[it.key()].name(); |
|
662 |
//skip attribute if it has edit type 'hidden' |
|
663 |
if ( layerHiddenAttributes.contains( attributeName ) ) |
|
664 |
{ |
|
665 |
continue; |
|
666 |
} |
|
667 | ||
668 |
//check if the attribute name should be replaced with an alias |
|
669 |
QMap<int, QString>::const_iterator aliasIt = layerAliasInfo.find( it.key() ); |
|
670 |
if ( aliasIt != layerAliasInfo.constEnd() ) |
|
671 |
{ |
|
672 |
attributeName = aliasIt.value(); |
|
673 |
} |
|
674 |
|
|
675 |
QDomElement fieldElem = gmlDoc.createElement( "qgs:"+attributeName ); |
|
676 |
QDomText fieldText = gmlDoc.createTextNode( it->toString() ); |
|
677 |
fieldElem.appendChild( fieldText ); |
|
678 |
typeNameElement.appendChild( fieldElem ); |
|
679 |
} |
|
680 | ||
681 |
if ( withGeom ) |
|
682 |
{ |
|
683 |
//add geometry column (as gml) |
|
684 |
QDomElement geomElem = gmlDoc.createElement( "qgs:geometry" ); |
|
685 |
QDomElement gmlElem = createGeometryElem( feature.geometry(), gmlDoc ); |
|
686 |
if ( !gmlElem.isNull() ) |
|
687 |
{ |
|
688 |
QgsCoordinateReferenceSystem layerCrs = layer->crs(); |
|
689 |
if ( layerCrs.isValid() ) |
|
690 |
{ |
|
691 |
gmlElem.setAttribute( "srsName", layerCrs.authid() ); |
|
692 |
} |
|
693 |
geomElem.appendChild( gmlElem ); |
|
694 |
typeNameElement.appendChild( geomElem ); |
|
695 |
} |
|
696 |
} |
|
697 |
|
|
698 |
result = gmlDoc.toByteArray(); |
|
699 |
request.sendGetFeatureResponse( &result ); |
|
700 |
gmlDoc.removeChild(featureElement); |
|
701 |
} |
|
702 | ||
703 |
fcString = "</wfs:FeatureCollection>"; |
|
704 |
result = fcString.toUtf8(); |
|
705 |
request.endGetFeatureResponse( &result ); |
|
706 |
fcString = ""; |
|
707 |
} |
|
708 | ||
709 |
} |
|
710 |
else |
|
711 |
{ |
|
712 |
return 2; |
|
713 |
} |
|
714 |
return 0; |
|
715 |
} |
|
716 | ||
717 |
QDomElement QgsWFSServer::createGeometryElem( QgsGeometry* geom, QDomDocument& doc ) /*const*/ |
|
718 |
{ |
|
719 |
if ( !geom ) |
|
720 |
{ |
|
721 |
return QDomElement(); |
|
722 |
} |
|
723 | ||
724 |
QDomElement geomElement; |
|
725 | ||
726 |
QString geomTypeName; |
|
727 |
QGis::WkbType wkbType = geom->wkbType(); |
|
728 |
switch ( wkbType ) |
|
729 |
{ |
|
730 |
case QGis::WKBPoint: |
|
731 |
case QGis::WKBPoint25D: |
|
732 |
geomElement = createPointElem( geom, doc ); |
|
733 |
break; |
|
734 |
case QGis::WKBMultiPoint: |
|
735 |
case QGis::WKBMultiPoint25D: |
|
736 |
geomElement = createMultiPointElem( geom, doc ); |
|
737 |
break; |
|
738 |
case QGis::WKBLineString: |
|
739 |
case QGis::WKBLineString25D: |
|
740 |
geomElement = createLineStringElem( geom, doc ); |
|
741 |
break; |
|
742 |
case QGis::WKBMultiLineString: |
|
743 |
case QGis::WKBMultiLineString25D: |
|
744 |
geomElement = createMultiLineStringElem( geom, doc ); |
|
745 |
break; |
|
746 |
case QGis::WKBPolygon: |
|
747 |
case QGis::WKBPolygon25D: |
|
748 |
geomElement = createPolygonElem( geom, doc ); |
|
749 |
break; |
|
750 |
case QGis::WKBMultiPolygon: |
|
751 |
case QGis::WKBMultiPolygon25D: |
|
752 |
geomElement = createMultiPolygonElem( geom, doc ); |
|
753 |
break; |
|
754 |
default: |
|
755 |
return QDomElement(); |
|
756 |
} |
|
757 |
return geomElement; |
|
758 |
} |
|
759 | ||
760 |
QDomElement QgsWFSServer::createLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const |
|
761 |
{ |
|
762 |
if ( !geom ) |
|
763 |
{ |
|
764 |
return QDomElement(); |
|
765 |
} |
|
766 | ||
767 |
QDomElement lineStringElem = doc.createElement( "gml:LineString" ); |
|
768 |
QDomElement coordElem = createCoordinateElem( geom->asPolyline(), doc ); |
|
769 |
lineStringElem.appendChild( coordElem ); |
|
770 |
return lineStringElem; |
|
771 |
} |
|
772 | ||
773 |
QDomElement QgsWFSServer::createMultiLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const |
|
774 |
{ |
|
775 |
if ( !geom ) |
|
776 |
{ |
|
777 |
return QDomElement(); |
|
778 |
} |
|
779 | ||
780 |
QDomElement multiLineStringElem = doc.createElement( "gml:MultiLineString" ); |
|
781 |
QgsMultiPolyline multiline = geom->asMultiPolyline(); |
|
782 | ||
783 |
QgsMultiPolyline::const_iterator multiLineIt = multiline.constBegin(); |
|
784 |
for ( ; multiLineIt != multiline.constEnd(); ++multiLineIt ) |
|
785 |
{ |
|
786 |
QgsGeometry* lineGeom = QgsGeometry::fromPolyline( *multiLineIt ); |
|
787 |
if ( lineGeom ) |
|
788 |
{ |
|
789 |
QDomElement lineStringMemberElem = doc.createElement( "gml:lineStringMember" ); |
|
790 |
QDomElement lineElem = createLineStringElem( lineGeom, doc ); |
|
791 |
lineStringMemberElem.appendChild( lineElem ); |
|
792 |
multiLineStringElem.appendChild( lineStringMemberElem ); |
|
793 |
} |
|
794 |
delete lineGeom; |
|
795 |
} |
|
796 | ||
797 |
return multiLineStringElem; |
|
798 |
} |