QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgswfsgetcapabilities.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgswfsgecapabilities.cpp
3  -------------------------
4  begin : December 20 , 2016
5  copyright : (C) 2007 by Marco Hugentobler (original code)
6  (C) 2012 by RenĂ©-Luc D'Hont (original code)
7  (C) 2014 by Alessandro Pasotti (original code)
8  (C) 2017 by David Marteau
9  email : marco dot hugentobler at karto dot baug dot ethz dot ch
10  a dot pasotti at itopen dot it
11  david dot marteau at 3liz dot com
12  ***************************************************************************/
13 
14 /***************************************************************************
15  * *
16  * This program is free software; you can redistribute it and/or modify *
17  * it under the terms of the GNU General Public License as published by *
18  * the Free Software Foundation; either version 2 of the License, or *
19  * (at your option) any later version. *
20  * *
21  ***************************************************************************/
22 #include "qgswfsutils.h"
23 #include "qgsserverprojectutils.h"
24 #include "qgswfsgetcapabilities.h"
25 
26 #include "qgsproject.h"
27 #include "qgsexception.h"
28 #include "qgsvectorlayer.h"
29 #include "qgsvectordataprovider.h"
30 #include "qgsmapserviceexception.h"
32 
33 #include <QStringList>
34 
35 namespace QgsWfs
36 {
37 
41  void writeGetCapabilities( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
42  const QgsServerRequest &request, QgsServerResponse &response )
43  {
44 #ifdef HAVE_SERVER_PYTHON_PLUGINS
45  QgsAccessControl *accessControl = serverIface->accessControls();
46 #endif
47  QDomDocument doc;
48  const QDomDocument *capabilitiesDocument = nullptr;
49 
50 #ifdef HAVE_SERVER_PYTHON_PLUGINS
51  QgsServerCacheManager *cacheManager = serverIface->cacheManager();
52  if ( cacheManager && cacheManager->getCachedDocument( &doc, project, request, accessControl ) )
53  {
54  capabilitiesDocument = &doc;
55  }
56  else //capabilities xml not in cache. Create a new one
57  {
58  doc = createGetCapabilitiesDocument( serverIface, project, version, request );
59 
60  if ( cacheManager )
61  {
62  cacheManager->setCachedDocument( &doc, project, request, accessControl );
63  }
64  capabilitiesDocument = &doc;
65  }
66 #else
67  doc = createGetCapabilitiesDocument( serverIface, project, version, request );
68  capabilitiesDocument = &doc;
69 #endif
70  response.setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/xml; charset=utf-8" ) );
71  response.write( capabilitiesDocument->toByteArray() );
72  }
73 
74 
75  QDomDocument createGetCapabilitiesDocument( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
76  const QgsServerRequest &request )
77  {
78  Q_UNUSED( version );
79 
80  QDomDocument doc;
81 
82  //wfs:WFS_Capabilities element
83  QDomElement wfsCapabilitiesElement = doc.createElement( QStringLiteral( "WFS_Capabilities" )/*wms:WFS_Capabilities*/ );
84  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns" ), WFS_NAMESPACE );
85  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
86  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xsi:schemaLocation" ), WFS_NAMESPACE + " http://schemas.opengis.net/wfs/1.0.0/WFS-capabilities.xsd" );
87  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:ogc" ), OGC_NAMESPACE );
88  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE );
89  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:ows" ), QStringLiteral( "http://www.opengis.net/ows" ) );
90  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
91  wfsCapabilitiesElement.setAttribute( QStringLiteral( "version" ), implementationVersion() );
92  wfsCapabilitiesElement.setAttribute( QStringLiteral( "updateSequence" ), QStringLiteral( "0" ) );
93  doc.appendChild( wfsCapabilitiesElement );
94 
95  //ows:ServiceIdentification
96  wfsCapabilitiesElement.appendChild( getServiceIdentificationElement( doc, project ) );
97 
98  //ows:ServiceProvider
99  wfsCapabilitiesElement.appendChild( getServiceProviderElement( doc, project ) );
100 
101  //wfs:OperationsMetadata
102  wfsCapabilitiesElement.appendChild( getOperationsMetadataElement( doc, project, request ) );
103 
104  //wfs:FeatureTypeList
105  wfsCapabilitiesElement.appendChild( getFeatureTypeListElement( doc, serverIface, project ) );
106 
107  /*
108  * Adding ogc:Filter_Capabilities in wfsCapabilitiesElement
109  */
110  //ogc:Filter_Capabilities element
111  QDomElement filterCapabilitiesElement = doc.createElement( QStringLiteral( "ogc:Filter_Capabilities" )/*ogc:Filter_Capabilities*/ );
112  wfsCapabilitiesElement.appendChild( filterCapabilitiesElement );
113  QDomElement spatialCapabilitiesElement = doc.createElement( QStringLiteral( "ogc:Spatial_Capabilities" )/*ogc:Spatial_Capabilities*/ );
114  filterCapabilitiesElement.appendChild( spatialCapabilitiesElement );
115  //GeometryOperands
116  QStringList geometryOperands;
117  geometryOperands << QStringLiteral( "gml:Point" ) << QStringLiteral( "gml:LineString" ) << QStringLiteral( "gml:Polygon" )
118  << QStringLiteral( "gml:Envelope" );
119  QDomElement geometryOperandsElem = doc.createElement( QStringLiteral( "ogc:GeometryOperands" ) );
120  for ( const QString &geometryOperand : geometryOperands )
121  {
122  QDomElement geometryOperandElem = doc.createElement( QStringLiteral( "ogc:GeometryOperand" ) );
123  QDomText geometryOperandText = doc.createTextNode( geometryOperand );
124  geometryOperandElem.appendChild( geometryOperandText );
125  geometryOperandsElem.appendChild( geometryOperandElem );
126  }
127  spatialCapabilitiesElement.appendChild( geometryOperandsElem );
128  //SpatialOperators
129  QStringList spatialOperators;
130  spatialOperators << QStringLiteral( "Equals" ) << QStringLiteral( "Disjoint" ) << QStringLiteral( "Touches" )
131  << QStringLiteral( "Within" ) << QStringLiteral( "Overlaps" ) << QStringLiteral( "Crosses" )
132  << QStringLiteral( "Intersects" ) << QStringLiteral( "Contains" ) << QStringLiteral( "DWithin" )
133  << QStringLiteral( "Beyond" ) << QStringLiteral( "BBOX" );
134  QDomElement spatialOperatorsElem = doc.createElement( QStringLiteral( "ogc:SpatialOperators" ) );
135  for ( const QString &spatialOperator : spatialOperators )
136  {
137  QDomElement spatialOperatorElem = doc.createElement( QStringLiteral( "ogc:SpatialOperator" ) );
138  spatialOperatorElem.setAttribute( QStringLiteral( "name" ), spatialOperator );
139  spatialOperatorsElem.appendChild( spatialOperatorElem );
140  }
141  spatialCapabilitiesElement.appendChild( spatialOperatorsElem );
142  QDomElement scalarCapabilitiesElement = doc.createElement( QStringLiteral( "ogc:Scalar_Capabilities" )/*ogc:Scalar_Capabilities*/ );
143  filterCapabilitiesElement.appendChild( scalarCapabilitiesElement );
144  QDomElement logicalOperatorsElement = doc.createElement( QStringLiteral( "ogc:LogicalOperators" ) );
145  scalarCapabilitiesElement.appendChild( logicalOperatorsElement );
146  // ComparisonOperators
147  QStringList comparisonOperators;
148  comparisonOperators << QStringLiteral( "LessThan" ) << QStringLiteral( "GreaterThan" )
149  << QStringLiteral( "LessThanEqualTo" ) << QStringLiteral( "GreaterThanEqualTo" )
150  << QStringLiteral( "EqualTo" ) << QStringLiteral( "Like" ) << QStringLiteral( "Between" );
151  QDomElement comparisonOperatorsElem = doc.createElement( QStringLiteral( "ogc:ComparisonOperators" ) );
152  for ( const QString &comparisonOperator : comparisonOperators )
153  {
154  QDomElement comparisonOperatorElem = doc.createElement( QStringLiteral( "ogc:ComparisonOperator" ) );
155  QDomText comparisonOperatorText = doc.createTextNode( comparisonOperator );
156  comparisonOperatorElem.appendChild( comparisonOperatorText );
157  comparisonOperatorsElem.appendChild( comparisonOperatorElem );
158  }
159  scalarCapabilitiesElement.appendChild( comparisonOperatorsElem );
160 
161  QDomElement idCapabilitiesElement = doc.createElement( QStringLiteral( "ogc:Id_Capabilities" ) );
162  QDomElement fidElem = doc.createElement( QStringLiteral( "ogc:FID" ) );
163  idCapabilitiesElement.appendChild( fidElem );
164  filterCapabilitiesElement.appendChild( idCapabilitiesElement );
165 
166  return doc;
167 
168  }
169 
170  QDomElement getServiceIdentificationElement( QDomDocument &doc, const QgsProject *project )
171  {
172  //Service element
173  QDomElement serviceElem = doc.createElement( QStringLiteral( "ows:ServiceIdentification" ) );
174 
175  QString title = QgsServerProjectUtils::owsServiceTitle( *project );
176  if ( !title.isEmpty() )
177  {
178  QDomElement titleElem = doc.createElement( QStringLiteral( "ows:Title" ) );
179  QDomText titleText = doc.createTextNode( title );
180  titleElem.appendChild( titleText );
181  serviceElem.appendChild( titleElem );
182  }
183 
184  QString abstract = QgsServerProjectUtils::owsServiceAbstract( *project );
185  if ( !abstract.isEmpty() )
186  {
187  QDomElement abstractElem = doc.createElement( QStringLiteral( "ows:Abstract" ) );
188  QDomText abstractText = doc.createCDATASection( abstract );
189  abstractElem.appendChild( abstractText );
190  serviceElem.appendChild( abstractElem );
191  }
192 
193  QStringList keywords = QgsServerProjectUtils::owsServiceKeywords( *project );
194  if ( !keywords.isEmpty() && !keywords.join( QStringLiteral( ", " ) ).isEmpty() )
195  {
196  QDomElement keywordsElem = doc.createElement( QStringLiteral( "ows:Keywords" ) );
197  for ( const QString &keyword : keywords )
198  {
199  if ( !keyword.isEmpty() )
200  {
201  QDomElement keywordElem = doc.createElement( QStringLiteral( "ows:Keyword" ) );
202  QDomText keywordText = doc.createTextNode( keyword );
203  keywordElem.appendChild( keywordText );
204  keywordsElem.appendChild( keywordElem );
205  }
206  }
207  serviceElem.appendChild( keywordsElem );
208  }
209 
210  //Service type
211  QDomElement serviceTypeElem = doc.createElement( QStringLiteral( "ows:ServiceType" ) );
212  QDomText serviceTypeText = doc.createTextNode( "WFS" );
213  serviceTypeElem.appendChild( serviceTypeText );
214  serviceElem.appendChild( serviceTypeElem );
215 
216  //Service type version
217  QDomElement serviceTypeVersionElem = doc.createElement( QStringLiteral( "ows:ServiceTypeVersion" ) );
218  QDomText serviceTypeVersionText = doc.createTextNode( "1.1.0" );
219  serviceTypeVersionElem.appendChild( serviceTypeVersionText );
220  serviceElem.appendChild( serviceTypeVersionElem );
221 
222  QDomElement feesElem = doc.createElement( QStringLiteral( "ows:Fees" ) );
223  QDomText feesText = doc.createTextNode( "None" );
224  const QString fees = QgsServerProjectUtils::owsServiceFees( *project );
225  if ( !fees.isEmpty() )
226  {
227  feesText = doc.createTextNode( fees );
228  }
229  feesElem.appendChild( feesText );
230  serviceElem.appendChild( feesElem );
231 
232  QDomElement accessConstraintsElem = doc.createElement( QStringLiteral( "ows:AccessConstraints" ) );
233  const QString accessConstraints = QgsServerProjectUtils::owsServiceAccessConstraints( *project );
234  QDomText accessConstraintsText = doc.createTextNode( "None" );
235  if ( !accessConstraints.isEmpty() )
236  {
237  accessConstraintsText = doc.createTextNode( accessConstraints );
238  }
239  accessConstraintsElem.appendChild( accessConstraintsText );
240  serviceElem.appendChild( accessConstraintsElem );
241 
242  return serviceElem;
243 
244  }
245 
246  QDomElement getServiceProviderElement( QDomDocument &doc, const QgsProject *project )
247  {
248  //Service element
249  QDomElement serviceElem = doc.createElement( QStringLiteral( "ows:ServiceProvider" ) );
250 
251  //ProviderName
252  const QString contactOrganization = QgsServerProjectUtils::owsServiceContactOrganization( *project );
253  if ( !contactOrganization.isEmpty() )
254  {
255  QDomElement providerNameElem = doc.createElement( QStringLiteral( "ows:ProviderName" ) );
256  QDomText providerNameText = doc.createTextNode( contactOrganization );
257  providerNameElem.appendChild( providerNameText );
258  serviceElem.appendChild( providerNameElem );
259  }
260 
261  const QString contactPerson = QgsServerProjectUtils::owsServiceContactPerson( *project );
262  const QString contactPosition = QgsServerProjectUtils::owsServiceContactPosition( *project );
263  if ( !contactPerson.isEmpty() ||
264  !contactPosition.isEmpty() )
265  {
266  //Contact information
267  QDomElement serviceContactElem = doc.createElement( QStringLiteral( "ows:ServiceContact" ) );
268 
269  if ( !contactPerson.isEmpty() )
270  {
271  QDomElement individualNameElem = doc.createElement( QStringLiteral( "ows:IndividualName" ) );
272  QDomText individualNameText = doc.createTextNode( contactPerson );
273  individualNameElem.appendChild( individualNameText );
274  serviceContactElem.appendChild( individualNameElem );
275  }
276 
277  if ( !contactPosition.isEmpty() )
278  {
279  QDomElement positionNameElem = doc.createElement( QStringLiteral( "ows:PositionName" ) );
280  QDomText positionNameText = doc.createTextNode( contactPosition );
281  positionNameElem.appendChild( positionNameText );
282  serviceContactElem.appendChild( positionNameElem );
283  }
284 
285  const QString contactMail = QgsServerProjectUtils::owsServiceContactMail( *project );
286  const QString contactPhone = QgsServerProjectUtils::owsServiceContactPhone( *project );
287  const QString onlineResource = QgsServerProjectUtils::owsServiceOnlineResource( *project );
288  if ( !contactMail.isEmpty() ||
289  !contactPhone.isEmpty() ||
290  !onlineResource.isEmpty() )
291  {
292  //Contact information
293  QDomElement contactInfoElem = doc.createElement( QStringLiteral( "ows:ContactInfo" ) );
294 
295  if ( !contactPhone.isEmpty() )
296  {
297  QDomElement phoneElem = doc.createElement( QStringLiteral( "ows:Phone" ) );
298  QDomElement voiceElem = doc.createElement( QStringLiteral( "ows:Voice" ) );
299  QDomText voiceText = doc.createTextNode( contactPhone );
300  voiceElem.appendChild( voiceText );
301  phoneElem.appendChild( voiceElem );
302  contactInfoElem.appendChild( phoneElem );
303  }
304 
305  if ( !contactMail.isEmpty() )
306  {
307  QDomElement addressElem = doc.createElement( QStringLiteral( "ows:Address" ) );
308  QDomElement mailElem = doc.createElement( QStringLiteral( "ows:ElectronicMailAddress" ) );
309  QDomText mailText = doc.createTextNode( contactMail );
310  mailElem.appendChild( mailText );
311  addressElem.appendChild( mailElem );
312  contactInfoElem.appendChild( addressElem );
313  }
314 
315  if ( !onlineResource.isEmpty() )
316  {
317  QDomElement onlineResourceElem = doc.createElement( QStringLiteral( "ows:OnlineResource" ) );
318  onlineResourceElem.setAttribute( "xlink:href", onlineResource );
319  contactInfoElem.appendChild( onlineResourceElem );
320  }
321  }
322 
323  QDomElement roleElem = doc.createElement( QStringLiteral( "ows:Role" ) );
324  QDomText roleText = doc.createTextNode( "PointOfContact" );
325  roleElem.appendChild( roleText );
326  serviceContactElem.appendChild( roleElem );
327 
328  serviceElem.appendChild( serviceContactElem );
329  }
330 
331  return serviceElem;
332 
333  }
334 
335  QDomElement getParameterElement( QDomDocument &doc, const QString &name, const QStringList &values )
336  {
337  QDomElement parameterElement = doc.createElement( QStringLiteral( "ows:Parameter" ) );
338  parameterElement.setAttribute( QStringLiteral( "name" ), name );
339 
340  for ( const QString &v : values )
341  {
342  QDomElement valueElement = doc.createElement( QStringLiteral( "ows:Value" ) );
343  QDomText valueText = doc.createTextNode( v );
344  valueElement.appendChild( valueText );
345  parameterElement.appendChild( valueElement );
346  }
347 
348  return parameterElement;
349  }
350 
351  QDomElement getOperationsMetadataElement( QDomDocument &doc, const QgsProject *project, const QgsServerRequest &request )
352  {
353  QDomElement oprationsElement = doc.createElement( QStringLiteral( "ows:OperationsMetadata" ) );
354 
355  //Prepare url
356  QString hrefString = serviceUrl( request, project );
357 
358  QDomElement operationElement = doc.createElement( QStringLiteral( "ows:Operation" ) );
359  QDomElement dcpElement = doc.createElement( QStringLiteral( "ows:DCP" ) );
360  QDomElement httpElement = doc.createElement( QStringLiteral( "ows:HTTP" ) );
361  QDomElement getElement = doc.createElement( QStringLiteral( "ows:Get" ) );
362  getElement.setAttribute( QStringLiteral( "xlink:href" ), hrefString );
363  httpElement.appendChild( getElement );
364 
365  QDomElement postElement = doc.createElement( QStringLiteral( "ows:Post" ) );
366  postElement.setAttribute( QStringLiteral( "xlink:href" ), hrefString );
367  httpElement.appendChild( postElement );
368 
369  dcpElement.appendChild( httpElement );
370  operationElement.appendChild( dcpElement );
371 
372  // GetCapabilities
373  QDomElement getCapabilitiesElement = operationElement.cloneNode().toElement();
374  getCapabilitiesElement.setAttribute( QStringLiteral( "name" ), QStringLiteral( "GetCapabilities" ) );
375  // GetCapabilities service
376  QDomElement serviceParameterElement = getParameterElement( doc, QStringLiteral( "service" ),
377  QStringList() << QStringLiteral( "WFS" ) );
378  getCapabilitiesElement.appendChild( serviceParameterElement );
379  // GetCapabilities AcceptVersions
380  QDomElement acceptVersionsParameterElement = getParameterElement( doc, QStringLiteral( "AcceptVersions" ),
381  QStringList() << QStringLiteral( "1.1.0" ) << QStringLiteral( "1.0.0" ) );
382  getCapabilitiesElement.appendChild( acceptVersionsParameterElement );
383  // GetCapabilities AcceptFormats
384  QDomElement acceptFormatsParameterElement = getParameterElement( doc, QStringLiteral( "AcceptFormats" ),
385  QStringList() << QStringLiteral( "text/xml" ) );
386  getCapabilitiesElement.appendChild( acceptFormatsParameterElement );
387  // Add
388  oprationsElement.appendChild( getCapabilitiesElement );
389 
390  // DescribeFeatureType
391  QDomElement describeFeatureTypeElement = operationElement.cloneNode().toElement();
392  describeFeatureTypeElement.setAttribute( QStringLiteral( "name" ), QStringLiteral( "DescribeFeatureType" ) );
393  // DescribeFeatureType outputFormat
394  QDomElement dftOutputFormatParameterElement = getParameterElement( doc, QStringLiteral( "outputFormat" ),
395  QStringList() << QStringLiteral( "XMLSCHEMA" )
396  << QStringLiteral( "text/xml; subtype=gml/2.1.2" )
397  << QStringLiteral( "text/xml; subtype=gml/3.1.1" ) );
398  describeFeatureTypeElement.appendChild( dftOutputFormatParameterElement );
399  // Add
400  oprationsElement.appendChild( describeFeatureTypeElement );
401 
402  // GetFeature
403  QDomElement getFeatureElement = operationElement.cloneNode().toElement();
404  getFeatureElement.setAttribute( QStringLiteral( "name" ), QStringLiteral( "GetFeature" ) );
405  // GetFeature outputFormat
406  QDomElement gfOutputFormatParameterElement = getParameterElement( doc, QStringLiteral( "outputFormat" ),
407  QStringList() << QStringLiteral( "text/xml; subtype=gml/2.1.2" )
408  << QStringLiteral( "text/xml; subtype=gml/3.1.1" )
409  << QStringLiteral( "application/vnd.geo+json" ) );
410  getFeatureElement.appendChild( gfOutputFormatParameterElement );
411  // GetFeature resultType
412  QDomElement resultTypeParameterElement = getParameterElement( doc, QStringLiteral( "resultType" ),
413  QStringList() << QStringLiteral( "results" ) << QStringLiteral( "hits" ) );
414  getFeatureElement.appendChild( resultTypeParameterElement );
415  // Add
416  oprationsElement.appendChild( getFeatureElement );
417 
418  // Transaction
419  QDomElement transactionElement = operationElement.cloneNode().toElement();
420  transactionElement.setAttribute( QStringLiteral( "name" ), QStringLiteral( "Transaction" ) );
421  // GetFeature inputFormat
422  QDomElement inputFormatParameterElement = getParameterElement( doc, QStringLiteral( "inputFormat" ),
423  QStringList() << QStringLiteral( "text/xml; subtype=gml/2.1.2" )
424  << QStringLiteral( "text/xml; subtype=gml/3.1.1" )
425  << QStringLiteral( "application/vnd.geo+json" ) );
426  transactionElement.appendChild( inputFormatParameterElement );
427  // Add
428  oprationsElement.appendChild( transactionElement );
429 
430  return oprationsElement;
431 
432  }
433 
434  QDomElement getFeatureTypeListElement( QDomDocument &doc, QgsServerInterface *serverIface, const QgsProject *project )
435  {
436 #ifdef HAVE_SERVER_PYTHON_PLUGINS
437  QgsAccessControl *accessControl = serverIface->accessControls();
438 #else
439  ( void )serverIface;
440 #endif
441 
442  //wfs:FeatureTypeList element
443  QDomElement featureTypeListElement = doc.createElement( QStringLiteral( "FeatureTypeList" )/*wfs:FeatureTypeList*/ );
444  //wfs:Operations element
445  QDomElement operationsElement = doc.createElement( QStringLiteral( "Operations" )/*wfs:Operations*/ );
446  featureTypeListElement.appendChild( operationsElement );
447  //wfs:Query element
448  QDomElement operationElement = doc.createElement( QStringLiteral( "Operation" ) );
449  QDomText queryText = doc.createTextNode( "Query" );
450  operationElement.appendChild( queryText );
451  operationsElement.appendChild( operationElement );
452 
453  const QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project );
454  const QStringList wfstUpdateLayersId = QgsServerProjectUtils::wfstUpdateLayerIds( *project );
455  const QStringList wfstInsertLayersId = QgsServerProjectUtils::wfstInsertLayerIds( *project );
456  const QStringList wfstDeleteLayersId = QgsServerProjectUtils::wfstDeleteLayerIds( *project );
457  for ( const QString &wfsLayerId : wfsLayerIds )
458  {
459  QgsMapLayer *layer = project->mapLayer( wfsLayerId );
460  if ( !layer )
461  {
462  continue;
463  }
464  if ( layer->type() != QgsMapLayer::LayerType::VectorLayer )
465  {
466  continue;
467  }
468  if ( accessControl && !accessControl->layerReadPermission( layer ) )
469  {
470  continue;
471  }
472 
473  QDomElement layerElem = doc.createElement( QStringLiteral( "FeatureType" ) );
474 
475  //create Name
476  QDomElement nameElem = doc.createElement( QStringLiteral( "Name" ) );
477  QDomText nameText = doc.createTextNode( layerTypeName( layer ) );
478  nameElem.appendChild( nameText );
479  layerElem.appendChild( nameElem );
480 
481  //create Title
482  QDomElement titleElem = doc.createElement( QStringLiteral( "Title" ) );
483  QString title = layer->title();
484  if ( title.isEmpty() )
485  {
486  title = layer->name();
487  }
488  QDomText titleText = doc.createTextNode( title );
489  titleElem.appendChild( titleText );
490  layerElem.appendChild( titleElem );
491 
492  //create Abstract
493  QString abstract = layer->abstract();
494  if ( !abstract.isEmpty() )
495  {
496  QDomElement abstractElem = doc.createElement( QStringLiteral( "Abstract" ) );
497  QDomText abstractText = doc.createTextNode( abstract );
498  abstractElem.appendChild( abstractText );
499  layerElem.appendChild( abstractElem );
500  }
501 
502  //create keywords
503  QString keywords = layer->keywordList();
504  if ( !keywords.isEmpty() )
505  {
506  QDomElement keywordsElem = doc.createElement( QStringLiteral( "ows:Keywords" ) );
507  for ( const QString &keyword : keywords.split( ',' ) )
508  {
509  if ( !keyword.trimmed().isEmpty() )
510  {
511  QDomElement keywordElem = doc.createElement( QStringLiteral( "ows:Keyword" ) );
512  QDomText keywordText = doc.createTextNode( keyword.trimmed() );
513  keywordElem.appendChild( keywordText );
514  keywordsElem.appendChild( keywordElem );
515  }
516  }
517  layerElem.appendChild( keywordsElem );
518  }
519 
520  //create DefaultSRS element
521  const QString defaultSrs = layer->crs().authid();
522  QDomElement srsElem = doc.createElement( QStringLiteral( "DefaultSRS" ) );
523  QDomText srsText = doc.createTextNode( defaultSrs );
524  srsElem.appendChild( srsText );
525  layerElem.appendChild( srsElem );
526 
527  //create OtherSRS elements
528  const QStringList outputCrsList = QgsServerProjectUtils::wmsOutputCrsList( *project );
529  for ( const QString &crs : outputCrsList )
530  {
531  if ( crs == defaultSrs )
532  continue;
533  QDomElement otherSrsElem = doc.createElement( QStringLiteral( "OtherSRS" ) );
534  QDomText otherSrsText = doc.createTextNode( crs );
535  otherSrsElem.appendChild( otherSrsText );
536  layerElem.appendChild( otherSrsElem );
537  }
538 
539  //wfs:Operations element
540  QDomElement operationsElement = doc.createElement( QStringLiteral( "Operations" )/*wfs:Operations*/ );
541  //wfs:Query element
542  QDomElement operationElement = doc.createElement( QStringLiteral( "Operation" ) );
543  QDomText queryText = doc.createTextNode( QStringLiteral( "Query" ) );
544  operationElement.appendChild( queryText );
545  operationsElement.appendChild( operationElement );
546 
547  if ( wfstUpdateLayersId.contains( layer->id() ) ||
548  wfstInsertLayersId.contains( layer->id() ) ||
549  wfstDeleteLayersId.contains( layer->id() ) )
550  {
551  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
552  QgsVectorDataProvider *provider = vlayer->dataProvider();
553  if ( ( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) && wfstInsertLayersId.contains( layer->id() ) )
554  {
555  //wfs:Insert element
556  QDomElement operationElement = doc.createElement( QStringLiteral( "Operation" ) );
557  QDomText insertText = doc.createTextNode( QStringLiteral( "Insert" )/*wfs:Insert*/ );
558  operationElement.appendChild( insertText );
559  operationsElement.appendChild( operationElement );
560  }
561 
562  if ( ( provider->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) &&
563  ( provider->capabilities() & QgsVectorDataProvider::ChangeGeometries ) &&
564  wfstUpdateLayersId.contains( layer->id() ) )
565  {
566  //wfs:Update element
567  QDomElement operationElement = doc.createElement( QStringLiteral( "Operation" ) );
568  QDomText updateText = doc.createTextNode( QStringLiteral( "Update" )/*wfs:Update*/ );
569  operationElement.appendChild( updateText );
570  operationsElement.appendChild( operationElement );
571  }
572 
573  if ( ( provider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) && wfstDeleteLayersId.contains( layer->id() ) )
574  {
575  //wfs:Delete element
576  QDomElement operationElement = doc.createElement( QStringLiteral( "Operation" ) );
577  QDomText deleteText = doc.createTextNode( QStringLiteral( "Delete" )/*wfs:Delete*/ );
578  operationElement.appendChild( deleteText );
579  operationsElement.appendChild( operationElement );
580  }
581  }
582 
583  layerElem.appendChild( operationsElement );
584 
585  //create OutputFormats element
586  QDomElement outputFormatsElem = doc.createElement( QStringLiteral( "OutputFormats" ) );
587  QDomElement outputFormatElem = doc.createElement( QStringLiteral( "Format" ) );
588  QDomText outputFormatText = doc.createTextNode( QStringLiteral( "text/xml; subtype=gml/3.1.1" ) );
589  outputFormatElem.appendChild( outputFormatText );
590  outputFormatsElem.appendChild( outputFormatElem );
591  layerElem.appendChild( outputFormatsElem );
592 
593  //create WGS84BoundingBox
594  QgsRectangle layerExtent = layer->extent();
595  //transform the layers native CRS into WGS84
597  int wgs84precision = 6;
598  QgsRectangle wgs84BoundingRect;
599  if ( !layerExtent.isNull() )
600  {
601  QgsCoordinateTransform exGeoTransform( layer->crs(), wgs84, project );
602  try
603  {
604  wgs84BoundingRect = exGeoTransform.transformBoundingBox( layerExtent );
605  }
606  catch ( const QgsCsException & )
607  {
608  wgs84BoundingRect = QgsRectangle();
609  }
610  }
611 
612  //create WGS84BoundingBox element
613  QDomElement bBoxElement = doc.createElement( QStringLiteral( "ows:WGS84BoundingBox" ) );
614  bBoxElement.setAttribute( QStringLiteral( "dimensions" ), QStringLiteral( "2" ) );
615  QDomElement lCornerElement = doc.createElement( QStringLiteral( "ows:LowerCorner" ) );
616  QDomText lCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( wgs84BoundingRect.xMinimum(), wgs84precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( wgs84BoundingRect.yMinimum(), wgs84precision ), wgs84precision ) );
617  lCornerElement.appendChild( lCornerText );
618  bBoxElement.appendChild( lCornerElement );
619  QDomElement uCornerElement = doc.createElement( QStringLiteral( "ows:UpperCorner" ) );
620  QDomText uCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( wgs84BoundingRect.xMaximum(), wgs84precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( wgs84BoundingRect.yMaximum(), wgs84precision ), wgs84precision ) );
621  uCornerElement.appendChild( uCornerText );
622  bBoxElement.appendChild( uCornerElement );
623  layerElem.appendChild( bBoxElement );
624 
625  // layer metadata URL
626  QString metadataUrl = layer->metadataUrl();
627  if ( !metadataUrl.isEmpty() )
628  {
629  QDomElement metaUrlElem = doc.createElement( QStringLiteral( "MetadataURL" ) );
630  QString metadataUrlType = layer->metadataUrlType();
631  metaUrlElem.setAttribute( QStringLiteral( "type" ), metadataUrlType );
632  QString metadataUrlFormat = layer->metadataUrlFormat();
633  metaUrlElem.setAttribute( QStringLiteral( "format" ), metadataUrlFormat );
634  QDomText metaUrlText = doc.createTextNode( metadataUrl );
635  metaUrlElem.appendChild( metaUrlText );
636  layerElem.appendChild( metaUrlElem );
637  }
638 
639  featureTypeListElement.appendChild( layerElem );
640  }
641 
642  return featureTypeListElement;
643  }
644 
645 } // namespace QgsWfs
646 
647 
648 
virtual void setHeader(const QString &key, const QString &value)=0
Set Header entry Add Header entry to the response Note that it is usually an error to set Header afte...
SERVER_EXPORT QStringList wmsOutputCrsList(const QgsProject &project)
Returns the WMS output CRS list.
QDomElement getParameterElement(QDomDocument &doc, const QString &name, const QStringList &values)
Create a parameter element.
A rectangle specified with double values.
Definition: qgsrectangle.h:40
Base class for all map layer types.
Definition: qgsmaplayer.h:63
SERVER_EXPORT QStringList wfstUpdateLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published as WFS-T with update capabilities...
bool getCachedDocument(QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl) const
Returns cached document (or 0 if document not in cache) like capabilities.
QDomDocument createGetCapabilitiesDocument(QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request)
Create get capabilities document.
QgsMapLayer::LayerType type() const
Returns the type of the layer.
bool setCachedDocument(const QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl) const
Updates or inserts the document in cache like capabilities.
SERVER_EXPORT QString owsServiceContactPosition(const QgsProject &project)
Returns the owsService contact position defined in project.
SERVER_EXPORT QString owsServiceContactPerson(const QgsProject &project)
Returns the owsService contact person defined in project.
SERVER_EXPORT QStringList owsServiceKeywords(const QgsProject &project)
Returns the owsService keywords defined in project.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
QDomElement getFeatureTypeListElement(QDomDocument &doc, QgsServerInterface *serverIface, const QgsProject *project)
Create FeatureTypeList element for get capabilities document.
SERVER_EXPORT QString owsServiceAbstract(const QgsProject &project)
Returns the owsService abstract defined in project.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:435
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:272
const QgsCoordinateReferenceSystem & crs
virtual void write(const QString &data)
Write string This is a convenient method that will write directly to the underlying I/O device...
QString layerTypeName(const QgsMapLayer *layer)
Returns typename from vector layer.
Definition: qgswfsutils.cpp:72
QString serviceUrl(const QgsServerRequest &request, const QgsProject *project)
Service URL string.
Definition: qgswfsutils.cpp:38
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:176
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
virtual QgsRectangle extent() const
Returns the extent of the layer.
SERVER_EXPORT QStringList wfstDeleteLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published as WFS-T with delete capabilities...
WMS implementation.
Definition: qgswfs.cpp:35
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:238
SERVER_EXPORT double floorWithPrecision(double number, int places)
Returns a double less than number to the specified number of places.
QDomElement getServiceIdentificationElement(QDomDocument &doc, const QgsProject *project)
Create Service Identification element for get capabilities document.
const QString GML_NAMESPACE
Definition: qgswfsutils.h:72
const QString WFS_NAMESPACE
Definition: qgswfsutils.h:71
A helper class that centralizes caches accesses given by all the server cache filter plugins...
Allows modifications of geometries.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
Reads and writes project states.
Definition: qgsproject.h:89
const QString GEO_EPSG_CRS_AUTHID
Geographic coord sys from EPSG authority.
Definition: qgis.cpp:69
QDomElement getOperationsMetadataElement(QDomDocument &doc, const QgsProject *project, const QgsServerRequest &request)
Create OperationsMetadata element for get capabilities document.
QString implementationVersion()
Returns the highest version supported by this implementation.
Definition: qgswfsutils.cpp:33
QString abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request. ...
Definition: qgsmaplayer.h:288
SERVER_EXPORT QString owsServiceFees(const QgsProject &project)
Returns the owsService fees defined in project.
SERVER_EXPORT double ceilWithPrecision(double number, int places)
Returns a double greater than number to the specified number of places.
SERVER_EXPORT QString owsServiceAccessConstraints(const QgsProject &project)
Returns the owsService access constraints defined in project.
SERVER_EXPORT QString owsServiceOnlineResource(const QgsProject &project)
Returns the owsService online resource defined in project.
SERVER_EXPORT QString owsServiceContactOrganization(const QgsProject &project)
Returns the owsService contact organization defined in project.
const QString OGC_NAMESPACE
Definition: qgswfsutils.h:73
QString metadataUrl() const
Returns the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:400
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
QgsServerInterface Class defining interfaces exposed by QGIS Server and made available to plugins...
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
SERVER_EXPORT QStringList wfsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WFS.
This class represents a coordinate reference system (CRS).
QString metadataUrlType() const
Returns the metadata type of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:418
QString authid() const
Returns the authority identifier for the CRS.
Class for doing transforms between two map coordinate systems.
virtual QgsServerCacheManager * cacheManager() const =0
Gets the registered server cache filters.
A helper class that centralizes restrictions given by all the access control filter plugins...
SERVER_EXPORT QStringList wfstInsertLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published as WFS-T with insert capabilities...
void writeGetCapabilities(QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response)
Output WFS GetCapabilities response.
QString name
Definition: qgsmaplayer.h:67
QgsServerResponse Class defining response interface passed to services QgsService::executeRequest() m...
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
virtual QgsAccessControl * accessControls() const =0
Gets the registered access control filters.
SERVER_EXPORT QString owsServiceContactMail(const QgsProject &project)
Returns the owsService contact mail defined in project.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider.
QString keywordList() const
Returns the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:304
This is the base class for vector data providers.
QDomElement getServiceProviderElement(QDomDocument &doc, const QgsProject *project)
Create Service Provider element for get capabilities document.
Represents a vector layer which manages a vector based data sets.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166
Allows modification of attribute values.
QString metadataUrlFormat() const
Returns the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:436
SERVER_EXPORT QString owsServiceTitle(const QgsProject &project)
Returns the owsService title defined in project.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:70
SERVER_EXPORT QString owsServiceContactPhone(const QgsProject &project)
Returns the owsService contact phone defined in project.
bool layerReadPermission(const QgsMapLayer *layer) const
Returns the layer read right.