QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgswfsdescribefeaturetypegml.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgswfsdescribefeaturetypegml.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"
26#include "qgswfsparameters.h"
27#include "qgsproject.h"
28#include "qgsvectorlayer.h"
29
30using namespace QgsWfs;
31
33 : wfsParameters( wfsParams )
34{}
35
36void QgsWfsDescribeFeatureTypeGml::writeDescribeFeatureType( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
37 const QgsServerRequest &request, QgsServerResponse &response ) const
38{
39#ifdef HAVE_SERVER_PYTHON_PLUGINS
40 QgsAccessControl *accessControl = serverIface->accessControls();
41#endif
42 QDomDocument doc;
43 const QDomDocument *describeDocument = nullptr;
44
45#ifdef HAVE_SERVER_PYTHON_PLUGINS
46 QgsServerCacheManager *cacheManager = serverIface->cacheManager();
47 if ( cacheManager && cacheManager->getCachedDocument( &doc, project, request, accessControl ) )
48 {
49 describeDocument = &doc;
50 }
51 else //describe feature xml not in cache. Create a new one
52 {
53 doc = createDescribeFeatureTypeDocument( serverIface, project, version, request );
54
55 if ( cacheManager )
56 {
57 cacheManager->setCachedDocument( &doc, project, request, accessControl );
58 }
59 describeDocument = &doc;
60 }
61#else
62 doc = createDescribeFeatureTypeDocument( serverIface, project, version, request );
63 describeDocument = &doc;
64#endif
65 response.setHeader( "Content-Type", "text/xml; charset=utf-8" );
66 response.write( describeDocument->toByteArray() );
67}
68
69
70QDomDocument QgsWfsDescribeFeatureTypeGml::createDescribeFeatureTypeDocument( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
71 const QgsServerRequest &request ) const
72{
73 Q_UNUSED( version )
74
75 QDomDocument doc;
76
77#ifdef HAVE_SERVER_PYTHON_PLUGINS
78 QgsAccessControl *accessControl = serverIface->accessControls();
79#else
80 ( void )serverIface;
81#endif
82
83 auto outputFormat = wfsParameters.outputFormat();
84
85 //xsd:schema
86 QDomElement schemaElement = doc.createElement( QStringLiteral( "schema" )/*xsd:schema*/ );
87 schemaElement.setAttribute( QStringLiteral( "xmlns" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema" ) );
88 schemaElement.setAttribute( QStringLiteral( "xmlns:xsd" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema" ) );
89 schemaElement.setAttribute( QStringLiteral( "xmlns:ogc" ), OGC_NAMESPACE );
90 schemaElement.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE );
91 schemaElement.setAttribute( QStringLiteral( "xmlns:qgs" ), QGS_NAMESPACE );
92 schemaElement.setAttribute( QStringLiteral( "targetNamespace" ), QGS_NAMESPACE );
93 schemaElement.setAttribute( QStringLiteral( "elementFormDefault" ), QStringLiteral( "qualified" ) );
94 schemaElement.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0" ) );
95 doc.appendChild( schemaElement );
96
97 //xsd:import
98 QDomElement importElement = doc.createElement( QStringLiteral( "import" )/*xsd:import*/ );
99 importElement.setAttribute( QStringLiteral( "namespace" ), GML_NAMESPACE );
100 if ( outputFormat == QgsWfsParameters::Format::GML2 )
101 importElement.setAttribute( QStringLiteral( "schemaLocation" ), QStringLiteral( "http://schemas.opengis.net/gml/2.1.2/feature.xsd" ) );
102 else if ( outputFormat == QgsWfsParameters::Format::GML3 )
103 importElement.setAttribute( QStringLiteral( "schemaLocation" ), QStringLiteral( "http://schemas.opengis.net/gml/3.1.1/base/gml.xsd" ) );
104 schemaElement.appendChild( importElement );
105
106 QStringList typeNameList = getRequestTypeNames( request, wfsParameters );
107
108 const QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project );
109 for ( int i = 0; i < wfsLayerIds.size(); ++i )
110 {
111 QgsMapLayer *layer = project->mapLayer( wfsLayerIds.at( i ) );
112 if ( !layer )
113 {
114 continue;
115 }
116
117 const QString name = layerTypeName( layer );
118
119 if ( !typeNameList.isEmpty() && !typeNameList.contains( name ) )
120 {
121 continue;
122 }
123#ifdef HAVE_SERVER_PYTHON_PLUGINS
124 if ( accessControl && !accessControl->layerReadPermission( layer ) )
125 {
126 if ( !typeNameList.isEmpty() )
127 {
128 throw QgsSecurityAccessException( QStringLiteral( "Feature access permission denied" ) );
129 }
130 else
131 {
132 continue;
133 }
134 }
135#endif
136 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( layer );
137 QgsVectorDataProvider *provider = vLayer->dataProvider();
138 if ( !provider )
139 {
140 continue;
141 }
142 setSchemaLayer( schemaElement, doc, const_cast<QgsVectorLayer *>( vLayer ) );
143 }
144 return doc;
145}
146
147void QgsWfsDescribeFeatureTypeGml::setSchemaLayer( QDomElement &parentElement, QDomDocument &doc, const QgsVectorLayer *layer ) const
148{
149 const QgsVectorDataProvider *provider = layer->dataProvider();
150 if ( !provider )
151 {
152 return;
153 }
154
155 const QString typeName = layerTypeName( layer );
156
157 //xsd:element
158 QDomElement elementElem = doc.createElement( QStringLiteral( "element" )/*xsd:element*/ );
159 elementElem.setAttribute( QStringLiteral( "name" ), typeName );
160 elementElem.setAttribute( QStringLiteral( "type" ), "qgs:" + typeName + "Type" );
161 elementElem.setAttribute( QStringLiteral( "substitutionGroup" ), QStringLiteral( "gml:_Feature" ) );
162 parentElement.appendChild( elementElem );
163
164 //xsd:complexType
165 QDomElement complexTypeElem = doc.createElement( QStringLiteral( "complexType" )/*xsd:complexType*/ );
166 complexTypeElem.setAttribute( QStringLiteral( "name" ), typeName + "Type" );
167 parentElement.appendChild( complexTypeElem );
168
169 //xsd:complexType
170 QDomElement complexContentElem = doc.createElement( QStringLiteral( "complexContent" )/*xsd:complexContent*/ );
171 complexTypeElem.appendChild( complexContentElem );
172
173 //xsd:extension
174 QDomElement extensionElem = doc.createElement( QStringLiteral( "extension" )/*xsd:extension*/ );
175 extensionElem.setAttribute( QStringLiteral( "base" ), QStringLiteral( "gml:AbstractFeatureType" ) );
176 complexContentElem.appendChild( extensionElem );
177
178 //xsd:sequence
179 QDomElement sequenceElem = doc.createElement( QStringLiteral( "sequence" )/*xsd:sequence*/ );
180 extensionElem.appendChild( sequenceElem );
181
182 //xsd:element
183 if ( layer->isSpatial() )
184 {
185 QDomElement geomElem = doc.createElement( QStringLiteral( "element" )/*xsd:element*/ );
186 geomElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "geometry" ) );
187 geomElem.setAttribute( QStringLiteral( "type" ), getGmlGeometryType( layer ) );
188 geomElem.setAttribute( QStringLiteral( "minOccurs" ), QStringLiteral( "0" ) );
189 geomElem.setAttribute( QStringLiteral( "maxOccurs" ), QStringLiteral( "1" ) );
190 sequenceElem.appendChild( geomElem );
191 }
192
193 //Attributes
194 const QgsFields fields = layer->fields();
195 //hidden attributes for this layer
196 for ( int idx = 0; idx < fields.count(); ++idx )
197 {
198 const QgsField field = fields.at( idx );
199 //skip attribute if excluded from WFS publication
201 {
202 continue;
203 }
204
205 QString attributeName, attributeType;
206
207 // Defined in qgswfsdescribefeaturetype.h
208 getFieldAttributes( field, attributeName, attributeType );
209
210 //xsd:element
211 QDomElement attElem = doc.createElement( QStringLiteral( "element" )/*xsd:element*/ );
212
213 attElem.setAttribute( QStringLiteral( "name" ), attributeName );
214 attElem.setAttribute( QStringLiteral( "type" ), attributeType );
215
216 if ( !( field.constraints().constraints() & QgsFieldConstraints::Constraint::ConstraintNotNull ) )
217 {
218 attElem.setAttribute( QStringLiteral( "nillable" ), QStringLiteral( "true" ) );
219 }
220
221 sequenceElem.appendChild( attElem );
222
223 const QString alias = field.alias();
224 if ( !alias.isEmpty() )
225 {
226 attElem.setAttribute( QStringLiteral( "alias" ), alias );
227 }
228 }
229}
230
231QString QgsWfsDescribeFeatureTypeGml::getGmlGeometryType( const QgsVectorLayer *layer ) const
232{
233 const Qgis::WkbType wkbType = layer->wkbType();
234 switch ( wfsParameters.outputFormat() )
235 {
236 case QgsWfsParameters::Format::GML2:
237 switch ( wkbType )
238 {
241 return QStringLiteral( "gml:PointPropertyType" );
242
245 return QStringLiteral( "gml:LineStringPropertyType" );
246
249 return QStringLiteral( "gml:PolygonPropertyType" );
250
253 return QStringLiteral( "gml:MultiPointPropertyType" );
254
258 return QStringLiteral( "gml:MultiLineStringPropertyType" );
259
263 return QStringLiteral( "gml:MultiPolygonPropertyType" );
264
265 default:
266 return QStringLiteral( "gml:GeometryPropertyType" );
267
268 }
269 case QgsWfsParameters::Format::GML3:
270 switch ( wkbType )
271 {
274 return QStringLiteral( "gml:PointPropertyType" );
275
278 return QStringLiteral( "gml:LineStringPropertyType" );
279
282 return QStringLiteral( "gml:PolygonPropertyType" );
283
286 return QStringLiteral( "gml:MultiPointPropertyType" );
287
291 return QStringLiteral( "gml:MultiCurvePropertyType" );
292
296 return QStringLiteral( "gml:MultiSurfacePropertyType" );
297
298 default:
299 return QStringLiteral( "gml:GeometryPropertyType" );
300 }
301 default:
302 return QStringLiteral( "gml:GeometryPropertyType" );
303 }
304}
305
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition: qgis.h:182
@ LineString25D
LineString25D.
@ LineString
LineString.
@ MultiPolygon25D
MultiPolygon25D.
@ MultiPoint
MultiPoint.
@ Polygon
Polygon.
@ MultiLineString25D
MultiLineString25D.
@ MultiPolygon
MultiPolygon.
@ MultiLineString
MultiLineString.
@ MultiPoint25D
MultiPoint25D.
@ MultiCurve
MultiCurve.
@ Point25D
Point25D.
@ MultiSurface
MultiSurface.
@ Polygon25D
Polygon25D.
@ HideFromWfs
Field is not available if layer is served as WFS from QGIS server.
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.
Q_GADGET Constraints constraints
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:53
Qgis::FieldConfigurationFlags configurationFlags
Definition: qgsfield.h:66
QString alias
Definition: qgsfield.h:63
QgsFieldConstraints constraints
Definition: qgsfield.h:65
Container of fields for a vector layer.
Definition: qgsfields.h:45
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
Base class for all map layer types.
Definition: qgsmaplayer.h:75
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:107
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
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.
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...
This is the base class for vector data providers.
Represents a vector layer which manages a vector based data sets.
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
void writeDescribeFeatureType(QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response) const
Output GML response.
QgsWfsDescribeFeatureTypeGml(const QgsWfs::QgsWfsParameters wfsParams)
Constructor.
Exception thrown when data access violates access controls.
Provides an interface to retrieve and manipulate WFS parameters received from the client.
Format outputFormat() const
Returns format.
SERVER_EXPORT QStringList wfsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WFS.
WMS implementation.
Definition: qgswfs.cpp:36
QString layerTypeName(const QgsMapLayer *layer)
Returns typename from vector layer.
Definition: qgswfsutils.cpp:68
void getFieldAttributes(const QgsField &field, QString &fieldName, QString &fieldType)
Helper for returning the field type and type name.
const QString QGS_NAMESPACE
Definition: qgswfsutils.h:77
QStringList getRequestTypeNames(const QgsServerRequest &request, const QgsWfsParameters &wfsParams)
Helper for returning typename list from the request.
#define GML_NAMESPACE
#define OGC_NAMESPACE
Definition: qgsogcutils.cpp:45
const QString & typeName