|
1 |
#include "qgswfsserver.h"
|
|
2 |
#include "qgsconfigparser.h"
|
|
3 |
#include "qgsepsgcache.h"
|
|
4 |
#include "qgsfield.h"
|
|
5 |
#include "qgsgeometry.h"
|
|
6 |
#include "qgsmaplayer.h"
|
|
7 |
#include "qgsmaplayerregistry.h"
|
|
8 |
#include "qgsmaprenderer.h"
|
|
9 |
#include "qgsmaptopixel.h"
|
|
10 |
#include "qgspallabeling.h"
|
|
11 |
#include "qgsproject.h"
|
|
12 |
#include "qgsrasterlayer.h"
|
|
13 |
#include "qgsscalecalculator.h"
|
|
14 |
#include "qgscoordinatereferencesystem.h"
|
|
15 |
#include "qgsvectordataprovider.h"
|
|
16 |
#include "qgsvectorlayer.h"
|
|
17 |
#include "qgsfilter.h"
|
|
18 |
#include "qgsmapserverlogger.h"
|
|
19 |
#include "qgsmapserviceexception.h"
|
|
20 |
#include "qgssldparser.h"
|
|
21 |
#include "qgssymbol.h"
|
|
22 |
#include "qgssymbolv2.h"
|
|
23 |
#include "qgsrenderer.h"
|
|
24 |
#include "qgslegendmodel.h"
|
|
25 |
#include "qgscomposerlegenditem.h"
|
|
26 |
#include "qgslogger.h"
|
|
27 |
#include <QImage>
|
|
28 |
#include <QPainter>
|
|
29 |
#include <QStringList>
|
|
30 |
#include <QTextStream>
|
|
31 |
#include <QDir>
|
|
32 |
|
|
33 |
//for printing
|
|
34 |
#include "qgscomposition.h"
|
|
35 |
#include <QBuffer>
|
|
36 |
#include <QPrinter>
|
|
37 |
#include <QSvgGenerator>
|
|
38 |
#include <QUrl>
|
|
39 |
#include <QPaintEngine>
|
|
40 |
|
|
41 |
QgsWFSServer::QgsWFSServer( std::map<QString, QString> parameters )
|
|
42 |
: mParameterMap( parameters )
|
|
43 |
, mConfigParser( 0 )
|
|
44 |
{
|
|
45 |
}
|
|
46 |
|
|
47 |
QgsWFSServer::~QgsWFSServer()
|
|
48 |
{
|
|
49 |
}
|
|
50 |
|
|
51 |
QgsWFSServer::QgsWFSServer()
|
|
52 |
{
|
|
53 |
}
|
|
54 |
|
|
55 |
QDomDocument QgsWFSServer::getCapabilities()
|
|
56 |
{
|
|
57 |
QgsMSDebugMsg( "Entering." );
|
|
58 |
QDomDocument doc;
|
|
59 |
//wfs:WFS_Capabilities element
|
|
60 |
QDomElement wfsCapabilitiesElement = doc.createElement( "WFS_Capabilities"/*wms:WFS_Capabilities*/ );
|
|
61 |
wfsCapabilitiesElement.setAttribute( "xmlns", "http://www.opengis.net/wfs" );
|
|
62 |
wfsCapabilitiesElement.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
|
|
63 |
wfsCapabilitiesElement.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" );
|
|
64 |
wfsCapabilitiesElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
|
|
65 |
wfsCapabilitiesElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" );
|
|
66 |
wfsCapabilitiesElement.setAttribute( "xmlns:ows", "http://www.opengis.net/ows" );
|
|
67 |
wfsCapabilitiesElement.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
|
|
68 |
wfsCapabilitiesElement.setAttribute( "version", "1.0.0" );
|
|
69 |
wfsCapabilitiesElement.setAttribute( "updateSequence", "0" );
|
|
70 |
doc.appendChild( wfsCapabilitiesElement );
|
|
71 |
|
|
72 |
if ( mConfigParser )
|
|
73 |
{
|
|
74 |
mConfigParser->serviceCapabilities( wfsCapabilitiesElement, doc );
|
|
75 |
}
|
|
76 |
|
|
77 |
//wfs:Capability element
|
|
78 |
QDomElement capabilityElement = doc.createElement( "Capability"/*wfs:Capability*/ );
|
|
79 |
wfsCapabilitiesElement.appendChild( capabilityElement );
|
|
80 |
|
|
81 |
//wfs:Request element
|
|
82 |
QDomElement requestElement = doc.createElement( "Request"/*wfs:Request*/ );
|
|
83 |
capabilityElement.appendChild( requestElement );
|
|
84 |
//wfs:GetCapabilities
|
|
85 |
QDomElement getCapabilitiesElement = doc.createElement( "GetCapabilities"/*wfs:GetCapabilities*/ );
|
|
86 |
requestElement.appendChild( getCapabilitiesElement );
|
|
87 |
QDomElement capabilitiesFormatElement = doc.createElement( "Format" );/*wfs:Format*/
|
|
88 |
getCapabilitiesElement.appendChild( capabilitiesFormatElement );
|
|
89 |
QDomText capabilitiesFormatText = doc.createTextNode( "text/xml" );
|
|
90 |
capabilitiesFormatElement.appendChild( capabilitiesFormatText );
|
|
91 |
|
|
92 |
QDomElement dcpTypeElement = doc.createElement( "DCPType"/*wfs:DCPType*/ );
|
|
93 |
getCapabilitiesElement.appendChild( dcpTypeElement );
|
|
94 |
QDomElement httpElement = doc.createElement( "HTTP"/*wfs:HTTP*/ );
|
|
95 |
dcpTypeElement.appendChild( httpElement );
|
|
96 |
|
|
97 |
//Prepare url
|
|
98 |
//Some client requests already have http://<SERVER_NAME> in the REQUEST_URI variable
|
|
99 |
QString hrefString;
|
|
100 |
QString requestUrl = getenv( "REQUEST_URI" );
|
|
101 |
QUrl mapUrl( requestUrl );
|
|
102 |
mapUrl.setHost( QString( getenv( "SERVER_NAME" ) ) );
|
|
103 |
mapUrl.removeQueryItem( "REQUEST" );
|
|
104 |
mapUrl.removeQueryItem( "VERSION" );
|
|
105 |
mapUrl.removeQueryItem( "SERVICE" );
|
|
106 |
hrefString = mapUrl.toString();
|
|
107 |
|
|
108 |
//only Get supported for the moment
|
|
109 |
QDomElement getElement = doc.createElement( "Get"/*wfs:Get*/ );
|
|
110 |
httpElement.appendChild( getElement );
|
|
111 |
QDomElement olResourceElement = doc.createElement( "OnlineResource"/*wfs:OnlineResource*/ );
|
|
112 |
olResourceElement.setAttribute( "xlink:type", "simple" );
|
|
113 |
requestUrl.truncate( requestUrl.indexOf( "?" ) + 1 );
|
|
114 |
olResourceElement.setAttribute( "xlink:href", hrefString );
|
|
115 |
getElement.appendChild( olResourceElement );
|
|
116 |
|
|
117 |
//wfs:DescribeFeatureType
|
|
118 |
QDomElement describeFeatureTypeElement = doc.createElement( "DescribeFeatureType"/*wfs:DescribeFeatureType*/ );
|
|
119 |
requestElement.appendChild( describeFeatureTypeElement );
|
|
120 |
QDomElement schemaDescriptionLanguageElement = doc.createElement( "SchemaDescriptionLanguage"/*wfs:SchemaDescriptionLanguage*/ );
|
|
121 |
describeFeatureTypeElement.appendChild( schemaDescriptionLanguageElement );
|
|
122 |
QDomElement xmlSchemaElement = doc.createElement( "XMLSCHEMA"/*wfs:XMLSCHEMA*/ );
|
|
123 |
schemaDescriptionLanguageElement.appendChild( xmlSchemaElement );
|
|
124 |
QDomElement describeFeatureTypeDhcTypeElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities'
|
|
125 |
describeFeatureTypeElement.appendChild( describeFeatureTypeDhcTypeElement );
|
|
126 |
|
|
127 |
//wfs:GetFeature
|
|
128 |
QDomElement getFeatureElement = doc.createElement( "GetFeature"/*wfs:GetFeature*/ );
|
|
129 |
requestElement.appendChild( getFeatureElement );
|
|
130 |
QDomElement getFeatureFormatElement = doc.createElement( "ResultFormat" );/*wfs:ResultFormat*/
|
|
131 |
getFeatureElement.appendChild( getFeatureFormatElement );
|
|
132 |
QDomElement gmlFormatElement = doc.createElement( "GML2" );/*wfs:GML2*/
|
|
133 |
getFeatureFormatElement.appendChild( gmlFormatElement );
|
|
134 |
QDomElement geojsonFormatElement = doc.createElement( "GeoJSON" );/*wfs:GeoJSON*/
|
|
135 |
getFeatureFormatElement.appendChild( geojsonFormatElement );
|
|
136 |
QDomElement getFeatureDhcTypeElement = dcpTypeElement.cloneNode().toElement();//this is the same as for 'GetCapabilities'
|
|
137 |
getFeatureElement.appendChild( getFeatureDhcTypeElement );
|
|
138 |
|
|
139 |
//wfs:FeatureTypeList element
|
|
140 |
QDomElement featureTypeListElement = doc.createElement( "FeatureTypeList"/*wfs:FeatureTypeList*/ );
|
|
141 |
capabilityElement.appendChild( featureTypeListElement );
|
|
142 |
//wfs:Operations element
|
|
143 |
QDomElement operationsElement = doc.createElement( "Operations"/*wfs:Operations*/ );
|
|
144 |
featureTypeListElement.appendChild( operationsElement );
|
|
145 |
//wfs:Query element
|
|
146 |
QDomElement queryElement = doc.createElement( "Query"/*wfs:Query*/ );
|
|
147 |
operationsElement.appendChild( queryElement );
|
|
148 |
/*
|
|
149 |
* Adding layer liste in featureTypeListElement
|
|
150 |
*/
|
|
151 |
if ( mConfigParser )
|
|
152 |
{
|
|
153 |
mConfigParser->featureTypeList( featureTypeListElement, doc );
|
|
154 |
}
|
|
155 |
|
|
156 |
/*
|
|
157 |
* Adding ogc:Filter_Capabilities in capabilityElement
|
|
158 |
*/
|
|
159 |
//ogc:Filter_Capabilities element
|
|
160 |
QDomElement filterCapabilitiesElement = doc.createElement( "ogc:Filter_Capabilities"/*ogc:Filter_Capabilities*/ );
|
|
161 |
capabilityElement.appendChild( filterCapabilitiesElement );
|
|
162 |
QDomElement spatialCapabilitiesElement = doc.createElement( "ogc:Spatial_Capabilities"/*ogc:Spatial_Capabilities*/ );
|
|
163 |
filterCapabilitiesElement.appendChild( spatialCapabilitiesElement );
|
|
164 |
QDomElement spatialOperatorsElement = doc.createElement( "ogc:Spatial_Operators"/*ogc:Spatial_Operators*/ );
|
|
165 |
spatialCapabilitiesElement.appendChild( spatialOperatorsElement );
|
|
166 |
QDomElement ogcBboxElement = doc.createElement( "ogc:BBOX"/*ogc:BBOX*/ );
|
|
167 |
spatialOperatorsElement.appendChild( ogcBboxElement );
|
|
168 |
QDomElement scalarCapabilitiesElement = doc.createElement( "ogc:Scalar_Capabilities"/*ogc:Scalar_Capabilities*/ );
|
|
169 |
filterCapabilitiesElement.appendChild( scalarCapabilitiesElement );
|
|
170 |
QDomElement comparisonOperatorsElement = doc.createElement( "ogc:Comparison_Operators"/*ogc:Comparison_Operators*/ );
|
|
171 |
scalarCapabilitiesElement.appendChild( comparisonOperatorsElement );
|
|
172 |
QDomElement simpleComparisonsElement = doc.createElement( "ogc:Simple_Comparisons"/*ogc:Simple_Comparisons*/ );
|
|
173 |
comparisonOperatorsElement.appendChild( simpleComparisonsElement );
|
|
174 |
return doc;
|
|
175 |
}
|
|
176 |
|
|
177 |
QDomDocument QgsWFSServer::describeFeatureType()
|
|
178 |
{
|
|
179 |
QgsMSDebugMsg( "Entering." );
|
|
180 |
QDomDocument doc;
|
|
181 |
//xsd:schema
|
|
182 |
QDomElement schemaElement = doc.createElement( "schema"/*xsd:schema*/ );
|
|
183 |
schemaElement.setAttribute( "xmlns", "http://www.w3.org/2001/XMLSchema" );
|
|
184 |
schemaElement.setAttribute( "xmlns:xsd", "http://www.w3.org/2001/XMLSchema" );
|
|
185 |
schemaElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
|
|
186 |
schemaElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" );
|
|
187 |
schemaElement.setAttribute( "xmlns:qgs", "http://www.qgis.org/gml" );
|
|
188 |
schemaElement.setAttribute( "targetNamespace", "http://www.qgis.org/gml" );
|
|
189 |
doc.appendChild( schemaElement );
|
|
190 |
|
|
191 |
//xsd:import
|
|
192 |
QDomElement importElement = doc.createElement( "import"/*xsd:import*/ );
|
|
193 |
importElement.setAttribute( "namespace", "http://www.opengis.net/gml" );
|
|
194 |
importElement.setAttribute( "schemaLocation", "http://schemas.opengis.net/gml/2.1.2/feature.xsd" );
|
|
195 |
schemaElement.appendChild( importElement );
|
|
196 |
|
|
197 |
//read TYPENAME
|
|
198 |
QString typeName;
|
|
199 |
std::map<QString, QString>::const_iterator type_name_it = mParameterMap.find( "TYPENAME" );
|
|
200 |
if ( type_name_it != mParameterMap.end() )
|
|
201 |
{
|
|
202 |
typeName = type_name_it->second;
|
|
203 |
}
|
|
204 |
else
|
|
205 |
{
|
|
206 |
return doc;
|
|
207 |
}
|
|
208 |
|
|
209 |
QStringList nonIdentifiableLayers = mConfigParser->identifyDisabledLayers();
|
|
210 |
QMap< QString, QMap< int, QString > > aliasInfo = mConfigParser->layerAliasInfo();
|
|
211 |
QMap< QString, QSet<QString> > hiddenAttributes = mConfigParser->hiddenAttributes();
|
|
212 |
|
|
213 |
QList<QgsMapLayer*> layerList;
|
|
214 |
QgsMapLayer* currentLayer = 0;
|
|
215 |
|
|
216 |
layerList = mConfigParser->mapLayerFromStyle( typeName, "" );
|
|
217 |
currentLayer = layerList.at( 0 );
|
|
218 |
|
|
219 |
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>( currentLayer );
|
|
220 |
if ( layer )
|
|
221 |
{
|
|
222 |
//is there alias info for this vector layer?
|
|
223 |
QMap< int, QString > layerAliasInfo;
|
|
224 |
QMap< QString, QMap< int, QString > >::const_iterator aliasIt = aliasInfo.find( currentLayer->id() );
|
|
225 |
if ( aliasIt != aliasInfo.constEnd() )
|
|
226 |
{
|
|
227 |
layerAliasInfo = aliasIt.value();
|
|
228 |
}
|
|
229 |
|
|
230 |
//hidden attributes for this layer
|
|
231 |
QSet<QString> layerHiddenAttributes;
|
|
232 |
QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find( currentLayer->id() );
|
|
233 |
if ( hiddenIt != hiddenAttributes.constEnd() )
|
|
234 |
{
|
|
235 |
layerHiddenAttributes = hiddenIt.value();
|
|
236 |
}
|
|
237 |
|
|
238 |
//do a select with searchRect and go through all the features
|
|
239 |
QgsVectorDataProvider* provider = layer->dataProvider();
|
|
240 |
if ( !provider )
|
|
241 |
{
|
|
242 |
return doc;
|
|
243 |
}
|
|
244 |
|
|
245 |
typeName = typeName.replace( QString(" "), QString("_") );
|
|
246 |
|
|
247 |
//xsd:element
|
|
248 |
QDomElement elementElem = doc.createElement( "element"/*xsd:element*/ );
|
|
249 |
elementElem.setAttribute( "name", typeName );
|
|
250 |
elementElem.setAttribute( "type", "qgs:" + typeName + "Type" );
|
|
251 |
elementElem.setAttribute( "substitutionGroup", "gml:_Feature" );
|
|
252 |
schemaElement.appendChild( elementElem );
|
|
253 |
|
|
254 |
//xsd:complexType
|
|
255 |
QDomElement complexTypeElem = doc.createElement( "complexType"/*xsd:complexType*/ );
|
|
256 |
complexTypeElem.setAttribute( "name", typeName + "Type" );
|
|
257 |
schemaElement.appendChild( complexTypeElem );
|
|
258 |
|
|
259 |
//xsd:complexType
|
|
260 |
QDomElement complexContentElem = doc.createElement( "complexContent"/*xsd:complexContent*/ );
|
|
261 |
complexTypeElem.appendChild( complexContentElem );
|
|
262 |
|
|
263 |
//xsd:extension
|
|
264 |
QDomElement extensionElem = doc.createElement( "extension"/*xsd:extension*/ );
|
|
265 |
extensionElem.setAttribute( "base", "gml:AbstractFeatureType" );
|
|
266 |
complexContentElem.appendChild( extensionElem );
|
|
267 |
|
|
268 |
//xsd:sequence
|
|
269 |
QDomElement sequenceElem = doc.createElement( "sequence"/*xsd:sequence*/ );
|
|
270 |
extensionElem.appendChild( sequenceElem );
|
|
271 |
|
|
272 |
//xsd:element
|
|
273 |
QDomElement geomElem = doc.createElement( "element"/*xsd:element*/ );
|
|
274 |
geomElem.setAttribute( "name", "geometry" );
|
|
275 |
geomElem.setAttribute( "type", "gml:GeometryPropertyType" );
|
|
276 |
geomElem.setAttribute( "minOccurs", "0" );
|
|
277 |
geomElem.setAttribute( "maxOccurs", "1" );
|
|
278 |
sequenceElem.appendChild( geomElem );
|
|
279 |
|
|
280 |
const QgsFieldMap& fields = provider->fields();
|
|
281 |
for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it )
|
|
282 |
{
|
|
283 |
|
|
284 |
QString attributeName = it.value().name();
|
|
285 |
//skip attribute if it has edit type 'hidden'
|
|
286 |
if ( layerHiddenAttributes.contains( attributeName ) )
|
|
287 |
{
|
|
288 |
continue;
|
|
289 |
}
|
|
290 |
|
|
291 |
//check if the attribute name should be replaced with an alias
|
|
292 |
QMap<int, QString>::const_iterator aliasIt = layerAliasInfo.find( it.key() );
|
|
293 |
if ( aliasIt != layerAliasInfo.constEnd() )
|
|
294 |
{
|
|
295 |
attributeName = aliasIt.value();
|
|
296 |
}
|
|
297 |
|
|
298 |
//xsd:element
|
|
299 |
QDomElement geomElem = doc.createElement( "element"/*xsd:element*/ );
|
|
300 |
geomElem.setAttribute( "name", attributeName );
|
|
301 |
if ( it.value().type() == 2 )
|
|
302 |
geomElem.setAttribute( "type", "integer" );
|
|
303 |
else if ( it.value().type() == 6 )
|
|
304 |
geomElem.setAttribute( "type", "double" );
|
|
305 |
else
|
|
306 |
geomElem.setAttribute( "type", "string" );
|
|
307 |
|
|
308 |
sequenceElem.appendChild( geomElem );
|
|
309 |
|
|
310 |
}
|
|
311 |
}
|
|
312 |
|
|
313 |
return doc;
|
|
314 |
}
|
|
315 |
|
|
316 |
int QgsWFSServer::getFeature( QByteArray& result, const QString& format )
|
|
317 |
{
|
|
318 |
QgsMSDebugMsg( "Info format is:" + infoFormat );
|
|
319 |
|
|
320 |
//read TYPENAME
|
|
321 |
QString typeName;
|
|
322 |
std::map<QString, QString>::const_iterator type_name_it = mParameterMap.find( "TYPENAME" );
|
|
323 |
if ( type_name_it != mParameterMap.end() )
|
|
324 |
{
|
|
325 |
typeName = type_name_it->second;
|
|
326 |
}
|
|
327 |
else
|
|
328 |
{
|
|
329 |
return 1;
|
|
330 |
}
|
|
331 |
|
|
332 |
QStringList nonIdentifiableLayers = mConfigParser->identifyDisabledLayers();
|
|
333 |
QMap< QString, QMap< int, QString > > aliasInfo = mConfigParser->layerAliasInfo();
|
|
334 |
QMap< QString, QSet<QString> > hiddenAttributes = mConfigParser->hiddenAttributes();
|
|
335 |
|
|
336 |
QList<QgsMapLayer*> layerList;
|
|
337 |
QgsMapLayer* currentLayer = 0;
|
|
338 |
|
|
339 |
layerList = mConfigParser->mapLayerFromStyle( typeName, "" );
|
|
340 |
currentLayer = layerList.at( 0 );
|
|
341 |
|
|
342 |
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>( currentLayer );
|
|
343 |
if ( layer )
|
|
344 |
{
|
|
345 |
//is there alias info for this vector layer?
|
|
346 |
QMap< int, QString > layerAliasInfo;
|
|
347 |
QMap< QString, QMap< int, QString > >::const_iterator aliasIt = aliasInfo.find( currentLayer->id() );
|
|
348 |
if ( aliasIt != aliasInfo.constEnd() )
|
|
349 |
{
|
|
350 |
layerAliasInfo = aliasIt.value();
|
|
351 |
}
|
|
352 |
|
|
353 |
//hidden attributes for this layer
|
|
354 |
QSet<QString> layerHiddenAttributes;
|
|
355 |
QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find( currentLayer->id() );
|
|
356 |
if ( hiddenIt != hiddenAttributes.constEnd() )
|
|
357 |
{
|
|
358 |
layerHiddenAttributes = hiddenIt.value();
|
|
359 |
}
|
|
360 |
|
|
361 |
//do a select with searchRect and go through all the features
|
|
362 |
QgsVectorDataProvider* provider = layer->dataProvider();
|
|
363 |
if ( !provider )
|
|
364 |
{
|
|
365 |
return 2;
|
|
366 |
}
|
|
367 |
|
|
368 |
QgsFeature feature;
|
|
369 |
QgsAttributeMap featureAttributes;
|
|
370 |
const QgsFieldMap& fields = provider->fields();
|
|
371 |
|
|
372 |
//map extent
|
|
373 |
QgsRectangle searchRect = layer->extent();
|
|
374 |
|
|
375 |
//read FEATUREDID
|
|
376 |
bool fidOk = false;
|
|
377 |
QString fid;
|
|
378 |
std::map<QString, QString>::const_iterator fidIt = mParameterMap.find( "FEATUREID" );
|
|
379 |
if ( fidIt != mParameterMap.end() ) {
|
|
380 |
fidOk = true;
|
|
381 |
fid = fidIt->second;
|
|
382 |
}
|
|
383 |
|
|
384 |
//read FILTER
|
|
385 |
bool filterOk = false;
|
|
386 |
QDomDocument filter;
|
|
387 |
std::map<QString, QString>::const_iterator filterIt = mParameterMap.find( "FILTER" );
|
|
388 |
if ( filterIt != mParameterMap.end() ) {
|
|
389 |
try {
|
|
390 |
QString errorMsg;
|
|
391 |
if ( !filter.setContent( filterIt->second, true, &errorMsg ) )
|
|
392 |
{
|
|
393 |
QgsMSDebugMsg( "soap request parse error" );
|
|
394 |
QgsMSDebugMsg( "error message: " + errorMsg );
|
|
395 |
QgsMSDebugMsg( "the xml string was:" );
|
|
396 |
QgsMSDebugMsg( filterIt->second );
|
|
397 |
}
|
|
398 |
else
|
|
399 |
{
|
|
400 |
filterOk = true;
|
|
401 |
}
|
|
402 |
} catch(QgsMapServiceException& e ) {
|
|
403 |
filterOk = false;
|
|
404 |
}
|
|
405 |
}
|
|
406 |
|
|
407 |
//read BBOX
|
|
408 |
bool conversionSuccess;
|
|
409 |
double minx, miny, maxx, maxy;
|
|
410 |
bool bboxOk = false;
|
|
411 |
std::map<QString, QString>::const_iterator bbIt = mParameterMap.find( "BBOX" );
|
|
412 |
if ( bbIt == mParameterMap.end() )
|
|
413 |
{
|
|
414 |
minx = 0; miny = 0; maxx = 0; maxy = 0;
|
|
415 |
}
|
|
416 |
else
|
|
417 |
{
|
|
418 |
bboxOk = true;
|
|
419 |
QString bbString = bbIt->second;
|
|
420 |
minx = bbString.section( ",", 0, 0 ).toDouble( &conversionSuccess );
|
|
421 |
if ( !conversionSuccess ) {bboxOk = false;}
|
|
422 |
miny = bbString.section( ",", 1, 1 ).toDouble( &conversionSuccess );
|
|
423 |
if ( !conversionSuccess ) {bboxOk = false;}
|
|
424 |
maxx = bbString.section( ",", 2, 2 ).toDouble( &conversionSuccess );
|
|
425 |
if ( !conversionSuccess ) {bboxOk = false;}
|
|
426 |
maxy = bbString.section( ",", 3, 3 ).toDouble( &conversionSuccess );
|
|
427 |
if ( !conversionSuccess ) {bboxOk = false;}
|
|
428 |
}
|
|
429 |
|
|
430 |
QList<QgsFeature> featureList;
|
|
431 |
if ( fidOk )
|
|
432 |
{
|
|
433 |
provider->featureAtId( fid.toInt(), feature, true, provider->attributeIndexes() );
|
|
434 |
featureList.append(feature);
|
|
435 |
}
|
|
436 |
else if ( filterOk )
|
|
437 |
{
|
|
438 |
provider->select( provider->attributeIndexes(), searchRect, true, true );
|
|
439 |
try {
|
|
440 |
QgsFilter* mFilter = QgsFilter::createFilterFromXml( filter.firstChild().toElement().firstChild().toElement(), layer );
|
|
441 |
while ( provider->nextFeature( feature ) )
|
|
442 |
{
|
|
443 |
if ( mFilter )
|
|
444 |
{
|
|
445 |
if ( mFilter->evaluate( feature ) )
|
|
446 |
{
|
|
447 |
featureList.append(feature);
|
|
448 |
}
|
|
449 |
}
|
|
450 |
else
|
|
451 |
{
|
|
452 |
featureList.append(feature);
|
|
453 |
}
|
|
454 |
}
|
|
455 |
delete mFilter;
|
|
456 |
} catch(QgsMapServiceException& e ) {
|
|
457 |
while ( provider->nextFeature( feature ) )
|
|
458 |
{
|
|
459 |
featureList.append(feature);
|
|
460 |
}
|
|
461 |
}
|
|
462 |
}
|
|
463 |
else
|
|
464 |
{
|
|
465 |
if ( bboxOk )
|
|
466 |
searchRect.set( minx, miny, maxx, maxy );
|
|
467 |
provider->select( provider->attributeIndexes(), searchRect, true, true );
|
|
468 |
while ( provider->nextFeature( feature ) )
|
|
469 |
{
|
|
470 |
featureList.append(feature);
|
|
471 |
}
|
|
472 |
}
|
|
473 |
QList<QgsFeature>::const_iterator featureIt = featureList.constBegin();
|
|
474 |
|
|
475 |
if ( format == "GeoJSON" )
|
|
476 |
{
|
|
477 |
int featureCounter = 0;
|
|
478 |
|
|
479 |
QString fcString;
|
|
480 |
fcString.append("{\"type\": \"FeatureCollection\",\n");
|
|
481 |
fcString.append(" \"features\": [\n");
|
|
482 |
for ( ; featureIt != featureList.constEnd(); ++featureIt )
|
|
483 |
{
|
|
484 |
feature = *featureIt;
|
|
485 |
if (featureCounter == 0)
|
|
486 |
fcString.append(" {\"type\": \"Feature\",\n");
|
|
487 |
else
|
|
488 |
fcString.append(" ,{\"type\": \"Feature\",\n");
|
|
489 |
|
|
490 |
fcString.append(" \"id\": ");
|
|
491 |
fcString.append( QString::number( feature.id() ) );
|
|
492 |
fcString.append(",\n");
|
|
493 |
|
|
494 |
QgsGeometry* geom = feature.geometry();
|
|
495 |
if ( geom )
|
|
496 |
{
|
|
497 |
fcString.append(" \"geometry\": ");
|
|
498 |
fcString.append(geom->exportToGeoJSON());
|
|
499 |
fcString.append(",\n");
|
|
500 |
}
|
|
501 |
|
|
502 |
fcString.append(" \"properties\": {\n");
|
|
503 |
|
|
504 |
//read all attribute values from the feature
|
|
505 |
featureAttributes = feature.attributeMap();
|
|
506 |
int attributeCounter = 0;
|
|
507 |
for ( QgsAttributeMap::const_iterator it = featureAttributes.begin(); it != featureAttributes.end(); ++it )
|
|
508 |
{
|
|
509 |
|
|
510 |
QString attributeName = fields[it.key()].name();
|
|
511 |
//skip attribute if it has edit type 'hidden'
|
|
512 |
if ( layerHiddenAttributes.contains( attributeName ) )
|
|
513 |
{
|
|
514 |
continue;
|
|
515 |
}
|
|
516 |
|
|
517 |
//check if the attribute name should be replaced with an alias
|
|
518 |
QMap<int, QString>::const_iterator aliasIt = layerAliasInfo.find( it.key() );
|
|
519 |
if ( aliasIt != layerAliasInfo.constEnd() )
|
|
520 |
{
|
|
521 |
attributeName = aliasIt.value();
|
|
522 |
}
|
|
523 |
|
|
524 |
if (attributeCounter == 0)
|
|
525 |
fcString.append(" \"");
|
|
526 |
else
|
|
527 |
fcString.append(" ,\"");
|
|
528 |
fcString.append(attributeName);
|
|
529 |
fcString.append("\": ");
|
|
530 |
if (it->type() == 6 || it->type() == 2)
|
|
531 |
{
|
|
532 |
fcString.append( it->toString());
|
|
533 |
}
|
|
534 |
else
|
|
535 |
{
|
|
536 |
fcString.append("\"");
|
|
537 |
fcString.append( it->toString().replace( QString( "\"" ), QString( "\\\"" ) ) );
|
|
538 |
fcString.append("\"");
|
|
539 |
}
|
|
540 |
fcString.append("\n");
|
|
541 |
++attributeCounter;
|
|
542 |
}
|
|
543 |
|
|
544 |
fcString.append(" }\n");
|
|
545 |
|
|
546 |
fcString.append(" }");
|
|
547 |
fcString.append("\n");
|
|
548 |
|
|
549 |
++featureCounter;
|
|
550 |
}
|
|
551 |
fcString.append(" ]\n");
|
|
552 |
fcString.append("}");
|
|
553 |
|
|
554 |
result = fcString.toUtf8();
|
|
555 |
}
|
|
556 |
else
|
|
557 |
{
|
|
558 |
QDomDocument gmlDoc;
|
|
559 |
//wfs:FeatureCollection
|
|
560 |
QDomElement fcElement = gmlDoc.createElement( "wfs:FeatureCollection"/*wfs:FeatureCollection*/ );
|
|
561 |
fcElement.setAttribute( "xmlns", "http://www.opengis.net/wfs" );
|
|
562 |
fcElement.setAttribute( "xmlns:wfs", "http://www.opengis.net/wfs" );
|
|
563 |
fcElement.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
|
|
564 |
fcElement.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" );
|
|
565 |
fcElement.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
|
|
566 |
fcElement.setAttribute( "xmlns:gml", "http://www.opengis.net/gml" );
|
|
567 |
fcElement.setAttribute( "xmlns:ows", "http://www.opengis.net/ows" );
|
|
568 |
fcElement.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
|
|
569 |
fcElement.setAttribute( "xmlns:qgs", "http://www.qgis.org/gml" );
|
|
570 |
gmlDoc.appendChild( fcElement );
|
|
571 |
|
|
572 |
for ( ; featureIt != featureList.constEnd(); ++featureIt )
|
|
573 |
{
|
|
574 |
feature = *featureIt;
|
|
575 |
//gml:FeatureMember
|
|
576 |
QDomElement featureElement = gmlDoc.createElement( "gml:featureMember"/*wfs:FeatureMember*/ );
|
|
577 |
fcElement.appendChild(featureElement);
|
|
578 |
|
|
579 |
//qgs:%TYPENAME%
|
|
580 |
QDomElement typeNameElement = gmlDoc.createElement( "qgs:"+typeName.replace( QString(" "), QString("_") )/*qgs:%TYPENAME%*/ );
|
|
581 |
typeNameElement.setAttribute( "fid", QString::number( feature.id() ) );
|
|
582 |
featureElement.appendChild(typeNameElement);
|
|
583 |
|
|
584 |
//add geometry column (as gml)
|
|
585 |
QDomElement geomElem = gmlDoc.createElement( "qgs:geometry" );
|
|
586 |
QDomElement gmlElem = createGeometryElem( feature.geometry(), gmlDoc );
|
|
587 |
if ( !gmlElem.isNull() )
|
|
588 |
{
|
|
589 |
QgsCoordinateReferenceSystem layerCrs = layer->crs();
|
|
590 |
if ( layerCrs.isValid() )
|
|
591 |
{
|
|
592 |
gmlElem.setAttribute( "srsName", layerCrs.authid() );
|
|
593 |
}
|
|
594 |
geomElem.appendChild( gmlElem );
|
|
595 |
typeNameElement.appendChild( geomElem );
|
|
596 |
}
|
|
597 |
|
|
598 |
//read all attribute values from the feature
|
|
599 |
featureAttributes = feature.attributeMap();
|
|
600 |
for ( QgsAttributeMap::const_iterator it = featureAttributes.begin(); it != featureAttributes.end(); ++it )
|
|
601 |
{
|
|
602 |
|
|
603 |
QString attributeName = fields[it.key()].name();
|
|
604 |
//skip attribute if it has edit type 'hidden'
|
|
605 |
if ( layerHiddenAttributes.contains( attributeName ) )
|
|
606 |
{
|
|
607 |
continue;
|
|
608 |
}
|
|
609 |
|
|
610 |
//check if the attribute name should be replaced with an alias
|
|
611 |
QMap<int, QString>::const_iterator aliasIt = layerAliasInfo.find( it.key() );
|
|
612 |
if ( aliasIt != layerAliasInfo.constEnd() )
|
|
613 |
{
|
|
614 |
attributeName = aliasIt.value();
|
|
615 |
}
|
|
616 |
|
|
617 |
QDomElement fieldElem = gmlDoc.createElement( "qgs:"+attributeName );
|
|
618 |
QDomText fieldText = gmlDoc.createTextNode( it->toString() );
|
|
619 |
fieldElem.appendChild( fieldText );
|
|
620 |
typeNameElement.appendChild( fieldElem );
|
|
621 |
}
|
|
622 |
}
|
|
623 |
|
|
624 |
result = gmlDoc.toByteArray();
|
|
625 |
}
|
|
626 |
|
|
627 |
}
|
|
628 |
else
|
|
629 |
{
|
|
630 |
return 2;
|
|
631 |
}
|
|
632 |
return 0;
|
|
633 |
}
|
|
634 |
|
|
635 |
QDomElement QgsWFSServer::createGeometryElem( QgsGeometry* geom, QDomDocument& doc ) /*const*/
|
|
636 |
{
|
|
637 |
if ( !geom )
|
|
638 |
{
|
|
639 |
return QDomElement();
|
|
640 |
}
|
|
641 |
|
|
642 |
|
|
643 |
QDomElement geomElement;
|
|
644 |
QString geomTypeName;
|
|
645 |
QGis::WkbType wkbType = geom->wkbType();
|
|
646 |
switch ( wkbType )
|
|
647 |
{
|
|
648 |
case QGis::WKBPoint:
|
|
649 |
case QGis::WKBPoint25D:
|
|
650 |
geomElement = createPointElem( geom, doc );
|
|
651 |
break;
|
|
652 |
case QGis::WKBMultiPoint:
|
|
653 |
case QGis::WKBMultiPoint25D:
|
|
654 |
geomElement = createMultiPointElem( geom, doc );
|
|
655 |
break;
|
|
656 |
case QGis::WKBLineString:
|
|
657 |
case QGis::WKBLineString25D:
|
|
658 |
geomElement = createLineStringElem( geom, doc );
|
|
659 |
break;
|
|
660 |
case QGis::WKBMultiLineString:
|
|
661 |
case QGis::WKBMultiLineString25D:
|
|
662 |
geomElement = createMultiLineStringElem( geom, doc );
|
|
663 |
break;
|
|
664 |
case QGis::WKBPolygon:
|
|
665 |
case QGis::WKBPolygon25D:
|
|
666 |
geomElement = createPolygonElem( geom, doc );
|
|
667 |
break;
|
|
668 |
case QGis::WKBMultiPolygon:
|
|
669 |
case QGis::WKBMultiPolygon25D:
|
|
670 |
geomElement = createMultiPolygonElem( geom, doc );
|
|
671 |
break;
|
|
672 |
default:
|
|
673 |
return QDomElement();
|
|
674 |
}
|
|
675 |
return geomElement;
|
|
676 |
}
|
|
677 |
|
|
678 |
QDomElement QgsWFSServer::createLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const
|
|
679 |
{
|
|
680 |
if ( !geom )
|
|
681 |
{
|
|
682 |
return QDomElement();
|
|
683 |
}
|
|
684 |
|
|
685 |
QDomElement lineStringElem = doc.createElement( "gml:LineString" );
|
|
686 |
QDomElement coordElem = createCoordinateElem( geom->asPolyline(), doc );
|
|
687 |
lineStringElem.appendChild( coordElem );
|
|
688 |
return lineStringElem;
|
|
689 |
}
|
|
690 |
|
|
691 |
QDomElement QgsWFSServer::createMultiLineStringElem( QgsGeometry* geom, QDomDocument& doc ) const
|
|
692 |
{
|
|
693 |
if ( !geom )
|
|
694 |
{
|
|
695 |
return QDomElement();
|
|
696 |
}
|
|
697 |
|
|
698 |
QDomElement multiLineStringElem = doc.createElement( "gml:MultiLineString" );
|
|
699 |
QgsMultiPolyline multiline = geom->asMultiPolyline();
|
|
700 |
|
|
701 |
QgsMultiPolyline::const_iterator multiLineIt = multiline.constBegin();
|
|
702 |
for ( ; multiLineIt != multiline.constEnd(); ++multiLineIt )
|
|
703 |
{
|
|
704 |
QgsGeometry* lineGeom = QgsGeometry::fromPolyline( *multiLineIt );
|
|
705 |
if ( lineGeom )
|
|
706 |
{
|
|
707 |
QDomElement lineStringMemberElem = doc.createElement( "gml:lineStringMember" );
|
|
708 |
QDomElement lineElem = createLineStringElem( lineGeom, doc );
|
|
709 |
lineStringMemberElem.appendChild( lineElem );
|
|
710 |
multiLineStringElem.appendChild( lineStringMemberElem );
|
|
711 |
}
|
|
712 |
delete lineGeom;
|
|
713 |
}
|
|
714 |
|
|
715 |
return multiLineStringElem;
|
|
716 |
}
|
|
717 |
|
|
718 |
QDomElement QgsWFSServer::createPointElem( QgsGeometry* geom, QDomDocument& doc ) const
|
|
719 |
{
|
|
720 |
if ( !geom )
|
|
721 |
{
|
|
722 |
return QDomElement();
|
|
723 |
}
|
|
724 |
|
|
725 |
QDomElement pointElem = doc.createElement( "gml:Point" );
|
|
726 |
QgsPoint p = geom->asPoint();
|
|
727 |
QVector<QgsPoint> v;
|
|
728 |
v.append( p );
|
|
729 |
QDomElement coordElem = createCoordinateElem( v, doc );
|
|
730 |
pointElem.appendChild( coordElem );
|
|
731 |
return pointElem;
|
|
732 |
}
|
|
733 |
|
|
734 |
QDomElement QgsWFSServer::createMultiPointElem( QgsGeometry* geom, QDomDocument& doc ) const
|
|
735 |
{
|
|
736 |
if ( !geom )
|
|
737 |
{
|
|
738 |
return QDomElement();
|
|
739 |
}
|
|
740 |
|
|
741 |
QDomElement multiPointElem = doc.createElement( "gml:MultiPoint" );
|
|
742 |
QgsMultiPoint multiPoint = geom->asMultiPoint();
|
|
743 |
|
|
744 |
QgsMultiPoint::const_iterator multiPointIt = multiPoint.constBegin();
|
|
745 |
for ( ; multiPointIt != multiPoint.constEnd(); ++multiPointIt )
|
|
746 |
{
|
|
747 |
QgsGeometry* pointGeom = QgsGeometry::fromPoint( *multiPointIt );
|
|
748 |
if ( pointGeom )
|
|
749 |
{
|
|
750 |
QDomElement multiPointMemberElem = doc.createElement( "gml:pointMember" );
|
|
751 |
QDomElement pointElem = createPointElem( pointGeom, doc );
|
|
752 |
multiPointMemberElem.appendChild( pointElem );
|
|
753 |
multiPointElem.appendChild( multiPointMemberElem );
|
|
754 |
}
|
|
755 |
}
|
|
756 |
return multiPointElem;
|
|
757 |
}
|
|
758 |
|
|
759 |
QDomElement QgsWFSServer::createPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const
|
|
760 |
{
|
|
761 |
if ( !geom )
|
|
762 |
{
|
|
763 |
return QDomElement();
|
|
764 |
}
|
|
765 |
|
|
766 |
QDomElement polygonElem = doc.createElement( "gml:Polygon" );
|
|
767 |
QgsPolygon poly = geom->asPolygon();
|
|
768 |
for ( int i = 0; i < poly.size(); ++i )
|
|
769 |
{
|
|
770 |
QString boundaryName;
|
|
771 |
if ( i == 0 )
|
|
772 |
{
|
|
773 |
boundaryName = "outerBoundaryIs";
|
|
774 |
}
|
|
775 |
else
|
|
776 |
{
|
|
777 |
boundaryName = "innerBoundaryIs";
|
|
778 |
}
|
|
779 |
QDomElement boundaryElem = doc.createElementNS( "http://www.opengis.net/gml", boundaryName );
|
|
780 |
QDomElement ringElem = doc.createElement( "gml:LinearRing" );
|
|
781 |
QDomElement coordElem = createCoordinateElem( poly.at( i ), doc );
|
|
782 |
ringElem.appendChild( coordElem );
|
|
783 |
boundaryElem.appendChild( ringElem );
|
|
784 |
polygonElem.appendChild( boundaryElem );
|
|
785 |
}
|
|
786 |
return polygonElem;
|
|
787 |
}
|
|
788 |
|
|
789 |
QDomElement QgsWFSServer::createMultiPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const
|
|
790 |
{
|
|
791 |
if ( !geom )
|
|
792 |
{
|
|
793 |
return QDomElement();
|
|
794 |
}
|
|
795 |
QDomElement multiPolygonElem = doc.createElement( "gml:MultiPolygon" );
|
|
796 |
QgsMultiPolygon multipoly = geom->asMultiPolygon();
|
|
797 |
|
|
798 |
QgsMultiPolygon::const_iterator polyIt = multipoly.constBegin();
|
|
799 |
for ( ; polyIt != multipoly.constEnd(); ++polyIt )
|
|
800 |
{
|
|
801 |
QgsGeometry* polygonGeom = QgsGeometry::fromPolygon( *polyIt );
|
|
802 |
if ( polygonGeom )
|
|
803 |
{
|
|
804 |
QDomElement polygonMemberElem = doc.createElement( "gml:polygonMember" );
|
|
805 |
QDomElement polygonElem = createPolygonElem( polygonGeom, doc );
|
|
806 |
delete polygonGeom;
|
|
807 |
polygonMemberElem.appendChild( polygonElem );
|
|
808 |
multiPolygonElem.appendChild( polygonMemberElem );
|
|
809 |
}
|
|
810 |
}
|
|
811 |
return multiPolygonElem;
|
|
812 |
}
|
|
813 |
|
|
814 |
QDomElement QgsWFSServer::createCoordinateElem( const QVector<QgsPoint> points, QDomDocument& doc ) const
|
|
815 |
{
|
|
816 |
QDomElement coordElem = doc.createElement( "gml:coordinates" );
|
|
817 |
coordElem.setAttribute( "cs", "," );
|
|
818 |
coordElem.setAttribute( "ts", " " );
|
|
819 |
|
|
820 |
//precision 4 for meters / feet, precision 8 for degrees
|
|
821 |
int precision = 6;
|
|
822 |
/*
|
|
823 |
if ( mSourceCRS.mapUnits() == QGis::Meters
|
|
824 |
|| mSourceCRS.mapUnits() == QGis::Feet )
|
|
825 |
{
|
|
826 |
precision = 4;
|
|
827 |
}
|
|
828 |
*/
|
|
829 |
|
|
830 |
QString coordString;
|
|
831 |
QVector<QgsPoint>::const_iterator pointIt = points.constBegin();
|
|
832 |
for ( ; pointIt != points.constEnd(); ++pointIt )
|
|
833 |
{
|
|
834 |
if ( pointIt != points.constBegin() )
|
|
835 |
{
|
|
836 |
coordString += " ";
|
|
837 |
}
|
|
838 |
coordString += QString::number( pointIt->x(), 'f', precision );
|