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