QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 #endif
66  response.setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/xml; charset=utf-8" ) );
67  response.write( capabilitiesDocument->toByteArray() );
68  }
69 
70 
71  QDomDocument createGetCapabilitiesDocument( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
72  const QgsServerRequest &request )
73  {
74  Q_UNUSED( version )
75 
76  QDomDocument doc;
77 
78  //wfs:WFS_Capabilities element
79  QDomElement wfsCapabilitiesElement = doc.createElement( QStringLiteral( "WFS_Capabilities" )/*wms:WFS_Capabilities*/ );
80  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns" ), WFS_NAMESPACE );
81  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
82  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xsi:schemaLocation" ), WFS_NAMESPACE + " http://schemas.opengis.net/wfs/1.0.0/WFS-capabilities.xsd" );
83  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:ogc" ), OGC_NAMESPACE );
84  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE );
85  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:ows" ), QStringLiteral( "http://www.opengis.net/ows" ) );
86  wfsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
87  wfsCapabilitiesElement.setAttribute( QStringLiteral( "version" ), implementationVersion() );
88  wfsCapabilitiesElement.setAttribute( QStringLiteral( "updateSequence" ), QStringLiteral( "0" ) );
89  doc.appendChild( wfsCapabilitiesElement );
90 
91  //ows:ServiceIdentification
92  wfsCapabilitiesElement.appendChild( getServiceIdentificationElement( doc, project ) );
93 
94  //ows:ServiceProvider
95  wfsCapabilitiesElement.appendChild( getServiceProviderElement( doc, project ) );
96 
97  //wfs:OperationsMetadata
98  wfsCapabilitiesElement.appendChild( getOperationsMetadataElement( doc, project, request ) );
99 
100  //wfs:FeatureTypeList
101  wfsCapabilitiesElement.appendChild( getFeatureTypeListElement( doc, serverIface, project ) );
102 
103  /*
104  * Adding ogc:Filter_Capabilities in wfsCapabilitiesElement
105  */
106  //ogc:Filter_Capabilities element
107  QDomElement filterCapabilitiesElement = doc.createElement( QStringLiteral( "ogc:Filter_Capabilities" )/*ogc:Filter_Capabilities*/ );
108  wfsCapabilitiesElement.appendChild( filterCapabilitiesElement );
109  QDomElement spatialCapabilitiesElement = doc.createElement( QStringLiteral( "ogc:Spatial_Capabilities" )/*ogc:Spatial_Capabilities*/ );
110  filterCapabilitiesElement.appendChild( spatialCapabilitiesElement );
111  //GeometryOperands
112  QStringList geometryOperands;
113  geometryOperands << QStringLiteral( "gml:Point" ) << QStringLiteral( "gml:LineString" ) << QStringLiteral( "gml:Polygon" )
114  << QStringLiteral( "gml:Envelope" );
115  QDomElement geometryOperandsElem = doc.createElement( QStringLiteral( "ogc:GeometryOperands" ) );
116  for ( const QString &geometryOperand : geometryOperands )
117  {
118  QDomElement geometryOperandElem = doc.createElement( QStringLiteral( "ogc:GeometryOperand" ) );
119  QDomText geometryOperandText = doc.createTextNode( geometryOperand );
120  geometryOperandElem.appendChild( geometryOperandText );
121  geometryOperandsElem.appendChild( geometryOperandElem );
122  }
123  spatialCapabilitiesElement.appendChild( geometryOperandsElem );
124  //SpatialOperators
125  QStringList spatialOperators;
126  spatialOperators << QStringLiteral( "Equals" ) << QStringLiteral( "Disjoint" ) << QStringLiteral( "Touches" )
127  << QStringLiteral( "Within" ) << QStringLiteral( "Overlaps" ) << QStringLiteral( "Crosses" )
128  << QStringLiteral( "Intersects" ) << QStringLiteral( "Contains" ) << QStringLiteral( "DWithin" )
129  << QStringLiteral( "Beyond" ) << 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( QStringLiteral( ", " ) ).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 )
348  {
349  QDomElement oprationsElement = doc.createElement( QStringLiteral( "ows:OperationsMetadata" ) );
350 
351  //Prepare url
352  QString hrefString = serviceUrl( request, project );
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 
559  if ( ( provider->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) &&
560  ( provider->capabilities() & QgsVectorDataProvider::ChangeGeometries ) &&
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 OutputFormats element
583  QDomElement outputFormatsElem = doc.createElement( QStringLiteral( "OutputFormats" ) );
584  QDomElement outputFormatElem = doc.createElement( QStringLiteral( "Format" ) );
585  QDomText outputFormatText = doc.createTextNode( QStringLiteral( "text/xml; subtype=gml/3.1.1" ) );
586  outputFormatElem.appendChild( outputFormatText );
587  outputFormatsElem.appendChild( outputFormatElem );
588  layerElem.appendChild( outputFormatsElem );
589 
590  //create WGS84BoundingBox
591  QgsRectangle layerExtent = layer->extent();
592  //transform the layers native CRS into WGS84
594  QgsRectangle wgs84BoundingRect;
595  if ( !layerExtent.isNull() )
596  {
597  QgsCoordinateTransform exGeoTransform( layer->crs(), wgs84, project );
598  try
599  {
600  wgs84BoundingRect = exGeoTransform.transformBoundingBox( layerExtent );
601  }
602  catch ( const QgsCsException & )
603  {
604  wgs84BoundingRect = QgsRectangle();
605  }
606  }
607 
608  //create WGS84BoundingBox element
609  QDomElement bBoxElement = doc.createElement( QStringLiteral( "ows:WGS84BoundingBox" ) );
610  bBoxElement.setAttribute( QStringLiteral( "dimensions" ), QStringLiteral( "2" ) );
611  QDomElement lCornerElement = doc.createElement( QStringLiteral( "ows:LowerCorner" ) );
612  QDomText lCornerText = doc.createTextNode( QString::number( wgs84BoundingRect.xMinimum() ) + " " + QString::number( wgs84BoundingRect.yMinimum() ) );
613  lCornerElement.appendChild( lCornerText );
614  bBoxElement.appendChild( lCornerElement );
615  QDomElement uCornerElement = doc.createElement( QStringLiteral( "ows:UpperCorner" ) );
616  QDomText uCornerText = doc.createTextNode( QString::number( wgs84BoundingRect.xMaximum() ) + " " + QString::number( wgs84BoundingRect.yMaximum() ) );
617  uCornerElement.appendChild( uCornerText );
618  bBoxElement.appendChild( uCornerElement );
619  layerElem.appendChild( bBoxElement );
620 
621  // layer metadata URL
622  QString metadataUrl = layer->metadataUrl();
623  if ( !metadataUrl.isEmpty() )
624  {
625  QDomElement metaUrlElem = doc.createElement( QStringLiteral( "MetadataURL" ) );
626  QString metadataUrlType = layer->metadataUrlType();
627  metaUrlElem.setAttribute( QStringLiteral( "type" ), metadataUrlType );
628  QString metadataUrlFormat = layer->metadataUrlFormat();
629  metaUrlElem.setAttribute( QStringLiteral( "format" ), metadataUrlFormat );
630  QDomText metaUrlText = doc.createTextNode( metadataUrl );
631  metaUrlElem.appendChild( metaUrlText );
632  layerElem.appendChild( metaUrlElem );
633  }
634 
635  featureTypeListElement.appendChild( layerElem );
636  }
637 
638  return featureTypeListElement;
639  }
640 
641 } // namespace QgsWfs
642 
643 
644 
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:78
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:294
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:442
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:310
QDomElement getServiceIdentificationElement(QDomDocument &doc, const QgsProject *project)
Create Service Identification element for get capabilities document.
const QString GML_NAMESPACE
Definition: qgswfsutils.h:67
const QString WFS_NAMESPACE
Definition: qgswfsutils.h:66
A helper class that centralizes caches accesses given by all the server cache filter plugins...
Allows modifications of geometries.
Reads and writes project states.
Definition: qgsproject.h:89
const QString GEO_EPSG_CRS_AUTHID
Geographic coord sys from EPSG authority.
Definition: qgis.cpp:69
QDomElement getOperationsMetadataElement(QDomDocument &doc, const QgsProject *project, const QgsServerRequest &request)
Create OperationsMetadata element for get capabilities document.
QString implementationVersion()
Returns the highest version supported by this implementation.
Definition: qgswfsutils.cpp: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:278
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:68
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...
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:406
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QString name
Definition: qgsmaplayer.h:82
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:85
QString metadataUrlType() const
Returns the metadata type of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:424
SERVER_EXPORT QString owsServiceContactPhone(const QgsProject &project)
Returns the owsService contact phone defined in project.