QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 ) );
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( "DWithin" )
130  << QStringLiteral( "Beyond" ) << 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  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  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  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  QString title = QgsServerProjectUtils::owsServiceTitle( *project );
173  if ( !title.isEmpty() )
174  {
175  QDomElement titleElem = doc.createElement( QStringLiteral( "ows:Title" ) );
176  QDomText titleText = doc.createTextNode( title );
177  titleElem.appendChild( titleText );
178  serviceElem.appendChild( titleElem );
179  }
180 
181  QString abstract = QgsServerProjectUtils::owsServiceAbstract( *project );
182  if ( !abstract.isEmpty() )
183  {
184  QDomElement abstractElem = doc.createElement( QStringLiteral( "ows:Abstract" ) );
185  QDomText abstractText = doc.createCDATASection( abstract );
186  abstractElem.appendChild( abstractText );
187  serviceElem.appendChild( abstractElem );
188  }
189 
190  QStringList keywords = QgsServerProjectUtils::owsServiceKeywords( *project );
191  if ( !keywords.isEmpty() && !keywords.join( QStringLiteral( ", " ) ).isEmpty() )
192  {
193  QDomElement keywordsElem = doc.createElement( QStringLiteral( "ows:Keywords" ) );
194  for ( const QString &keyword : keywords )
195  {
196  if ( !keyword.isEmpty() )
197  {
198  QDomElement keywordElem = doc.createElement( QStringLiteral( "ows:Keyword" ) );
199  QDomText keywordText = doc.createTextNode( keyword );
200  keywordElem.appendChild( keywordText );
201  keywordsElem.appendChild( keywordElem );
202  }
203  }
204  serviceElem.appendChild( keywordsElem );
205  }
206 
207  //Service type
208  QDomElement serviceTypeElem = doc.createElement( QStringLiteral( "ows:ServiceType" ) );
209  QDomText serviceTypeText = doc.createTextNode( "WFS" );
210  serviceTypeElem.appendChild( serviceTypeText );
211  serviceElem.appendChild( serviceTypeElem );
212 
213  //Service type version
214  QDomElement serviceTypeVersionElem = doc.createElement( QStringLiteral( "ows:ServiceTypeVersion" ) );
215  QDomText serviceTypeVersionText = doc.createTextNode( "1.1.0" );
216  serviceTypeVersionElem.appendChild( serviceTypeVersionText );
217  serviceElem.appendChild( serviceTypeVersionElem );
218 
219  QDomElement feesElem = doc.createElement( QStringLiteral( "ows:Fees" ) );
220  QDomText feesText = doc.createTextNode( "None" );
221  const QString fees = QgsServerProjectUtils::owsServiceFees( *project );
222  if ( !fees.isEmpty() )
223  {
224  feesText = doc.createTextNode( fees );
225  }
226  feesElem.appendChild( feesText );
227  serviceElem.appendChild( feesElem );
228 
229  QDomElement accessConstraintsElem = doc.createElement( QStringLiteral( "ows:AccessConstraints" ) );
230  const QString accessConstraints = QgsServerProjectUtils::owsServiceAccessConstraints( *project );
231  QDomText accessConstraintsText = doc.createTextNode( "None" );
232  if ( !accessConstraints.isEmpty() )
233  {
234  accessConstraintsText = doc.createTextNode( accessConstraints );
235  }
236  accessConstraintsElem.appendChild( accessConstraintsText );
237  serviceElem.appendChild( accessConstraintsElem );
238 
239  return serviceElem;
240 
241  }
242 
243  QDomElement getServiceProviderElement( QDomDocument &doc, const QgsProject *project )
244  {
245  //Service element
246  QDomElement serviceElem = doc.createElement( QStringLiteral( "ows:ServiceProvider" ) );
247 
248  //ProviderName
249  const QString contactOrganization = QgsServerProjectUtils::owsServiceContactOrganization( *project );
250  if ( !contactOrganization.isEmpty() )
251  {
252  QDomElement providerNameElem = doc.createElement( QStringLiteral( "ows:ProviderName" ) );
253  QDomText providerNameText = doc.createTextNode( contactOrganization );
254  providerNameElem.appendChild( providerNameText );
255  serviceElem.appendChild( providerNameElem );
256  }
257 
258  const QString contactPerson = QgsServerProjectUtils::owsServiceContactPerson( *project );
259  const QString contactPosition = QgsServerProjectUtils::owsServiceContactPosition( *project );
260  if ( !contactPerson.isEmpty() ||
261  !contactPosition.isEmpty() )
262  {
263  //Contact information
264  QDomElement serviceContactElem = doc.createElement( QStringLiteral( "ows:ServiceContact" ) );
265 
266  if ( !contactPerson.isEmpty() )
267  {
268  QDomElement individualNameElem = doc.createElement( QStringLiteral( "ows:IndividualName" ) );
269  QDomText individualNameText = doc.createTextNode( contactPerson );
270  individualNameElem.appendChild( individualNameText );
271  serviceContactElem.appendChild( individualNameElem );
272  }
273 
274  if ( !contactPosition.isEmpty() )
275  {
276  QDomElement positionNameElem = doc.createElement( QStringLiteral( "ows:PositionName" ) );
277  QDomText positionNameText = doc.createTextNode( contactPosition );
278  positionNameElem.appendChild( positionNameText );
279  serviceContactElem.appendChild( positionNameElem );
280  }
281 
282  const QString contactMail = QgsServerProjectUtils::owsServiceContactMail( *project );
283  const QString contactPhone = QgsServerProjectUtils::owsServiceContactPhone( *project );
284  const QString onlineResource = QgsServerProjectUtils::owsServiceOnlineResource( *project );
285  if ( !contactMail.isEmpty() ||
286  !contactPhone.isEmpty() ||
287  !onlineResource.isEmpty() )
288  {
289  //Contact information
290  QDomElement contactInfoElem = doc.createElement( QStringLiteral( "ows:ContactInfo" ) );
291 
292  if ( !contactPhone.isEmpty() )
293  {
294  QDomElement phoneElem = doc.createElement( QStringLiteral( "ows:Phone" ) );
295  QDomElement voiceElem = doc.createElement( QStringLiteral( "ows:Voice" ) );
296  QDomText voiceText = doc.createTextNode( contactPhone );
297  voiceElem.appendChild( voiceText );
298  phoneElem.appendChild( voiceElem );
299  contactInfoElem.appendChild( phoneElem );
300  }
301 
302  if ( !contactMail.isEmpty() )
303  {
304  QDomElement addressElem = doc.createElement( QStringLiteral( "ows:Address" ) );
305  QDomElement mailElem = doc.createElement( QStringLiteral( "ows:ElectronicMailAddress" ) );
306  QDomText mailText = doc.createTextNode( contactMail );
307  mailElem.appendChild( mailText );
308  addressElem.appendChild( mailElem );
309  contactInfoElem.appendChild( addressElem );
310  }
311 
312  if ( !onlineResource.isEmpty() )
313  {
314  QDomElement onlineResourceElem = doc.createElement( QStringLiteral( "ows:OnlineResource" ) );
315  onlineResourceElem.setAttribute( "xlink:href", onlineResource );
316  contactInfoElem.appendChild( onlineResourceElem );
317  }
318  }
319 
320  QDomElement roleElem = doc.createElement( QStringLiteral( "ows:Role" ) );
321  QDomText roleText = doc.createTextNode( "PointOfContact" );
322  roleElem.appendChild( roleText );
323  serviceContactElem.appendChild( roleElem );
324 
325  serviceElem.appendChild( serviceContactElem );
326  }
327 
328  return serviceElem;
329 
330  }
331 
332  QDomElement getParameterElement( QDomDocument &doc, const QString &name, const QStringList &values )
333  {
334  QDomElement parameterElement = doc.createElement( QStringLiteral( "ows:Parameter" ) );
335  parameterElement.setAttribute( QStringLiteral( "name" ), name );
336 
337  for ( const QString &v : values )
338  {
339  QDomElement valueElement = doc.createElement( QStringLiteral( "ows:Value" ) );
340  QDomText valueText = doc.createTextNode( v );
341  valueElement.appendChild( valueText );
342  parameterElement.appendChild( valueElement );
343  }
344 
345  return parameterElement;
346  }
347 
348  QDomElement getOperationsMetadataElement( QDomDocument &doc, const QgsProject *project, const QgsServerRequest &request )
349  {
350  QDomElement oprationsElement = doc.createElement( QStringLiteral( "ows:OperationsMetadata" ) );
351 
352  //Prepare url
353  QString hrefString = serviceUrl( request, project );
354 
355  QDomElement operationElement = doc.createElement( QStringLiteral( "ows:Operation" ) );
356  QDomElement dcpElement = doc.createElement( QStringLiteral( "ows:DCP" ) );
357  QDomElement httpElement = doc.createElement( QStringLiteral( "ows:HTTP" ) );
358  QDomElement getElement = doc.createElement( QStringLiteral( "ows:Get" ) );
359  getElement.setAttribute( QStringLiteral( "xlink:href" ), hrefString );
360  httpElement.appendChild( getElement );
361 
362  QDomElement postElement = doc.createElement( QStringLiteral( "ows:Post" ) );
363  postElement.setAttribute( QStringLiteral( "xlink:href" ), hrefString );
364  httpElement.appendChild( postElement );
365 
366  dcpElement.appendChild( httpElement );
367  operationElement.appendChild( dcpElement );
368 
369  // GetCapabilities
370  QDomElement getCapabilitiesElement = operationElement.cloneNode().toElement();
371  getCapabilitiesElement.setAttribute( QStringLiteral( "name" ), QStringLiteral( "GetCapabilities" ) );
372  // GetCapabilities service
373  QDomElement serviceParameterElement = getParameterElement( doc, QStringLiteral( "service" ),
374  QStringList() << QStringLiteral( "WFS" ) );
375  getCapabilitiesElement.appendChild( serviceParameterElement );
376  // GetCapabilities AcceptVersions
377  QDomElement acceptVersionsParameterElement = getParameterElement( doc, QStringLiteral( "AcceptVersions" ),
378  QStringList() << QStringLiteral( "1.1.0" ) << QStringLiteral( "1.0.0" ) );
379  getCapabilitiesElement.appendChild( acceptVersionsParameterElement );
380  // GetCapabilities AcceptFormats
381  QDomElement acceptFormatsParameterElement = getParameterElement( doc, QStringLiteral( "AcceptFormats" ),
382  QStringList() << QStringLiteral( "text/xml" ) );
383  getCapabilitiesElement.appendChild( acceptFormatsParameterElement );
384  // Add
385  oprationsElement.appendChild( getCapabilitiesElement );
386 
387  // DescribeFeatureType
388  QDomElement describeFeatureTypeElement = operationElement.cloneNode().toElement();
389  describeFeatureTypeElement.setAttribute( QStringLiteral( "name" ), QStringLiteral( "DescribeFeatureType" ) );
390  // DescribeFeatureType outputFormat
391  QDomElement dftOutputFormatParameterElement = getParameterElement( doc, QStringLiteral( "outputFormat" ),
392  QStringList() << QStringLiteral( "XMLSCHEMA" )
393  << QStringLiteral( "text/xml; subtype=gml/2.1.2" )
394  << QStringLiteral( "text/xml; subtype=gml/3.1.1" ) );
395  describeFeatureTypeElement.appendChild( dftOutputFormatParameterElement );
396  // Add
397  oprationsElement.appendChild( describeFeatureTypeElement );
398 
399  // GetFeature
400  QDomElement getFeatureElement = operationElement.cloneNode().toElement();
401  getFeatureElement.setAttribute( QStringLiteral( "name" ), QStringLiteral( "GetFeature" ) );
402  // GetFeature outputFormat
403  QDomElement gfOutputFormatParameterElement = getParameterElement( doc, QStringLiteral( "outputFormat" ),
404  QStringList() << QStringLiteral( "text/xml; subtype=gml/2.1.2" )
405  << QStringLiteral( "text/xml; subtype=gml/3.1.1" )
406  << QStringLiteral( "application/vnd.geo+json" ) );
407  getFeatureElement.appendChild( gfOutputFormatParameterElement );
408  // GetFeature resultType
409  QDomElement resultTypeParameterElement = getParameterElement( doc, QStringLiteral( "resultType" ),
410  QStringList() << QStringLiteral( "results" ) << QStringLiteral( "hits" ) );
411  getFeatureElement.appendChild( resultTypeParameterElement );
412  // Add
413  oprationsElement.appendChild( getFeatureElement );
414 
415  // Transaction
416  QDomElement transactionElement = operationElement.cloneNode().toElement();
417  transactionElement.setAttribute( QStringLiteral( "name" ), QStringLiteral( "Transaction" ) );
418  // GetFeature inputFormat
419  QDomElement inputFormatParameterElement = getParameterElement( doc, QStringLiteral( "inputFormat" ),
420  QStringList() << QStringLiteral( "text/xml; subtype=gml/2.1.2" )
421  << QStringLiteral( "text/xml; subtype=gml/3.1.1" )
422  << QStringLiteral( "application/vnd.geo+json" ) );
423  transactionElement.appendChild( inputFormatParameterElement );
424  // Add
425  oprationsElement.appendChild( transactionElement );
426 
427  return oprationsElement;
428 
429  }
430 
431  QDomElement getFeatureTypeListElement( QDomDocument &doc, QgsServerInterface *serverIface, const QgsProject *project )
432  {
433 #ifdef HAVE_SERVER_PYTHON_PLUGINS
434  QgsAccessControl *accessControl = serverIface->accessControls();
435 #else
436  ( void )serverIface;
437 #endif
438 
439  //wfs:FeatureTypeList element
440  QDomElement featureTypeListElement = doc.createElement( QStringLiteral( "FeatureTypeList" )/*wfs:FeatureTypeList*/ );
441  //wfs:Operations element
442  QDomElement operationsElement = doc.createElement( QStringLiteral( "Operations" )/*wfs:Operations*/ );
443  featureTypeListElement.appendChild( operationsElement );
444  //wfs:Query element
445  QDomElement operationElement = doc.createElement( QStringLiteral( "Operation" ) );
446  QDomText queryText = doc.createTextNode( "Query" );
447  operationElement.appendChild( queryText );
448  operationsElement.appendChild( operationElement );
449 
450  const QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project );
451  const QStringList wfstUpdateLayersId = QgsServerProjectUtils::wfstUpdateLayerIds( *project );
452  const QStringList wfstInsertLayersId = QgsServerProjectUtils::wfstInsertLayerIds( *project );
453  const QStringList wfstDeleteLayersId = QgsServerProjectUtils::wfstDeleteLayerIds( *project );
454  for ( const QString &wfsLayerId : wfsLayerIds )
455  {
456  QgsMapLayer *layer = project->mapLayer( wfsLayerId );
457  if ( !layer )
458  {
459  continue;
460  }
461  if ( layer->type() != QgsMapLayerType::VectorLayer )
462  {
463  continue;
464  }
465 #ifdef HAVE_SERVER_PYTHON_PLUGINS
466  if ( accessControl && !accessControl->layerReadPermission( layer ) )
467  {
468  continue;
469  }
470 #endif
471  QDomElement layerElem = doc.createElement( QStringLiteral( "FeatureType" ) );
472 
473  //create Name
474  QDomElement nameElem = doc.createElement( QStringLiteral( "Name" ) );
475  QDomText nameText = doc.createTextNode( layerTypeName( layer ) );
476  nameElem.appendChild( nameText );
477  layerElem.appendChild( nameElem );
478 
479  //create Title
480  QDomElement titleElem = doc.createElement( QStringLiteral( "Title" ) );
481  QString title = layer->title();
482  if ( title.isEmpty() )
483  {
484  title = layer->name();
485  }
486  QDomText titleText = doc.createTextNode( title );
487  titleElem.appendChild( titleText );
488  layerElem.appendChild( titleElem );
489 
490  //create Abstract
491  QString abstract = layer->abstract();
492  if ( !abstract.isEmpty() )
493  {
494  QDomElement abstractElem = doc.createElement( QStringLiteral( "Abstract" ) );
495  QDomText abstractText = doc.createTextNode( abstract );
496  abstractElem.appendChild( abstractText );
497  layerElem.appendChild( abstractElem );
498  }
499 
500  //create keywords
501  QString keywords = layer->keywordList();
502  if ( !keywords.isEmpty() )
503  {
504  QDomElement keywordsElem = doc.createElement( QStringLiteral( "ows:Keywords" ) );
505  for ( const QString &keyword : keywords.split( ',' ) )
506  {
507  if ( !keyword.trimmed().isEmpty() )
508  {
509  QDomElement keywordElem = doc.createElement( QStringLiteral( "ows:Keyword" ) );
510  QDomText keywordText = doc.createTextNode( keyword.trimmed() );
511  keywordElem.appendChild( keywordText );
512  keywordsElem.appendChild( keywordElem );
513  }
514  }
515  layerElem.appendChild( keywordsElem );
516  }
517 
518  //create DefaultSRS element
519  const QString defaultSrs = layer->crs().authid();
520  QDomElement srsElem = doc.createElement( QStringLiteral( "DefaultSRS" ) );
521  QDomText srsText = doc.createTextNode( defaultSrs );
522  srsElem.appendChild( srsText );
523  layerElem.appendChild( srsElem );
524 
525  //create OtherSRS elements
526  const QStringList outputCrsList = QgsServerProjectUtils::wmsOutputCrsList( *project );
527  for ( const QString &crs : outputCrsList )
528  {
529  if ( crs == defaultSrs )
530  continue;
531  QDomElement otherSrsElem = doc.createElement( QStringLiteral( "OtherSRS" ) );
532  QDomText otherSrsText = doc.createTextNode( crs );
533  otherSrsElem.appendChild( otherSrsText );
534  layerElem.appendChild( otherSrsElem );
535  }
536 
537  //wfs:Operations element
538  QDomElement operationsElement = doc.createElement( QStringLiteral( "Operations" )/*wfs:Operations*/ );
539  //wfs:Query element
540  QDomElement operationElement = doc.createElement( QStringLiteral( "Operation" ) );
541  QDomText queryText = doc.createTextNode( QStringLiteral( "Query" ) );
542  operationElement.appendChild( queryText );
543  operationsElement.appendChild( operationElement );
544 
545  if ( wfstUpdateLayersId.contains( layer->id() ) ||
546  wfstInsertLayersId.contains( layer->id() ) ||
547  wfstDeleteLayersId.contains( layer->id() ) )
548  {
549  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
550  QgsVectorDataProvider *provider = vlayer->dataProvider();
551  if ( ( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) && wfstInsertLayersId.contains( layer->id() ) )
552  {
553  //wfs:Insert element
554  QDomElement operationElement = doc.createElement( QStringLiteral( "Operation" ) );
555  QDomText insertText = doc.createTextNode( QStringLiteral( "Insert" )/*wfs:Insert*/ );
556  operationElement.appendChild( insertText );
557  operationsElement.appendChild( operationElement );
558  }
559 
560  if ( ( provider->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) &&
561  ( provider->capabilities() & QgsVectorDataProvider::ChangeGeometries ) &&
562  wfstUpdateLayersId.contains( layer->id() ) )
563  {
564  //wfs:Update element
565  QDomElement operationElement = doc.createElement( QStringLiteral( "Operation" ) );
566  QDomText updateText = doc.createTextNode( QStringLiteral( "Update" )/*wfs:Update*/ );
567  operationElement.appendChild( updateText );
568  operationsElement.appendChild( operationElement );
569  }
570 
571  if ( ( provider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) && wfstDeleteLayersId.contains( layer->id() ) )
572  {
573  //wfs:Delete element
574  QDomElement operationElement = doc.createElement( QStringLiteral( "Operation" ) );
575  QDomText deleteText = doc.createTextNode( QStringLiteral( "Delete" )/*wfs:Delete*/ );
576  operationElement.appendChild( deleteText );
577  operationsElement.appendChild( operationElement );
578  }
579  }
580 
581  layerElem.appendChild( operationsElement );
582 
583  //create OutputFormats element
584  QDomElement outputFormatsElem = doc.createElement( QStringLiteral( "OutputFormats" ) );
585  QDomElement outputFormatElem = doc.createElement( QStringLiteral( "Format" ) );
586  QDomText outputFormatText = doc.createTextNode( QStringLiteral( "text/xml; subtype=gml/3.1.1" ) );
587  outputFormatElem.appendChild( outputFormatText );
588  outputFormatsElem.appendChild( outputFormatElem );
589  layerElem.appendChild( outputFormatsElem );
590 
591  //create WGS84BoundingBox
592  QgsRectangle layerExtent = layer->extent();
593  //transform the layers native CRS into WGS84
595  QgsRectangle wgs84BoundingRect;
596  if ( !layerExtent.isNull() )
597  {
598  QgsCoordinateTransform exGeoTransform( layer->crs(), wgs84, project );
599  try
600  {
601  wgs84BoundingRect = exGeoTransform.transformBoundingBox( layerExtent );
602  }
603  catch ( const QgsCsException & )
604  {
605  wgs84BoundingRect = QgsRectangle();
606  }
607  }
608 
609  //create WGS84BoundingBox element
610  QDomElement bBoxElement = doc.createElement( QStringLiteral( "ows:WGS84BoundingBox" ) );
611  bBoxElement.setAttribute( QStringLiteral( "dimensions" ), QStringLiteral( "2" ) );
612  QDomElement lCornerElement = doc.createElement( QStringLiteral( "ows:LowerCorner" ) );
613  QDomText lCornerText = doc.createTextNode( QString::number( wgs84BoundingRect.xMinimum() ) + " " + QString::number( wgs84BoundingRect.yMinimum() ) );
614  lCornerElement.appendChild( lCornerText );
615  bBoxElement.appendChild( lCornerElement );
616  QDomElement uCornerElement = doc.createElement( QStringLiteral( "ows:UpperCorner" ) );
617  QDomText uCornerText = doc.createTextNode( QString::number( wgs84BoundingRect.xMaximum() ) + " " + QString::number( wgs84BoundingRect.yMaximum() ) );
618  uCornerElement.appendChild( uCornerText );
619  bBoxElement.appendChild( uCornerElement );
620  layerElem.appendChild( bBoxElement );
621 
622  // layer metadata URL
623  QString metadataUrl = layer->metadataUrl();
624  if ( !metadataUrl.isEmpty() )
625  {
626  QDomElement metaUrlElem = doc.createElement( QStringLiteral( "MetadataURL" ) );
627  QString metadataUrlType = layer->metadataUrlType();
628  metaUrlElem.setAttribute( QStringLiteral( "type" ), metadataUrlType );
629  QString metadataUrlFormat = layer->metadataUrlFormat();
630  metaUrlElem.setAttribute( QStringLiteral( "format" ), metadataUrlFormat );
631  QDomText metaUrlText = doc.createTextNode( metadataUrl );
632  metaUrlElem.appendChild( metaUrlText );
633  layerElem.appendChild( metaUrlElem );
634  }
635 
636  featureTypeListElement.appendChild( layerElem );
637  }
638 
639  return featureTypeListElement;
640  }
641 
642 } // namespace QgsWfs
643 
644 
645 
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:41
Base class for all map layer types.
Definition: qgsmaplayer.h:79
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...
QDomDocument createGetCapabilitiesDocument(QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request)
Create get capabilities document.
QgsMapLayerType type() const
Returns the type of the layer.
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.
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.
QString abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request. ...
Definition: qgsmaplayer.h:295
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:71
virtual QgsRectangle extent() const
Returns the extent of the layer.
QString metadataUrlFormat() const
Returns the metadata format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:443
QString serviceUrl(const QgsServerRequest &request, const QgsProject *project)
Service URL string.
Definition: qgswfsutils.cpp:37
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
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 keywordList() const
Returns the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:311
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.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc.
Definition: qgsproject.h:89
const QString GEO_EPSG_CRS_AUTHID
Geographic coord sys from EPSG authority.
Definition: qgis.cpp:70
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:32
SERVER_EXPORT QString owsServiceFees(const QgsProject &project)
Returns the owsService fees defined in project.
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.
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.
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:279
SERVER_EXPORT QString owsServiceContactOrganization(const QgsProject &project)
Returns the owsService contact organization defined in project.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
const QString OGC_NAMESPACE
Definition: qgswfsutils.h:73
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
bool layerReadPermission(const QgsMapLayer *layer) const
Returns the layer read right.
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.
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).
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:436
bool setCachedDocument(const QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl) const
Updates or inserts the document in cache like capabilities.
Class for doing transforms between two map coordinate systems.
virtual QgsServerCacheManager * cacheManager() const =0
Gets the registered server cache filters.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
A helper class that centralizes restrictions given by all the access control filter plugins...
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
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 metadataUrl() const
Returns the metadata URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:407
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QString name
Definition: qgsmaplayer.h:83
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, it may be nullptr.
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.
Allows modification of attribute values.
QString authid() const
Returns the authority identifier for the CRS.
SERVER_EXPORT QString owsServiceTitle(const QgsProject &project)
Returns the owsService title defined in project.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:86
QString metadataUrlType() const
Returns the metadata type of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:425
SERVER_EXPORT QString owsServiceContactPhone(const QgsProject &project)
Returns the owsService contact phone defined in project.