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