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