QGIS API Documentation 3.43.0-Master (c67cf405802)
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, const QgsServerRequest &request, QgsServerResponse &response ) const
37{
38#ifdef HAVE_SERVER_PYTHON_PLUGINS
39 QgsAccessControl *accessControl = serverIface->accessControls();
40#endif
41 QDomDocument doc;
42 const QDomDocument *describeDocument = nullptr;
43
44#ifdef HAVE_SERVER_PYTHON_PLUGINS
45 QgsServerCacheManager *cacheManager = serverIface->cacheManager();
46 if ( cacheManager && cacheManager->getCachedDocument( &doc, project, request, accessControl ) )
47 {
48 describeDocument = &doc;
49 }
50 else //describe feature xml not in cache. Create a new one
51 {
52 doc = createDescribeFeatureTypeDocument( serverIface, project, version, request );
53
54 if ( cacheManager )
55 {
56 cacheManager->setCachedDocument( &doc, project, request, accessControl );
57 }
58 describeDocument = &doc;
59 }
60#else
61 doc = createDescribeFeatureTypeDocument( serverIface, project, version, request );
62 describeDocument = &doc;
63#endif
64 response.setHeader( "Content-Type", "text/xml; charset=utf-8" );
65 response.write( describeDocument->toByteArray() );
66}
67
68
69QDomDocument QgsWfsDescribeFeatureTypeGml::createDescribeFeatureTypeDocument( QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request ) const
70{
71 Q_UNUSED( version )
72
73 QDomDocument doc;
74
75#ifdef HAVE_SERVER_PYTHON_PLUGINS
76 QgsAccessControl *accessControl = serverIface->accessControls();
77#else
78 ( void ) serverIface;
79#endif
80
81 auto outputFormat = wfsParameters.outputFormat();
82
83 //xsd:schema
84 QDomElement schemaElement = doc.createElement( QStringLiteral( "schema" ) /*xsd:schema*/ );
85 schemaElement.setAttribute( QStringLiteral( "xmlns" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema" ) );
86 schemaElement.setAttribute( QStringLiteral( "xmlns:xsd" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema" ) );
87 schemaElement.setAttribute( QStringLiteral( "xmlns:ogc" ), OGC_NAMESPACE );
88 schemaElement.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE );
89 schemaElement.setAttribute( QStringLiteral( "xmlns:qgs" ), QGS_NAMESPACE );
90 schemaElement.setAttribute( QStringLiteral( "targetNamespace" ), QGS_NAMESPACE );
91 schemaElement.setAttribute( QStringLiteral( "elementFormDefault" ), QStringLiteral( "qualified" ) );
92 schemaElement.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0" ) );
93 doc.appendChild( schemaElement );
94
95 //xsd:import
96 QDomElement importElement = doc.createElement( QStringLiteral( "import" ) /*xsd:import*/ );
97 importElement.setAttribute( QStringLiteral( "namespace" ), GML_NAMESPACE );
98 if ( outputFormat == QgsWfsParameters::Format::GML2 )
99 importElement.setAttribute( QStringLiteral( "schemaLocation" ), QStringLiteral( "http://schemas.opengis.net/gml/2.1.2/feature.xsd" ) );
100 else if ( outputFormat == QgsWfsParameters::Format::GML3 )
101 importElement.setAttribute( QStringLiteral( "schemaLocation" ), QStringLiteral( "http://schemas.opengis.net/gml/3.1.1/base/gml.xsd" ) );
102 schemaElement.appendChild( importElement );
103
104 QStringList typeNameList = getRequestTypeNames( request, wfsParameters );
105
106 const QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project );
107 for ( int i = 0; i < wfsLayerIds.size(); ++i )
108 {
109 QgsMapLayer *layer = project->mapLayer( wfsLayerIds.at( i ) );
110 if ( !layer )
111 {
112 continue;
113 }
114
115 const QString name = layerTypeName( layer );
116
117 if ( !typeNameList.isEmpty() && !typeNameList.contains( name ) )
118 {
119 continue;
120 }
121#ifdef HAVE_SERVER_PYTHON_PLUGINS
122 if ( accessControl && !accessControl->layerReadPermission( layer ) )
123 {
124 if ( !typeNameList.isEmpty() )
125 {
126 throw QgsSecurityAccessException( QStringLiteral( "Feature access permission denied" ) );
127 }
128 else
129 {
130 continue;
131 }
132 }
133#endif
134 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( layer );
135 QgsVectorDataProvider *provider = vLayer->dataProvider();
136 if ( !provider )
137 {
138 continue;
139 }
140 setSchemaLayer( schemaElement, doc, const_cast<QgsVectorLayer *>( vLayer ) );
141 }
142 return doc;
143}
144
145void QgsWfsDescribeFeatureTypeGml::setSchemaLayer( QDomElement &parentElement, QDomDocument &doc, const QgsVectorLayer *layer ) const
146{
147 const QgsVectorDataProvider *provider = layer->dataProvider();
148 if ( !provider )
149 {
150 return;
151 }
152
153 const QString typeName = layerTypeName( layer );
154
155 //xsd:element
156 QDomElement elementElem = doc.createElement( QStringLiteral( "element" ) /*xsd:element*/ );
157 elementElem.setAttribute( QStringLiteral( "name" ), typeName );
158 elementElem.setAttribute( QStringLiteral( "type" ), "qgs:" + typeName + "Type" );
159 elementElem.setAttribute( QStringLiteral( "substitutionGroup" ), QStringLiteral( "gml:_Feature" ) );
160 parentElement.appendChild( elementElem );
161
162 //xsd:complexType
163 QDomElement complexTypeElem = doc.createElement( QStringLiteral( "complexType" ) /*xsd:complexType*/ );
164 complexTypeElem.setAttribute( QStringLiteral( "name" ), typeName + "Type" );
165 parentElement.appendChild( complexTypeElem );
166
167 //xsd:complexType
168 QDomElement complexContentElem = doc.createElement( QStringLiteral( "complexContent" ) /*xsd:complexContent*/ );
169 complexTypeElem.appendChild( complexContentElem );
170
171 //xsd:extension
172 QDomElement extensionElem = doc.createElement( QStringLiteral( "extension" ) /*xsd:extension*/ );
173 extensionElem.setAttribute( QStringLiteral( "base" ), QStringLiteral( "gml:AbstractFeatureType" ) );
174 complexContentElem.appendChild( extensionElem );
175
176 //xsd:sequence
177 QDomElement sequenceElem = doc.createElement( QStringLiteral( "sequence" ) /*xsd:sequence*/ );
178 extensionElem.appendChild( sequenceElem );
179
180 //xsd:element
181 if ( layer->isSpatial() )
182 {
183 QDomElement geomElem = doc.createElement( QStringLiteral( "element" ) /*xsd:element*/ );
184 geomElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "geometry" ) );
185 geomElem.setAttribute( QStringLiteral( "type" ), getGmlGeometryType( layer ) );
186 geomElem.setAttribute( QStringLiteral( "minOccurs" ), QStringLiteral( "0" ) );
187 geomElem.setAttribute( QStringLiteral( "maxOccurs" ), QStringLiteral( "1" ) );
188 sequenceElem.appendChild( geomElem );
189 }
190
191 //Attributes
192 const QgsFields fields = layer->fields();
193 //hidden attributes for this layer
194 for ( int idx = 0; idx < fields.count(); ++idx )
195 {
196 const QgsField field = fields.at( idx );
197 //skip attribute if excluded from WFS publication
199 {
200 continue;
201 }
202
203 QString attributeName, attributeType;
204
205 // Defined in qgswfsdescribefeaturetype.h
206 getFieldAttributes( field, attributeName, attributeType );
207
208 //xsd:element
209 QDomElement attElem = doc.createElement( QStringLiteral( "element" ) /*xsd:element*/ );
210
211 attElem.setAttribute( QStringLiteral( "name" ), attributeName );
212 attElem.setAttribute( QStringLiteral( "type" ), attributeType );
213
215 {
216 attElem.setAttribute( QStringLiteral( "nillable" ), QStringLiteral( "true" ) );
217 }
218
219 sequenceElem.appendChild( attElem );
220
221 const QString alias = field.alias();
222 if ( !alias.isEmpty() )
223 {
224 attElem.setAttribute( QStringLiteral( "alias" ), alias );
225 }
226 }
227}
228
229QString QgsWfsDescribeFeatureTypeGml::getGmlGeometryType( const QgsVectorLayer *layer ) const
230{
231 const Qgis::WkbType wkbType = layer->wkbType();
232 switch ( wfsParameters.outputFormat() )
233 {
234 case QgsWfsParameters::Format::GML2:
235 switch ( wkbType )
236 {
239 return QStringLiteral( "gml:PointPropertyType" );
240
243 return QStringLiteral( "gml:LineStringPropertyType" );
244
247 return QStringLiteral( "gml:PolygonPropertyType" );
248
251 return QStringLiteral( "gml:MultiPointPropertyType" );
252
256 return QStringLiteral( "gml:MultiLineStringPropertyType" );
257
261 return QStringLiteral( "gml:MultiPolygonPropertyType" );
262
263 default:
264 return QStringLiteral( "gml:GeometryPropertyType" );
265 }
266 case QgsWfsParameters::Format::GML3:
267 switch ( wkbType )
268 {
271 return QStringLiteral( "gml:PointPropertyType" );
272
275 return QStringLiteral( "gml:LineStringPropertyType" );
276
279 return QStringLiteral( "gml:PolygonPropertyType" );
280
283 return QStringLiteral( "gml:MultiPointPropertyType" );
284
288 return QStringLiteral( "gml:MultiCurvePropertyType" );
289
293 return QStringLiteral( "gml:MultiSurfacePropertyType" );
294
295 default:
296 return QStringLiteral( "gml:GeometryPropertyType" );
297 }
298 default:
299 return QStringLiteral( "gml:GeometryPropertyType" );
300 }
301}
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:256
@ 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.
@ ConstraintNotNull
Field may not be null.
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:46
int count
Definition qgsfields.h:50
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Base class for all map layer types.
Definition qgsmaplayer.h:77
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.
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.
static QStringList wfsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WFS.
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...
Base class for vector data providers.
Represents a vector layer which manages a vector based dataset.
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
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.
WMS implementation.
Definition qgswfs.cpp:36
QString layerTypeName(const QgsMapLayer *layer)
Returns typename from vector layer.
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
const QString & typeName