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