wfs-server-1_7.patch

For branch 1.7 : This patch adds a public method to get QgsGeometry in GeoJSON format. This pacth adds WFS 1.0.0 service capabilities to QGIS Server This pacth extends WFS 1.0.0 service capabilities with GeoJSON output format. - Michael Douchin, 2012-02-27 08:58 AM

Download (54.8 KB)

View differences:

src/core/qgsgeometry.cpp
4101 4101
  }
4102 4102
}
4103 4103

  
4104
QString QgsGeometry::exportToGeoJSON()
4105
{
4106
  QgsDebugMsg( "entered." );
4107

  
4108
  // TODO: implement with GEOS
4109
  if ( mDirtyWkb )
4110
  {
4111
    exportGeosToWkb();
4112
  }
4113

  
4114
  if ( !mGeometry )
4115
  {
4116
    QgsDebugMsg( "WKB geometry not available!" );
4117
    return QString::null;
4118
  }
4119

  
4120
  QGis::WkbType wkbType;
4121
  bool hasZValue = false;
4122
  double *x, *y;
4123

  
4124
  QString mWkt; // TODO: rename
4125

  
4126
  // Will this really work when mGeometry[0] == 0 ???? I (gavin) think not.
4127
  //wkbType = (mGeometry[0] == 1) ? mGeometry[1] : mGeometry[4];
4128
  memcpy( &wkbType, &( mGeometry[1] ), sizeof( int ) );
4129

  
4130
  switch ( wkbType )
4131
  {
4132
    case QGis::WKBPoint25D:
4133
    case QGis::WKBPoint:
4134
    {
4135
      mWkt += "{ \"type\": \"Point\", \"coordinates\": [";
4136
      x = ( double * )( mGeometry + 5 );
4137
      mWkt += QString::number( *x, 'f', 6 );
4138
      mWkt += ", ";
4139
      y = ( double * )( mGeometry + 5 + sizeof( double ) );
4140
      mWkt += QString::number( *y, 'f', 6 );
4141
      mWkt += "] }";
4142
      return mWkt;
4143
    }
4144

  
4145
    case QGis::WKBLineString25D:
4146
      hasZValue = true;
4147
    case QGis::WKBLineString:
4148
    {
4149
      QgsDebugMsg( "LINESTRING found" );
4150
      unsigned char *ptr;
4151
      int *nPoints;
4152
      int idx;
4153

  
4154
      mWkt += "{ \"type\": \"LineString\", \"coordinates\": [ ";
4155
      // get number of points in the line
4156
      ptr = mGeometry + 5;
4157
      nPoints = ( int * ) ptr;
4158
      ptr = mGeometry + 1 + 2 * sizeof( int );
4159
      for ( idx = 0; idx < *nPoints; ++idx )
4160
      {
4161
        if ( idx != 0 )
4162
        {
4163
          mWkt += ", ";
4164
        }
4165
        mWkt += "[";
4166
        x = ( double * ) ptr;
4167
        mWkt += QString::number( *x, 'f', 6 );
4168
        mWkt += ", ";
4169
        ptr += sizeof( double );
4170
        y = ( double * ) ptr;
4171
        mWkt += QString::number( *y, 'f', 6 );
4172
        ptr += sizeof( double );
4173
        if ( hasZValue )
4174
        {
4175
          ptr += sizeof( double );
4176
        }
4177
        mWkt += "]";
4178
      }
4179
      mWkt += " ] }";
4180
      return mWkt;
4181
    }
4182

  
4183
    case QGis::WKBPolygon25D:
4184
      hasZValue = true;
4185
    case QGis::WKBPolygon:
4186
    {
4187
      QgsDebugMsg( "POLYGON found" );
4188
      unsigned char *ptr;
4189
      int idx, jdx;
4190
      int *numRings, *nPoints;
4191

  
4192
      mWkt += "{ \"type\": \"Polygon\", \"coordinates\": [ ";
4193
      // get number of rings in the polygon
4194
      numRings = ( int * )( mGeometry + 1 + sizeof( int ) );
4195
      if ( !( *numRings ) )  // sanity check for zero rings in polygon
4196
      {
4197
        return QString();
4198
      }
4199
      int *ringStart; // index of first point for each ring
4200
      int *ringNumPoints; // number of points in each ring
4201
      ringStart = new int[*numRings];
4202
      ringNumPoints = new int[*numRings];
4203
      ptr = mGeometry + 1 + 2 * sizeof( int ); // set pointer to the first ring
4204
      for ( idx = 0; idx < *numRings; idx++ )
4205
      {
4206
        if ( idx != 0 )
4207
        {
4208
          mWkt += ", ";
4209
        }
4210
        mWkt += "[ ";
4211
        // get number of points in the ring
4212
        nPoints = ( int * ) ptr;
4213
        ringNumPoints[idx] = *nPoints;
4214
        ptr += 4;
4215

  
4216
        for ( jdx = 0; jdx < *nPoints; jdx++ )
4217
        {
4218
          if ( jdx != 0 )
4219
          {
4220
            mWkt += ", ";
4221
          }
4222
          mWkt += "[";
4223
          x = ( double * ) ptr;
4224
          mWkt += QString::number( *x, 'f', 6 );
4225
          mWkt += ", ";
4226
          ptr += sizeof( double );
4227
          y = ( double * ) ptr;
4228
          mWkt += QString::number( *y, 'f', 6 );
4229
          ptr += sizeof( double );
4230
          if ( hasZValue )
4231
          {
4232
            ptr += sizeof( double );
4233
          }
4234
          mWkt += "]";
4235
        }
4236
        mWkt += " ]";
4237
      }
4238
      mWkt += " ] }";
4239
      delete [] ringStart;
4240
      delete [] ringNumPoints;
4241
      return mWkt;
4242
    }
4243

  
4244
    case QGis::WKBMultiPoint25D:
4245
      hasZValue = true;
4246
    case QGis::WKBMultiPoint:
4247
    {
4248
      unsigned char *ptr;
4249
      int idx;
4250
      int *nPoints;
4251

  
4252
      mWkt += "{ \"type\": \"MultiPoint\", \"coordinates\": [ ";
4253
      nPoints = ( int* )( mGeometry + 5 );
4254
      ptr = mGeometry + 5 + sizeof( int );
4255
      for ( idx = 0; idx < *nPoints; ++idx )
4256
      {
4257
        ptr += ( 1 + sizeof( int ) );
4258
        if ( idx != 0 )
4259
        {
4260
          mWkt += ", ";
4261
        }
4262
        mWkt += "[";
4263
        x = ( double * )( ptr );
4264
        mWkt += QString::number( *x, 'f', 6 );
4265
        mWkt += ", ";
4266
        ptr += sizeof( double );
4267
        y = ( double * )( ptr );
4268
        mWkt += QString::number( *y, 'f', 6 );
4269
        ptr += sizeof( double );
4270
        if ( hasZValue )
4271
        {
4272
          ptr += sizeof( double );
4273
        }
4274
        mWkt += "]";
4275
      }
4276
      mWkt += " ] }";
4277
      return mWkt;
4278
    }
4279

  
4280
    case QGis::WKBMultiLineString25D:
4281
      hasZValue = true;
4282
    case QGis::WKBMultiLineString:
4283
    {
4284
      QgsDebugMsg( "MULTILINESTRING found" );
4285
      unsigned char *ptr;
4286
      int idx, jdx, numLineStrings;
4287
      int *nPoints;
4288

  
4289
      mWkt += "{ \"type\": \"MultiLineString\", \"coordinates\": [ ";
4290
      numLineStrings = ( int )( mGeometry[5] );
4291
      ptr = mGeometry + 9;
4292
      for ( jdx = 0; jdx < numLineStrings; jdx++ )
4293
      {
4294
        if ( jdx != 0 )
4295
        {
4296
          mWkt += ", ";
4297
        }
4298
        mWkt += "[ ";
4299
        ptr += 5; // skip type since we know its 2
4300
        nPoints = ( int * ) ptr;
4301
        ptr += sizeof( int );
4302
        for ( idx = 0; idx < *nPoints; idx++ )
4303
        {
4304
          if ( idx != 0 )
4305
          {
4306
            mWkt += ", ";
4307
          }
4308
          mWkt += "[";
4309
          x = ( double * ) ptr;
4310
          mWkt += QString::number( *x, 'f', 6 );
4311
          ptr += sizeof( double );
4312
          mWkt += ", ";
4313
          y = ( double * ) ptr;
4314
          mWkt += QString::number( *y, 'f', 6 );
4315
          ptr += sizeof( double );
4316
          if ( hasZValue )
4317
          {
4318
            ptr += sizeof( double );
4319
          }
4320
          mWkt += "]";
4321
        }
4322
        mWkt += " ]";
4323
      }
4324
      mWkt += " ] }";
4325
      return mWkt;
4326
    }
4327

  
4328
    case QGis::WKBMultiPolygon25D:
4329
      hasZValue = true;
4330
    case QGis::WKBMultiPolygon:
4331
    {
4332
      QgsDebugMsg( "MULTIPOLYGON found" );
4333
      unsigned char *ptr;
4334
      int idx, jdx, kdx;
4335
      int *numPolygons, *numRings, *nPoints;
4336

  
4337
      mWkt += "{ \"type\": \"MultiPolygon\", \"coordinates\": [ ";
4338
      ptr = mGeometry + 5;
4339
      numPolygons = ( int * ) ptr;
4340
      ptr = mGeometry + 9;
4341
      for ( kdx = 0; kdx < *numPolygons; kdx++ )
4342
      {
4343
        if ( kdx != 0 )
4344
        {
4345
          mWkt += ", ";
4346
        }
4347
        mWkt += "[ ";
4348
        ptr += 5;
4349
        numRings = ( int * ) ptr;
4350
        ptr += 4;
4351
        for ( idx = 0; idx < *numRings; idx++ )
4352
        {
4353
          if ( idx != 0 )
4354
          {
4355
            mWkt += ", ";
4356
          }
4357
          mWkt += "[ ";
4358
          nPoints = ( int * ) ptr;
4359
          ptr += 4;
4360
          for ( jdx = 0; jdx < *nPoints; jdx++ )
4361
          {
4362
            if ( jdx != 0 )
4363
            {
4364
              mWkt += ", ";
4365
            }
4366
            mWkt += "[";
4367
            x = ( double * ) ptr;
4368
            mWkt += QString::number( *x, 'f', 6 );
4369
            ptr += sizeof( double );
4370
            mWkt += ", ";
4371
            y = ( double * ) ptr;
4372
            mWkt += QString::number( *y, 'f', 6 );
4373
            ptr += sizeof( double );
4374
            if ( hasZValue )
4375
            {
4376
              ptr += sizeof( double );
4377
            }
4378
            mWkt += "]";
4379
          }
4380
          mWkt += " ]";
4381
        }
4382
        mWkt += " ]";
4383
      }
4384
      mWkt += " ] }";
4385
      return mWkt;
4386
    }
4387

  
4388
    default:
4389
      QgsDebugMsg( "error: mGeometry type not recognized" );
4390
      return QString::null;
4391
  }
4392
}
4393

  
4104 4394
bool QgsGeometry::exportWkbToGeos()
4105 4395
{
4106 4396
  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
27 27
  qgssldparser.cpp
28 28
  qgssldrenderer.cpp
29 29
  qgswmsserver.cpp
30
  qgswfsserver.cpp
30 31
  qgsmapserviceexception.cpp
31 32
  qgsmapserverlogger.cpp
32 33
  qgsmslayercache.cpp
src/mapserver/qgis_map_serv.cpp
28 28
#include "qgsmapserviceexception.h"
29 29
#include "qgsprojectparser.h"
30 30
#include "qgssldparser.h"
31
#include "qgswfsserver.h"
31 32
#include <QDomDocument>
32 33
#include <QImage>
33 34
#include <QSettings>
......
264 265
    }
265 266

  
266 267
    QgsWMSServer* theServer = 0;
268
    if ( serviceIt->second == "WFS" )
269
    {
270
      delete theServer;
271
      QgsWFSServer* theServer = 0;
272
      try
273
      {
274
        theServer = new QgsWFSServer( parameterMap );
275
      }
276
      catch ( QgsMapServiceException e ) //admin.sld may be invalid
277
      {
278
        theRequestHandler->sendServiceException( e );
279
        continue;
280
      }
281

  
282
      theServer->setAdminConfigParser( adminConfigParser );
283

  
284

  
285
      //request type
286
      std::map<QString, QString>::const_iterator requestIt = parameterMap.find( "REQUEST" );
287
      if ( requestIt == parameterMap.end() )
288
      {
289
        //do some error handling
290
        QgsMSDebugMsg( "unable to find 'REQUEST' parameter, exiting..." );
291
        theRequestHandler->sendServiceException( QgsMapServiceException( "OperationNotSupported", "Please check the value of the REQUEST parameter" ) );
292
        delete theRequestHandler;
293
        delete theServer;
294
        continue;
295
      }
296

  
297
      if ( requestIt->second == "GetCapabilities" )
298
      {
299
        QDomDocument capabilitiesDocument;
300
        try
301
        {
302
          capabilitiesDocument = theServer->getCapabilities();
303
        }
304
        catch ( QgsMapServiceException& ex )
305
        {
306
          theRequestHandler->sendServiceException( ex );
307
          delete theRequestHandler;
308
          delete theServer;
309
          continue;
310
        }
311
        QgsMSDebugMsg( "sending GetCapabilities response" );
312
        theRequestHandler->sendGetCapabilitiesResponse( capabilitiesDocument );
313
        delete theRequestHandler;
314
        delete theServer;
315
        continue;
316
      }
317
      else if ( requestIt->second == "DescribeFeatureType" )
318
      {
319
        QDomDocument describeDocument;
320
        try
321
        {
322
          describeDocument = theServer->describeFeatureType();
323
        }
324
        catch ( QgsMapServiceException& ex )
325
        {
326
          theRequestHandler->sendServiceException( ex );
327
          delete theRequestHandler;
328
          delete theServer;
329
          continue;
330
        }
331
        QgsMSDebugMsg( "sending GetCapabilities response" );
332
        theRequestHandler->sendGetCapabilitiesResponse( describeDocument );
333
        delete theRequestHandler;
334
        delete theServer;
335
        continue;
336
      }
337
      else if ( requestIt->second == "GetFeature" )
338
      {
339
        //output format for GetFeature
340
        QString outputFormat;
341
        std::map<QString, QString>::const_iterator p_it = parameterMap.find( "OUTPUTFORMAT" );
342
        if ( p_it != parameterMap.end() )
343
        {
344
          outputFormat = p_it->second;
345
        }
346

  
347
        QByteArray fba;
348
        try
349
        {
350
          if ( theServer->getFeature( fba, outputFormat ) != 0 )
351
          {
352
            delete theRequestHandler;
353
            delete theServer;
354
            continue;
355
          } else {
356
            theRequestHandler->sendGetFeatureResponse( &fba, outputFormat );
357
            delete theRequestHandler;
358
            delete theServer;
359
            continue;
360
          }
361
        }
362
        catch ( QgsMapServiceException& ex )
363
        {
364
          theRequestHandler->sendServiceException( ex );
365
          delete theRequestHandler;
366
          delete theServer;
367
          continue;
368
        }
369
      }
370

  
371
      return 0;
372
    } 
373
    else 
374
    {
267 375
    try
268 376
    {
269 377
      theServer = new QgsWMSServer( parameterMap, theMapRenderer );
......
273 381
      theRequestHandler->sendServiceException( e );
274 382
      continue;
275 383
    }
384
    }
276 385

  
277 386
    theServer->setAdminConfigParser( adminConfigParser );
278 387

  
src/mapserver/qgsconfigparser.h
40 40
    /**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.*/
41 41
    virtual void layersAndStylesCapabilities( QDomElement& parentElement, QDomDocument& doc ) const = 0;
42 42

  
43
    virtual void featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const = 0;
44

  
43 45
    /**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.
44 46
       If no layers/style are found, an empty list is returned*/
45 47
    virtual QList<QgsMapLayer*> mapLayerFromStyle( const QString& layerName, const QString& styleName, bool allowCaching = true ) const = 0;
src/mapserver/qgsgetrequesthandler.cpp
306 306
{
307 307
  sendHttpResponse( ba, formatToMimeType( mFormat ) );
308 308
}
309

  
310
void QgsGetRequestHandler::sendGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const
311
{
312
  if (infoFormat == "GeoJSON")
313
    sendHttpResponse( ba, "text/plain" );
314
  else
315
    sendHttpResponse( ba, "text/xml" );
316
}
src/mapserver/qgsgetrequesthandler.h
30 30
    void sendServiceException( const QgsMapServiceException& ex ) const;
31 31
    void sendGetStyleResponse( const QDomDocument& doc ) const;
32 32
    void sendGetPrintResponse( QByteArray* ba ) const;
33
    void sendGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const;
33 34
};
src/mapserver/qgsprojectparser.cpp
115 115
  parentElement.appendChild( layerParentElem );
116 116
}
117 117

  
118
void QgsProjectParser::featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const
119
{
120
  QList<QDomElement> layerElems = projectLayerElements();
121

  
122
  QStringList nonIdentifiableLayers = identifyDisabledLayers();
123

  
124
  if ( layerElems.size() < 1 )
125
  {
126
    return;
127
  }
128

  
129
  QMap<QString, QgsMapLayer *> layerMap;
130

  
131
  QList<QDomElement>::const_iterator layerIt = layerElems.constBegin();
132
  for ( ; layerIt != layerElems.constEnd(); ++layerIt )
133
  { 
134
    QDomElement elem = *layerIt;
135
    QString type = elem.attribute( "type" );
136
    if ( type == "vector" )
137
    {
138
      QgsMapLayer *layer = createLayerFromElement( *layerIt );
139
      if ( layer )
140
      {
141
        QgsMSDebugMsg( QString( "add layer %1 to map" ).arg( layer->id() ) );
142
        layerMap.insert( layer->id(), layer );
143

  
144
        QDomElement layerElem = doc.createElement( "FeatureType" );
145
        QDomElement nameElem = doc.createElement( "Name" );
146
        //We use the layer name even though it might not be unique.
147
        //Because the id sometimes contains user/pw information and the name is more descriptive
148
        QDomText nameText = doc.createTextNode( layer->name() );
149
        nameElem.appendChild( nameText );
150
        layerElem.appendChild( nameElem );
151

  
152
        QDomElement titleElem = doc.createElement( "Title" );
153
        QDomText titleText = doc.createTextNode( layer->name() );
154
        titleElem.appendChild( titleText );
155
        layerElem.appendChild( titleElem );
156

  
157
        //appendExGeographicBoundingBox( layerElem, doc, layer->extent(), layer->crs() );
158

  
159
        QDomElement srsElem = doc.createElement( "SRS" );
160
        QDomText srsText = doc.createTextNode( layer->crs().authid() );
161
        srsElem.appendChild( srsText );
162
        layerElem.appendChild( srsElem );
163

  
164
        QgsRectangle layerExtent = layer->extent();
165
        QDomElement bBoxElement = doc.createElement( "LatLongBoundingBox" );
166
        bBoxElement.setAttribute( "minx", QString::number( layerExtent.xMinimum() ) );
167
        bBoxElement.setAttribute( "miny", QString::number( layerExtent.yMinimum() ) );
168
        bBoxElement.setAttribute( "maxx", QString::number( layerExtent.xMaximum() ) );
169
        bBoxElement.setAttribute( "maxy", QString::number( layerExtent.yMaximum() ) );
170
        layerElem.appendChild( bBoxElement );
171

  
172
        parentElement.appendChild(layerElem);
173
      }
174
#if QGSMSDEBUG
175
      else
176
      {
177
        QString buf;
178
        QTextStream s( &buf );
179
        layerIt->save( s, 0 );
180
        QgsMSDebugMsg( QString( "layer %1 not found" ).arg( buf ) );
181
      }
182
#endif
183
    }
184
  }
185
  return;
186
}
187

  
118 188
void QgsProjectParser::addLayers( QDomDocument &doc,
119 189
                                  QDomElement &parentElem,
120 190
                                  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 void sendGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const = 0;
44 45
    QString format() const { return mFormat; }
45 46
  protected:
46 47
    /**This is set by the parseInput methods of the subclasses (parameter FORMAT, e.g. 'FORMAT=PNG')*/
src/mapserver/qgssldparser.h
57 57
    /**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.*/
58 58
    void layersAndStylesCapabilities( QDomElement& parentElement, QDomDocument& doc ) const;
59 59

  
60
    void featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const {};
61

  
60 62
    /**Returns number of layers in configuration*/
61 63
    int numberOfLayers() const;
62 64

  
src/mapserver/qgssoaprequesthandler.h
35 35
    void sendServiceException( const QgsMapServiceException& ex ) const;
36 36
    void sendGetStyleResponse( const QDomDocument& doc ) const;
37 37
    void sendGetPrintResponse( QByteArray* ba ) const;
38
    void sendGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) const {};
38 39
  private:
39 40
    /**Parses the xml of a getMap request and fills the parameters into the map. Returns 0 in case of success*/
40 41
    int parseGetMapElement( std::map<QString, QString>& parameterMap, const QDomElement& getMapElement ) const;
src/mapserver/qgswfsserver.cpp
1
#include "qgswfsserver.h"
2
#include "qgsconfigparser.h"
3
#include "qgsepsgcache.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 "qgsmapserverlogger.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 <QImage>
28
#include <QPainter>
29
#include <QStringList>
30
#include <QTextStream>
31
#include <QDir>
32

  
33
//for printing
34
#include "qgscomposition.h"
35
#include <QBuffer>
36
#include <QPrinter>
37
#include <QSvgGenerator>
38
#include <QUrl>
39
#include <QPaintEngine>
40

  
41
QgsWFSServer::QgsWFSServer( std::map<QString, QString> parameters )
42
    : mParameterMap( parameters )
43
    , mConfigParser( 0 )
44
{
45
}
46

  
47
QgsWFSServer::~QgsWFSServer()
48
{
49
}
50

  
51
QgsWFSServer::QgsWFSServer()
52
{
53
}
54

  
55
QDomDocument QgsWFSServer::getCapabilities()
56
{
57
  QgsMSDebugMsg( "Entering." );
58
  QDomDocument doc;
59
  //wfs:WFS_Capabilities element
60
  QDomElement wfsCapabilitiesElement = doc.createElement( "WFS_Capabilities"/*wms:WFS_Capabilities*/ );
61
  wfsCapabilitiesElement.setAttribute( "xmlns", "http://www.opengis.net/wfs" );
62
  wfsCapabilitiesElement.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
63
  wfsCapabilitiesElement.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" );
64
  wfsCapabilitiesElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
65
  wfsCapabilitiesElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" );
66
  wfsCapabilitiesElement.setAttribute( "xmlns:ows", "http://www.opengis.net/ows" );
67
  wfsCapabilitiesElement.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
68
  wfsCapabilitiesElement.setAttribute( "version", "1.0.0" );
69
  wfsCapabilitiesElement.setAttribute( "updateSequence", "0" );
70
  doc.appendChild( wfsCapabilitiesElement );
71

  
72
  if ( mConfigParser )
73
  {
74
    mConfigParser->serviceCapabilities( wfsCapabilitiesElement, doc );
75
  }
76

  
77
  //wfs:Capability element
78
  QDomElement capabilityElement = doc.createElement( "Capability"/*wfs:Capability*/ );
79
  wfsCapabilitiesElement.appendChild( capabilityElement );
80
  
81
  //wfs:Request element
82
  QDomElement requestElement = doc.createElement( "Request"/*wfs:Request*/ );
83
  capabilityElement.appendChild( requestElement );
84
  //wfs:GetCapabilities
85
  QDomElement getCapabilitiesElement = doc.createElement( "GetCapabilities"/*wfs:GetCapabilities*/ );
86
  requestElement.appendChild( getCapabilitiesElement );
87
  QDomElement capabilitiesFormatElement = doc.createElement( "Format" );/*wfs:Format*/
88
  getCapabilitiesElement.appendChild( capabilitiesFormatElement );
89
  QDomText capabilitiesFormatText = doc.createTextNode( "text/xml" );
90
  capabilitiesFormatElement.appendChild( capabilitiesFormatText );
91

  
92
  QDomElement dcpTypeElement = doc.createElement( "DCPType"/*wfs:DCPType*/ );
93
  getCapabilitiesElement.appendChild( dcpTypeElement );
94
  QDomElement httpElement = doc.createElement( "HTTP"/*wfs:HTTP*/ );
95
  dcpTypeElement.appendChild( httpElement );
96

  
97
  //Prepare url
98
  //Some client requests already have http://<SERVER_NAME> in the REQUEST_URI variable
99
  QString hrefString;
100
  QString requestUrl = getenv( "REQUEST_URI" );
101
  QUrl mapUrl( requestUrl );
102
  mapUrl.setHost( QString( getenv( "SERVER_NAME" ) ) );
103
  mapUrl.removeQueryItem( "REQUEST" );
104
  mapUrl.removeQueryItem( "VERSION" );
105
  mapUrl.removeQueryItem( "SERVICE" );
106
  hrefString = mapUrl.toString();
107

  
108
  //only Get supported for the moment
109
  QDomElement getElement = doc.createElement( "Get"/*wfs:Get*/ );
110
  httpElement.appendChild( getElement );
111
  QDomElement olResourceElement = doc.createElement( "OnlineResource"/*wfs:OnlineResource*/ );
112
  olResourceElement.setAttribute( "xlink:type", "simple" );
113
  requestUrl.truncate( requestUrl.indexOf( "?" ) + 1 );
114
  olResourceElement.setAttribute( "xlink:href", hrefString );
115
  getElement.appendChild( olResourceElement );
116

  
117
  //wfs:DescribeFeatureType
118
  QDomElement describeFeatureTypeElement = doc.createElement( "DescribeFeatureType"/*wfs:DescribeFeatureType*/ );
119
  requestElement.appendChild( describeFeatureTypeElement );
120
  QDomElement schemaDescriptionLanguageElement = doc.createElement( "SchemaDescriptionLanguage"/*wfs:SchemaDescriptionLanguage*/ );
121
  describeFeatureTypeElement.appendChild( schemaDescriptionLanguageElement );
122
  QDomElement xmlSchemaElement = doc.createElement( "XMLSCHEMA"/*wfs:XMLSCHEMA*/ );
123
  schemaDescriptionLanguageElement.appendChild( xmlSchemaElement );
124
  QDomElement describeFeatureTypeDhcTypeElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities'
125
  describeFeatureTypeElement.appendChild( describeFeatureTypeDhcTypeElement );
126

  
127
  //wfs:GetFeature
128
  QDomElement getFeatureElement = doc.createElement( "GetFeature"/*wfs:GetFeature*/ );
129
  requestElement.appendChild( getFeatureElement );
130
  QDomElement getFeatureFormatElement = doc.createElement( "ResultFormat" );/*wfs:ResultFormat*/
131
  getFeatureElement.appendChild( getFeatureFormatElement );
132
  QDomElement gmlFormatElement = doc.createElement( "GML2" );/*wfs:GML2*/
133
  getFeatureFormatElement.appendChild( gmlFormatElement );
134
  QDomElement geojsonFormatElement = doc.createElement( "GeoJSON" );/*wfs:GeoJSON*/
135
  getFeatureFormatElement.appendChild( geojsonFormatElement );
136
  QDomElement getFeatureDhcTypeElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities'
137
  getFeatureElement.appendChild( getFeatureDhcTypeElement );
138

  
139
  //wfs:FeatureTypeList element
140
  QDomElement featureTypeListElement = doc.createElement( "FeatureTypeList"/*wfs:FeatureTypeList*/ );
141
  capabilityElement.appendChild( featureTypeListElement );
142
  //wfs:Operations element
143
  QDomElement operationsElement = doc.createElement( "Operations"/*wfs:Operations*/ );
144
  featureTypeListElement.appendChild( operationsElement );
145
  //wfs:Query element
146
  QDomElement queryElement = doc.createElement( "Query"/*wfs:Query*/ );
147
  operationsElement.appendChild( queryElement );
148
  /*
149
   * Adding layer liste in featureTypeListElement
150
   */
151
  if ( mConfigParser )
152
  {
153
    mConfigParser->featureTypeList( featureTypeListElement, doc );
154
  }
155

  
156
  /*
157
   * Adding ogc:Filter_Capabilities in capabilityElement
158
   */
159
  //ogc:Filter_Capabilities element
160
  QDomElement filterCapabilitiesElement = doc.createElement( "ogc:Filter_Capabilities"/*ogc:Filter_Capabilities*/ );
161
  capabilityElement.appendChild( filterCapabilitiesElement );
162
  QDomElement spatialCapabilitiesElement = doc.createElement( "ogc:Spatial_Capabilities"/*ogc:Spatial_Capabilities*/ );
163
  filterCapabilitiesElement.appendChild( spatialCapabilitiesElement );
164
  QDomElement spatialOperatorsElement = doc.createElement( "ogc:Spatial_Operators"/*ogc:Spatial_Operators*/ );
165
  spatialCapabilitiesElement.appendChild( spatialOperatorsElement );
166
  QDomElement ogcBboxElement = doc.createElement( "ogc:BBOX"/*ogc:BBOX*/ );
167
  spatialOperatorsElement.appendChild( ogcBboxElement );
168
  QDomElement scalarCapabilitiesElement = doc.createElement( "ogc:Scalar_Capabilities"/*ogc:Scalar_Capabilities*/ );
169
  filterCapabilitiesElement.appendChild( scalarCapabilitiesElement );
170
  QDomElement comparisonOperatorsElement = doc.createElement( "ogc:Comparison_Operators"/*ogc:Comparison_Operators*/ );
171
  scalarCapabilitiesElement.appendChild( comparisonOperatorsElement );
172
  QDomElement simpleComparisonsElement = doc.createElement( "ogc:Simple_Comparisons"/*ogc:Simple_Comparisons*/ );
173
  comparisonOperatorsElement.appendChild( simpleComparisonsElement );
174
  return doc;
175
}
176

  
177
QDomDocument QgsWFSServer::describeFeatureType()
178
{
179
  QgsMSDebugMsg( "Entering." );
180
  QDomDocument doc;
181
  //xsd:schema
182
  QDomElement schemaElement = doc.createElement( "schema"/*xsd:schema*/ );
183
  schemaElement.setAttribute( "xmlns", "http://www.w3.org/2001/XMLSchema" );
184
  schemaElement.setAttribute( "xmlns:xsd", "http://www.w3.org/2001/XMLSchema" );
185
  schemaElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
186
  schemaElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" );
187
  schemaElement.setAttribute( "xmlns:qgs", "http://www.qgis.org/gml" );
188
  schemaElement.setAttribute( "targetNamespace", "http://www.qgis.org/gml" );
189
  doc.appendChild( schemaElement );
190

  
191
  //xsd:import
192
  QDomElement importElement = doc.createElement( "import"/*xsd:import*/ );
193
  importElement.setAttribute( "namespace", "http://www.opengis.net/gml" );
194
  importElement.setAttribute( "schemaLocation", "http://schemas.opengis.net/gml/2.1.2/feature.xsd" );
195
  schemaElement.appendChild( importElement );
196

  
197
  //read TYPENAME
198
  QString typeName;
199
  std::map<QString, QString>::const_iterator type_name_it = mParameterMap.find( "TYPENAME" );
200
  if ( type_name_it != mParameterMap.end() )
201
  {
202
    typeName = type_name_it->second;
203
  }
204
  else
205
  {
206
    return doc;
207
  }
208

  
209
  QStringList nonIdentifiableLayers = mConfigParser->identifyDisabledLayers();
210
  QMap< QString, QMap< int, QString > > aliasInfo = mConfigParser->layerAliasInfo();
211
  QMap< QString, QSet<QString> > hiddenAttributes = mConfigParser->hiddenAttributes();
212
  
213
  QList<QgsMapLayer*> layerList;
214
  QgsMapLayer* currentLayer = 0;
215

  
216
  layerList = mConfigParser->mapLayerFromStyle( typeName, "" );
217
  currentLayer = layerList.at( 0 );
218
  
219
  QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>( currentLayer );
220
  if ( layer )
221
  {
222
    //is there alias info for this vector layer?
223
    QMap< int, QString > layerAliasInfo;
224
    QMap< QString, QMap< int, QString > >::const_iterator aliasIt = aliasInfo.find( currentLayer->id() );
225
    if ( aliasIt != aliasInfo.constEnd() )
226
    {
227
      layerAliasInfo = aliasIt.value();
228
    }
229

  
230
    //hidden attributes for this layer
231
    QSet<QString> layerHiddenAttributes;
232
    QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find( currentLayer->id() );
233
    if ( hiddenIt != hiddenAttributes.constEnd() )
234
    {
235
      layerHiddenAttributes = hiddenIt.value();
236
    }
237
    
238
    //do a select with searchRect and go through all the features
239
    QgsVectorDataProvider* provider = layer->dataProvider();
240
    if ( !provider )
241
    {
242
      return doc;
243
    }
244

  
245
    typeName = typeName.replace( QString(" "), QString("_") );
246
    
247
    //xsd:element
248
    QDomElement elementElem = doc.createElement( "element"/*xsd:element*/ );
249
    elementElem.setAttribute( "name", typeName );
250
    elementElem.setAttribute( "type", "qgs:" + typeName + "Type" );
251
    elementElem.setAttribute( "substitutionGroup", "gml:_Feature" );
252
    schemaElement.appendChild( elementElem );
253

  
254
    //xsd:complexType
255
    QDomElement complexTypeElem = doc.createElement( "complexType"/*xsd:complexType*/ );
256
    complexTypeElem.setAttribute( "name", typeName + "Type" );
257
    schemaElement.appendChild( complexTypeElem );
258

  
259
    //xsd:complexType
260
    QDomElement complexContentElem = doc.createElement( "complexContent"/*xsd:complexContent*/ );
261
    complexTypeElem.appendChild( complexContentElem );
262

  
263
    //xsd:extension
264
    QDomElement extensionElem = doc.createElement( "extension"/*xsd:extension*/ );
265
    extensionElem.setAttribute( "base", "gml:AbstractFeatureType" );
266
    complexContentElem.appendChild( extensionElem );
267

  
268
    //xsd:sequence
269
    QDomElement sequenceElem = doc.createElement( "sequence"/*xsd:sequence*/ );
270
    extensionElem.appendChild( sequenceElem );
271

  
272
    //xsd:element
273
    QDomElement geomElem = doc.createElement( "element"/*xsd:element*/ );
274
    geomElem.setAttribute( "name", "geometry" );
275
    geomElem.setAttribute( "type", "gml:GeometryPropertyType" );
276
    geomElem.setAttribute( "minOccurs", "0" );
277
    geomElem.setAttribute( "maxOccurs", "1" );
278
    sequenceElem.appendChild( geomElem );
279

  
280
    const QgsFieldMap& fields = provider->fields();
281
    for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it )
282
    {
283

  
284
      QString attributeName = it.value().name();
285
      //skip attribute if it has edit type 'hidden'
286
      if ( layerHiddenAttributes.contains( attributeName ) )
287
      {
288
        continue;
289
      }
290

  
291
      //check if the attribute name should be replaced with an alias
292
      QMap<int, QString>::const_iterator aliasIt = layerAliasInfo.find( it.key() );
293
      if ( aliasIt != layerAliasInfo.constEnd() )
294
      {
295
        attributeName = aliasIt.value();
296
      }
297

  
298
      //xsd:element
299
      QDomElement geomElem = doc.createElement( "element"/*xsd:element*/ );
300
      geomElem.setAttribute( "name", attributeName );
301
      if ( it.value().type() == 2 )
302
        geomElem.setAttribute( "type", "integer" );
303
      else if ( it.value().type() == 6 )
304
        geomElem.setAttribute( "type", "double" );
305
      else
306
        geomElem.setAttribute( "type", "string" );
307

  
308
      sequenceElem.appendChild( geomElem );
309

  
310
    }
311
  }
312

  
313
  return doc;
314
}
315

  
316
int QgsWFSServer::getFeature( QByteArray& result, const QString& format )
317
{
318
  QgsMSDebugMsg( "Info format is:" + infoFormat );
319

  
320
  //read TYPENAME
321
  QString typeName;
322
  std::map<QString, QString>::const_iterator type_name_it = mParameterMap.find( "TYPENAME" );
323
  if ( type_name_it != mParameterMap.end() )
324
  {
325
    typeName = type_name_it->second;
326
  }
327
  else
328
  {
329
    return 1;
330
  }
331

  
332
  QStringList nonIdentifiableLayers = mConfigParser->identifyDisabledLayers();
333
  QMap< QString, QMap< int, QString > > aliasInfo = mConfigParser->layerAliasInfo();
334
  QMap< QString, QSet<QString> > hiddenAttributes = mConfigParser->hiddenAttributes();
335
  
336
  QList<QgsMapLayer*> layerList;
337
  QgsMapLayer* currentLayer = 0;
338

  
339
  layerList = mConfigParser->mapLayerFromStyle( typeName, "" );
340
  currentLayer = layerList.at( 0 );
341
  
342
  QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>( currentLayer );
343
  if ( layer )
344
  {
345
    //is there alias info for this vector layer?
346
    QMap< int, QString > layerAliasInfo;
347
    QMap< QString, QMap< int, QString > >::const_iterator aliasIt = aliasInfo.find( currentLayer->id() );
348
    if ( aliasIt != aliasInfo.constEnd() )
349
    {
350
      layerAliasInfo = aliasIt.value();
351
    }
352

  
353
    //hidden attributes for this layer
354
    QSet<QString> layerHiddenAttributes;
355
    QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find( currentLayer->id() );
356
    if ( hiddenIt != hiddenAttributes.constEnd() )
357
    {
358
      layerHiddenAttributes = hiddenIt.value();
359
    }
360
    
361
    //do a select with searchRect and go through all the features
362
    QgsVectorDataProvider* provider = layer->dataProvider();
363
    if ( !provider )
364
    {
365
      return 2;
366
    }
367

  
368
    QgsFeature feature;
369
    QgsAttributeMap featureAttributes;
370
    const QgsFieldMap& fields = provider->fields();
371

  
372
    //map extent
373
    QgsRectangle searchRect = layer->extent();
374

  
375
    //read FEATUREDID
376
    bool fidOk = false;
377
    QString fid;
378
    std::map<QString, QString>::const_iterator fidIt = mParameterMap.find( "FEATUREID" );
379
    if ( fidIt != mParameterMap.end() ) {
380
      fidOk = true;
381
      fid = fidIt->second;
382
    }
383

  
384
    //read FILTER
385
    bool filterOk = false;
386
    QDomDocument filter;
387
    std::map<QString, QString>::const_iterator filterIt = mParameterMap.find( "FILTER" );
388
    if ( filterIt != mParameterMap.end() ) {
389
      try {
390
      QString errorMsg;
391
      if ( !filter.setContent( filterIt->second, true, &errorMsg ) )
392
      {
393
        QgsMSDebugMsg( "soap request parse error" );
394
        QgsMSDebugMsg( "error message: " + errorMsg );
395
        QgsMSDebugMsg( "the xml string was:" );
396
        QgsMSDebugMsg( filterIt->second );
397
      }
398
      else 
399
      {
400
        filterOk = true;
401
      }
402
      } catch(QgsMapServiceException& e ) {
403
        filterOk = false;
404
      }
405
    }
406

  
407
    //read BBOX
408
    bool conversionSuccess;
409
    double minx, miny, maxx, maxy;
410
    bool bboxOk = false;
411
    std::map<QString, QString>::const_iterator bbIt = mParameterMap.find( "BBOX" );
412
    if ( bbIt == mParameterMap.end() )
413
    {
414
      minx = 0; miny = 0; maxx = 0; maxy = 0;
415
    }
416
    else
417
    {
418
      bboxOk = true;
419
      QString bbString = bbIt->second;
420
      minx = bbString.section( ",", 0, 0 ).toDouble( &conversionSuccess );
421
      if ( !conversionSuccess ) {bboxOk = false;}
422
      miny = bbString.section( ",", 1, 1 ).toDouble( &conversionSuccess );
423
      if ( !conversionSuccess ) {bboxOk = false;}
424
      maxx = bbString.section( ",", 2, 2 ).toDouble( &conversionSuccess );
425
      if ( !conversionSuccess ) {bboxOk = false;}
426
      maxy = bbString.section( ",", 3, 3 ).toDouble( &conversionSuccess );
427
      if ( !conversionSuccess ) {bboxOk = false;}
428
    }
429

  
430
    QList<QgsFeature> featureList;
431
    if ( fidOk )
432
    {
433
      provider->featureAtId(  fid.toInt(), feature, true, provider->attributeIndexes() );
434
      featureList.append(feature);
435
    }
436
    else if ( filterOk )
437
    {
438
      provider->select( provider->attributeIndexes(), searchRect, true, true );
439
      try {
440
        QgsFilter* mFilter = QgsFilter::createFilterFromXml( filter.firstChild().toElement().firstChild().toElement(), layer );
441
        while ( provider->nextFeature( feature ) )
442
        {
443
          if ( mFilter )
444
          {
445
            if ( mFilter->evaluate( feature ) )
446
            {
447
              featureList.append(feature);
448
            }
449
          }
450
          else
451
          {
452
            featureList.append(feature);
453
          }
454
        }
455
        delete mFilter;
456
      } catch(QgsMapServiceException& e ) {
457
        while ( provider->nextFeature( feature ) )
458
        {
459
          featureList.append(feature);
460
        }
461
      }
462
    }
463
    else
464
    {
465
      if ( bboxOk )
466
        searchRect.set( minx, miny, maxx, maxy );
467
      provider->select( provider->attributeIndexes(), searchRect, true, true );
468
      while ( provider->nextFeature( feature ) )
469
      {
470
        featureList.append(feature);
471
      }
472
    }
473
    QList<QgsFeature>::const_iterator featureIt = featureList.constBegin();
474

  
475
    if ( format == "GeoJSON" )
476
    {
477
      int featureCounter = 0;
478

  
479
      QString fcString;
480
      fcString.append("{\"type\": \"FeatureCollection\",\n");
481
      fcString.append(" \"features\": [\n");
482
      for ( ; featureIt != featureList.constEnd(); ++featureIt )
483
      {
484
        feature = *featureIt;
485
        if (featureCounter == 0)
486
          fcString.append("  {\"type\": \"Feature\",\n");
487
        else
488
          fcString.append(" ,{\"type\": \"Feature\",\n");
489

  
490
        fcString.append("   \"id\": ");
491
        fcString.append( QString::number( feature.id() ) );
492
        fcString.append(",\n");
493

  
494
        QgsGeometry* geom = feature.geometry();
495
        if ( geom )
496
        {
497
          fcString.append("  \"geometry\": ");
498
          fcString.append(geom->exportToGeoJSON());
499
          fcString.append(",\n");
500
        }
501

  
502
        fcString.append("   \"properties\": {\n");
503

  
504
        //read all attribute values from the feature
505
        featureAttributes = feature.attributeMap();
506
        int attributeCounter = 0;
507
        for ( QgsAttributeMap::const_iterator it = featureAttributes.begin(); it != featureAttributes.end(); ++it )
508
        {
509

  
510
          QString attributeName = fields[it.key()].name();
511
          //skip attribute if it has edit type 'hidden'
512
          if ( layerHiddenAttributes.contains( attributeName ) )
513
          {
514
            continue;
515
          }
516

  
517
          //check if the attribute name should be replaced with an alias
518
          QMap<int, QString>::const_iterator aliasIt = layerAliasInfo.find( it.key() );
519
          if ( aliasIt != layerAliasInfo.constEnd() )
520
          {
521
            attributeName = aliasIt.value();
522
          }
523

  
524
          if (attributeCounter == 0)
525
            fcString.append("    \"");
526
          else
527
            fcString.append("   ,\"");
528
          fcString.append(attributeName);
529
          fcString.append("\": ");
530
          if (it->type() == 6 || it->type() == 2) 
531
          {
532
            fcString.append( it->toString());
533
          }
534
          else
535
          {
536
            fcString.append("\"");
537
            fcString.append( it->toString().replace( QString( "\"" ), QString( "\\\"" ) ) );
538
            fcString.append("\"");
539
          }
540
          fcString.append("\n");
541
          ++attributeCounter;
542
        }
543

  
544
        fcString.append("   }\n");
545

  
546
        fcString.append("  }");
547
        fcString.append("\n");
548

  
549
        ++featureCounter;
550
      }
551
      fcString.append(" ]\n");
552
      fcString.append("}");
553

  
554
      result = fcString.toUtf8();
555
    }
556
    else
557
    {
558
      QDomDocument gmlDoc;
559
      //wfs:FeatureCollection
560
      QDomElement fcElement = gmlDoc.createElement( "wfs:FeatureCollection"/*wfs:FeatureCollection*/ );
561
      fcElement.setAttribute( "xmlns", "http://www.opengis.net/wfs" );
562
      fcElement.setAttribute( "xmlns:wfs", "http://www.opengis.net/wfs" );
563
      fcElement.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
564
      fcElement.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" );
565
      fcElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
566
      fcElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" );
567
      fcElement.setAttribute( "xmlns:ows", "http://www.opengis.net/ows" );
568
      fcElement.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
569
      fcElement.setAttribute( "xmlns:qgs", "http://www.qgis.org/gml" );
570
      gmlDoc.appendChild( fcElement );
571

  
572
      for ( ; featureIt != featureList.constEnd(); ++featureIt )
573
      {
574
        feature = *featureIt;
575
        //gml:FeatureMember
576
        QDomElement featureElement = gmlDoc.createElement( "gml:featureMember"/*wfs:FeatureMember*/ );
577
        fcElement.appendChild(featureElement);
578

  
579
        //qgs:%TYPENAME%
580
        QDomElement typeNameElement = gmlDoc.createElement( "qgs:"+typeName.replace( QString(" "), QString("_") )/*qgs:%TYPENAME%*/ );
581
        typeNameElement.setAttribute( "fid", QString::number( feature.id() ) );
582
        featureElement.appendChild(typeNameElement);
583

  
584
        //add geometry column (as gml)
585
        QDomElement geomElem = gmlDoc.createElement( "qgs:geometry" );
586
        QDomElement gmlElem = createGeometryElem( feature.geometry(), gmlDoc );
587
        if ( !gmlElem.isNull() )
588
        {
589
          QgsCoordinateReferenceSystem layerCrs = layer->crs();
590
          if ( layerCrs.isValid() )
591
          {
592
            gmlElem.setAttribute( "srsName", layerCrs.authid() );
593
          }
594
          geomElem.appendChild( gmlElem );
595
          typeNameElement.appendChild( geomElem );
596
        }
597

  
598
        //read all attribute values from the feature
599
        featureAttributes = feature.attributeMap();
600
        for ( QgsAttributeMap::const_iterator it = featureAttributes.begin(); it != featureAttributes.end(); ++it )
601
        {
602

  
603
          QString attributeName = fields[it.key()].name();
604
          //skip attribute if it has edit type 'hidden'
605
          if ( layerHiddenAttributes.contains( attributeName ) )
606
          {
607
            continue;
608
          }
609

  
610
          //check if the attribute name should be replaced with an alias
611
          QMap<int, QString>::const_iterator aliasIt = layerAliasInfo.find( it.key() );
612
          if ( aliasIt != layerAliasInfo.constEnd() )
613
          {
614
            attributeName = aliasIt.value();
615
          }
616
          
617
          QDomElement fieldElem = gmlDoc.createElement( "qgs:"+attributeName );
618
          QDomText fieldText = gmlDoc.createTextNode( it->toString() );
619
          fieldElem.appendChild( fieldText );
620
          typeNameElement.appendChild( fieldElem );
621
        }
622
      }
623

  
624
      result = gmlDoc.toByteArray();
625
    }
626

  
627
  }
628
  else
629
  {
630
    return 2;
631
  }
632
  return 0;
633
}
634

  
635
QDomElement QgsWFSServer::createGeometryElem( QgsGeometry* geom, QDomDocument& doc ) /*const*/
636
{
637
  if ( !geom )
638
  {
639
    return QDomElement();
640
  }
641

  
642

  
643
  QDomElement geomElement;
644
  QString geomTypeName;
645
  QGis::WkbType wkbType = geom->wkbType();
646
  switch ( wkbType )
647
  {
648
    case QGis::WKBPoint:
649
    case QGis::WKBPoint25D:
650
      geomElement = createPointElem( geom, doc );
651
      break;
652
    case QGis::WKBMultiPoint:
653
    case QGis::WKBMultiPoint25D:
654
      geomElement = createMultiPointElem( geom, doc );
655
      break;
656
    case QGis::WKBLineString:
657
    case QGis::WKBLineString25D:
658
      geomElement = createLineStringElem( geom, doc );
659
      break;
660
    case QGis::WKBMultiLineString:
661
    case QGis::WKBMultiLineString25D:
662
      geomElement = createMultiLineStringElem( geom, doc );
663
      break;
664
    case QGis::WKBPolygon:
665
    case QGis::WKBPolygon25D:
666
      geomElement = createPolygonElem( geom, doc );
667
      break;
668
    case QGis::WKBMultiPolygon:
669
    case QGis::WKBMultiPolygon25D:
670
      geomElement = createMultiPolygonElem( geom, doc );
671
      break;
672
    default:
673
      return QDomElement();
674
  }
675
  return geomElement;
676
}
677

  
678
QDomElement QgsWFSServer::createLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const
679
{
680
  if ( !geom )
681
  {
682
    return QDomElement();
683
  }
684

  
685
  QDomElement lineStringElem = doc.createElement( "gml:LineString" );
686
  QDomElement coordElem = createCoordinateElem( geom->asPolyline(), doc );
687
  lineStringElem.appendChild( coordElem );
688
  return lineStringElem;
689
}
690

  
691
QDomElement QgsWFSServer::createMultiLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const
692
{
693
  if ( !geom )
694
  {
695
    return QDomElement();
696
  }
697

  
698
  QDomElement multiLineStringElem = doc.createElement( "gml:MultiLineString" );
699
  QgsMultiPolyline multiline = geom->asMultiPolyline();
700

  
701
  QgsMultiPolyline::const_iterator multiLineIt = multiline.constBegin();
702
  for ( ; multiLineIt != multiline.constEnd(); ++multiLineIt )
703
  {
704
    QgsGeometry* lineGeom = QgsGeometry::fromPolyline( *multiLineIt );
705
    if ( lineGeom )
706
    {
707
      QDomElement lineStringMemberElem = doc.createElement( "gml:lineStringMember" );
708
      QDomElement lineElem = createLineStringElem( lineGeom, doc );
709
      lineStringMemberElem.appendChild( lineElem );
710
      multiLineStringElem.appendChild( lineStringMemberElem );
711
    }
712
    delete lineGeom;
713
  }
714

  
715
  return multiLineStringElem;
716
}
717

  
718
QDomElement QgsWFSServer::createPointElem( QgsGeometry* geom, QDomDocument& doc ) const
719
{
720
  if ( !geom )
721
  {
722
    return QDomElement();
723
  }
724

  
725
  QDomElement pointElem = doc.createElement( "gml:Point" );
726
  QgsPoint p = geom->asPoint();
727
  QVector<QgsPoint> v;
728
  v.append( p );
729
  QDomElement coordElem = createCoordinateElem( v, doc );
730
  pointElem.appendChild( coordElem );
731
  return pointElem;
732
}
733

  
734
QDomElement QgsWFSServer::createMultiPointElem( QgsGeometry* geom, QDomDocument& doc ) const
735
{
736
  if ( !geom )
737
  {
738
    return QDomElement();
739
  }
740

  
741
  QDomElement multiPointElem = doc.createElement( "gml:MultiPoint" );
742
  QgsMultiPoint multiPoint = geom->asMultiPoint();
743

  
744
  QgsMultiPoint::const_iterator multiPointIt = multiPoint.constBegin();
745
  for ( ; multiPointIt != multiPoint.constEnd(); ++multiPointIt )
746
  {
747
    QgsGeometry* pointGeom = QgsGeometry::fromPoint( *multiPointIt );
748
    if ( pointGeom )
749
    {
750
      QDomElement multiPointMemberElem = doc.createElement( "gml:pointMember" );
751
      QDomElement pointElem = createPointElem( pointGeom, doc );
752
      multiPointMemberElem.appendChild( pointElem );
753
      multiPointElem.appendChild( multiPointMemberElem );
754
    }
755
  }
756
  return multiPointElem;
757
}
758

  
759
QDomElement QgsWFSServer::createPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const
760
{
761
  if ( !geom )
762
  {
763
    return QDomElement();
764
  }
765

  
766
  QDomElement polygonElem = doc.createElement( "gml:Polygon" );
767
  QgsPolygon poly = geom->asPolygon();
768
  for ( int i = 0; i < poly.size(); ++i )
769
  {
770
    QString boundaryName;
771
    if ( i == 0 )
772
    {
773
      boundaryName = "outerBoundaryIs";
774
    }
775
    else
776
    {
777
      boundaryName = "innerBoundaryIs";
778
    }
779
    QDomElement boundaryElem = doc.createElementNS( "http://www.opengis.net/gml", boundaryName );
780
    QDomElement ringElem = doc.createElement( "gml:LinearRing" );
781
    QDomElement coordElem = createCoordinateElem( poly.at( i ), doc );
782
    ringElem.appendChild( coordElem );
783
    boundaryElem.appendChild( ringElem );
784
    polygonElem.appendChild( boundaryElem );
785
  }
786
  return polygonElem;
787
}
788

  
789
QDomElement QgsWFSServer::createMultiPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const
790
{
791
  if ( !geom )
792
  {
793
    return QDomElement();
794
  }
795
  QDomElement multiPolygonElem = doc.createElement( "gml:MultiPolygon" );
796
  QgsMultiPolygon multipoly = geom->asMultiPolygon();
797

  
798
  QgsMultiPolygon::const_iterator polyIt = multipoly.constBegin();
799
  for ( ; polyIt != multipoly.constEnd(); ++polyIt )
800
  {
801
    QgsGeometry* polygonGeom = QgsGeometry::fromPolygon( *polyIt );
802
    if ( polygonGeom )
803
    {
804
      QDomElement polygonMemberElem = doc.createElement( "gml:polygonMember" );
805
      QDomElement polygonElem = createPolygonElem( polygonGeom, doc );
806
      delete polygonGeom;
807
      polygonMemberElem.appendChild( polygonElem );
808
      multiPolygonElem.appendChild( polygonMemberElem );
809
    }
810
  }
811
  return multiPolygonElem;
812
}
813

  
814
QDomElement QgsWFSServer::createCoordinateElem( const QVector<QgsPoint> points, QDomDocument& doc ) const
815
{
816
  QDomElement coordElem = doc.createElement( "gml:coordinates" );
817
  coordElem.setAttribute( "cs", "," );
818
  coordElem.setAttribute( "ts", " " );
819

  
820
  //precision 4 for meters / feet, precision 8 for degrees
821
  int precision = 6;
822
  /*
823
  if ( mSourceCRS.mapUnits() == QGis::Meters
824
       || mSourceCRS.mapUnits() == QGis::Feet )
825
  {
826
    precision = 4;
827
  }
828
  */
829

  
830
  QString coordString;
831
  QVector<QgsPoint>::const_iterator pointIt = points.constBegin();
832
  for ( ; pointIt != points.constEnd(); ++pointIt )
833
  {
834
    if ( pointIt != points.constBegin() )
835
    {
836
      coordString += " ";
837
    }
838
    coordString += QString::number( pointIt->x(), 'f', precision );
... This diff was truncated because it exceeds the maximum size that can be displayed.