1 : /******************************************************************************
2 : * $Id: ogrwfslayer.cpp 25760 2013-03-15 21:53:45Z rouault $
3 : *
4 : * Project: WFS Translator
5 : * Purpose: Implements OGRWFSLayer class.
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Even Rouault <even dot rouault at mines dash paris dot org>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_port.h"
31 : #include "ogr_wfs.h"
32 : #include "ogr_api.h"
33 : #include "cpl_minixml.h"
34 : #include "cpl_http.h"
35 : #include "parsexsd.h"
36 :
37 : CPL_CVSID("$Id: ogrwfslayer.cpp 25760 2013-03-15 21:53:45Z rouault $");
38 :
39 :
40 : /************************************************************************/
41 : /* OGRWFSRecursiveUnlink() */
42 : /************************************************************************/
43 :
44 208 : static void OGRWFSRecursiveUnlink( const char *pszName )
45 :
46 : {
47 : char **papszFileList;
48 : int i;
49 :
50 208 : papszFileList = CPLReadDir( pszName );
51 :
52 277 : for( i = 0; papszFileList != NULL && papszFileList[i] != NULL; i++ )
53 : {
54 : VSIStatBufL sStatBuf;
55 :
56 69 : if( EQUAL(papszFileList[i],".") || EQUAL(papszFileList[i],"..") )
57 0 : continue;
58 :
59 : CPLString osFullFilename =
60 69 : CPLFormFilename( pszName, papszFileList[i], NULL );
61 :
62 69 : VSIStatL( osFullFilename, &sStatBuf );
63 :
64 69 : if( VSI_ISREG( sStatBuf.st_mode ) )
65 : {
66 69 : VSIUnlink( osFullFilename );
67 : }
68 0 : else if( VSI_ISDIR( sStatBuf.st_mode ) )
69 : {
70 0 : OGRWFSRecursiveUnlink( osFullFilename );
71 : }
72 : }
73 :
74 208 : CSLDestroy( papszFileList );
75 :
76 208 : VSIRmdir( pszName );
77 208 : }
78 :
79 : /************************************************************************/
80 : /* OGRWFSLayer() */
81 : /************************************************************************/
82 :
83 208 : OGRWFSLayer::OGRWFSLayer( OGRWFSDataSource* poDS,
84 : OGRSpatialReference* poSRS,
85 : int bAxisOrderAlreadyInverted,
86 : const char* pszBaseURL,
87 : const char* pszName,
88 : const char* pszNS,
89 208 : const char* pszNSVal )
90 :
91 : {
92 208 : this->poDS = poDS;
93 208 : this->poSRS = poSRS;
94 208 : this->bAxisOrderAlreadyInverted = bAxisOrderAlreadyInverted;
95 208 : this->pszBaseURL = CPLStrdup(pszBaseURL);
96 208 : this->pszName = CPLStrdup(pszName);
97 208 : this->pszNS = pszNS ? CPLStrdup(pszNS) : NULL;
98 208 : this->pszNSVal = pszNSVal ? CPLStrdup(pszNSVal) : NULL;
99 :
100 208 : poFeatureDefn = NULL;
101 208 : poGMLFeatureClass = NULL;
102 208 : bGotApproximateLayerDefn = FALSE;
103 :
104 208 : bStreamingDS = FALSE;
105 208 : poBaseDS = NULL;
106 208 : poBaseLayer = NULL;
107 208 : bReloadNeeded = FALSE;
108 208 : bHasFetched = FALSE;
109 208 : eGeomType = wkbUnknown;
110 208 : nFeatures = -1;
111 208 : bCountFeaturesInGetNextFeature = FALSE;
112 :
113 208 : dfMinX = dfMinY = dfMaxX = dfMaxY = 0;
114 208 : bHasExtents = FALSE;
115 208 : poFetchedFilterGeom = NULL;
116 :
117 208 : nExpectedInserts = 0;
118 208 : bInTransaction = FALSE;
119 208 : bUseFeatureIdAtLayerLevel = FALSE;
120 :
121 208 : bPagingActive = FALSE;
122 208 : nPagingStartIndex = 0;
123 208 : nFeatureRead = 0;
124 208 : nFeatureCountRequested = 0;
125 :
126 208 : pszRequiredOutputFormat = NULL;
127 :
128 208 : bAscFlag = TRUE;
129 208 : }
130 :
131 : /************************************************************************/
132 : /* Clone() */
133 : /************************************************************************/
134 :
135 1 : OGRWFSLayer* OGRWFSLayer::Clone()
136 : {
137 : OGRWFSLayer* poDupLayer = new OGRWFSLayer(poDS, poSRS, bAxisOrderAlreadyInverted,
138 1 : pszBaseURL, pszName, pszNS, pszNSVal);
139 1 : if (poSRS)
140 1 : poSRS->Reference();
141 1 : poDupLayer->poFeatureDefn = GetLayerDefn()->Clone();
142 1 : poDupLayer->poFeatureDefn->Reference();
143 1 : poDupLayer->bGotApproximateLayerDefn = bGotApproximateLayerDefn;
144 1 : poDupLayer->eGeomType = poDupLayer->poFeatureDefn->GetGeomType();
145 1 : poDupLayer->pszRequiredOutputFormat = pszRequiredOutputFormat ? CPLStrdup(pszRequiredOutputFormat) : NULL;
146 1 : poDupLayer->bAscFlag = bAscFlag;
147 :
148 : /* Copy existing schema file if already found */
149 1 : CPLString osSrcFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
150 1 : CPLString osTargetFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", poDupLayer);
151 1 : CPLCopyFile(osTargetFileName, osSrcFileName);
152 :
153 1 : return poDupLayer;
154 : }
155 :
156 : /************************************************************************/
157 : /* ~OGRWFSLayer() */
158 : /************************************************************************/
159 :
160 208 : OGRWFSLayer::~OGRWFSLayer()
161 :
162 : {
163 208 : if (bInTransaction)
164 0 : CommitTransaction();
165 :
166 208 : if( poSRS != NULL )
167 208 : poSRS->Release();
168 :
169 208 : if (poFeatureDefn != NULL)
170 65 : poFeatureDefn->Release();
171 208 : delete poGMLFeatureClass;
172 :
173 208 : CPLFree(pszBaseURL);
174 208 : CPLFree(pszName);
175 208 : CPLFree(pszNS);
176 208 : CPLFree(pszNSVal);
177 :
178 208 : OGRDataSource::DestroyDataSource(poBaseDS);
179 :
180 208 : delete poFetchedFilterGeom;
181 :
182 208 : CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this);
183 208 : OGRWFSRecursiveUnlink(osTmpDirName);
184 :
185 208 : CPLFree(pszRequiredOutputFormat);
186 208 : }
187 :
188 : /************************************************************************/
189 : /* GetDescribeFeatureTypeURL() */
190 : /************************************************************************/
191 :
192 8 : CPLString OGRWFSLayer::GetDescribeFeatureTypeURL(int bWithNS)
193 : {
194 8 : CPLString osURL(pszBaseURL);
195 8 : osURL = CPLURLAddKVP(osURL, "SERVICE", "WFS");
196 8 : osURL = CPLURLAddKVP(osURL, "VERSION", poDS->GetVersion());
197 8 : osURL = CPLURLAddKVP(osURL, "REQUEST", "DescribeFeatureType");
198 8 : osURL = CPLURLAddKVP(osURL, "TYPENAME", WFS_EscapeURL(pszName));
199 8 : osURL = CPLURLAddKVP(osURL, "PROPERTYNAME", NULL);
200 8 : osURL = CPLURLAddKVP(osURL, "MAXFEATURES", NULL);
201 8 : osURL = CPLURLAddKVP(osURL, "COUNT", NULL);
202 8 : osURL = CPLURLAddKVP(osURL, "FILTER", NULL);
203 8 : osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", pszRequiredOutputFormat ? WFS_EscapeURL(pszRequiredOutputFormat).c_str() : NULL);
204 :
205 8 : if (pszNS && poDS->GetNeedNAMESPACE())
206 : {
207 : /* Older Deegree version require NAMESPACE (e.g. http://www.nokis.org/deegree2/ogcwebservice) */
208 : /* This has been now corrected */
209 0 : CPLString osValue("xmlns(");
210 0 : osValue += pszNS;
211 0 : osValue += "=";
212 0 : osValue += pszNSVal;
213 0 : osValue += ")";
214 0 : osURL = CPLURLAddKVP(osURL, "NAMESPACE", WFS_EscapeURL(osValue));
215 : }
216 :
217 0 : return osURL;
218 : }
219 :
220 : /************************************************************************/
221 : /* DescribeFeatureType() */
222 : /************************************************************************/
223 :
224 7 : OGRFeatureDefn* OGRWFSLayer::DescribeFeatureType()
225 : {
226 7 : CPLString osURL = GetDescribeFeatureTypeURL(TRUE);
227 :
228 7 : CPLDebug("WFS", "%s", osURL.c_str());
229 :
230 7 : CPLHTTPResult* psResult = poDS->HTTPFetch( osURL, NULL);
231 7 : if (psResult == NULL)
232 : {
233 0 : return NULL;
234 : }
235 :
236 7 : if (strstr((const char*)psResult->pabyData, "<ServiceExceptionReport") != NULL)
237 : {
238 0 : if (poDS->IsOldDeegree((const char*)psResult->pabyData))
239 : {
240 0 : CPLHTTPDestroyResult(psResult);
241 0 : return DescribeFeatureType();
242 : }
243 : CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
244 0 : psResult->pabyData);
245 0 : CPLHTTPDestroyResult(psResult);
246 0 : return NULL;
247 : }
248 :
249 7 : CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
250 7 : if (psXML == NULL)
251 : {
252 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
253 0 : psResult->pabyData);
254 0 : CPLHTTPDestroyResult(psResult);
255 0 : return NULL;
256 : }
257 7 : CPLHTTPDestroyResult(psResult);
258 :
259 7 : CPLXMLNode* psSchema = WFSFindNode(psXML, "schema");
260 7 : if (psSchema == NULL)
261 : {
262 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <Schema>");
263 0 : CPLDestroyXMLNode( psXML );
264 :
265 0 : return NULL;
266 : }
267 :
268 7 : OGRFeatureDefn* poFDefn = ParseSchema(psSchema);
269 7 : if (poFDefn)
270 7 : poDS->SaveLayerSchema(pszName, psSchema);
271 :
272 7 : CPLDestroyXMLNode( psXML );
273 7 : return poFDefn;
274 : }
275 :
276 : /************************************************************************/
277 : /* ParseSchema() */
278 : /************************************************************************/
279 :
280 64 : OGRFeatureDefn* OGRWFSLayer::ParseSchema(CPLXMLNode* psSchema)
281 : {
282 64 : osTargetNamespace = CPLGetXMLValue(psSchema, "targetNamespace", "");
283 :
284 64 : CPLString osTmpFileName;
285 :
286 128 : osTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
287 64 : CPLSerializeXMLTreeToFile(psSchema, osTmpFileName);
288 :
289 64 : std::vector<GMLFeatureClass*> aosClasses;
290 64 : int bHaveSchema = GMLParseXSD( osTmpFileName, aosClasses );
291 :
292 64 : if (bHaveSchema && aosClasses.size() == 1)
293 : {
294 : //CPLDebug("WFS", "Creating %s for %s", osTmpFileName.c_str(), GetName());
295 64 : return BuildLayerDefnFromFeatureClass(aosClasses[0]);
296 : }
297 0 : else if (bHaveSchema)
298 : {
299 0 : std::vector<GMLFeatureClass*>::const_iterator iter = aosClasses.begin();
300 0 : std::vector<GMLFeatureClass*>::const_iterator eiter = aosClasses.end();
301 0 : while (iter != eiter)
302 : {
303 0 : GMLFeatureClass* poClass = *iter;
304 0 : iter ++;
305 0 : delete poClass;
306 : }
307 : }
308 :
309 0 : VSIUnlink(osTmpFileName);
310 :
311 0 : return NULL;
312 : }
313 : /************************************************************************/
314 : /* BuildLayerDefnFromFeatureClass() */
315 : /************************************************************************/
316 :
317 64 : OGRFeatureDefn* OGRWFSLayer::BuildLayerDefnFromFeatureClass(GMLFeatureClass* poClass)
318 : {
319 64 : this->poGMLFeatureClass = poClass;
320 :
321 64 : OGRFeatureDefn* poFDefn = new OGRFeatureDefn( pszName );
322 64 : poFDefn->SetGeomType( (OGRwkbGeometryType)poGMLFeatureClass->GetGeometryType() );
323 :
324 : /* -------------------------------------------------------------------- */
325 : /* Added attributes (properties). */
326 : /* -------------------------------------------------------------------- */
327 64 : OGRFieldDefn oField( "gml_id", OFTString );
328 64 : poFDefn->AddFieldDefn( &oField );
329 :
330 346 : for( int iField = 0; iField < poGMLFeatureClass->GetPropertyCount(); iField++ )
331 : {
332 282 : GMLPropertyDefn *poProperty = poGMLFeatureClass->GetProperty( iField );
333 : OGRFieldType eFType;
334 :
335 282 : if( poProperty->GetType() == GMLPT_Untyped )
336 0 : eFType = OFTString;
337 282 : else if( poProperty->GetType() == GMLPT_String )
338 110 : eFType = OFTString;
339 172 : else if( poProperty->GetType() == GMLPT_Integer )
340 32 : eFType = OFTInteger;
341 140 : else if( poProperty->GetType() == GMLPT_Real )
342 140 : eFType = OFTReal;
343 0 : else if( poProperty->GetType() == GMLPT_StringList )
344 0 : eFType = OFTStringList;
345 0 : else if( poProperty->GetType() == GMLPT_IntegerList )
346 0 : eFType = OFTIntegerList;
347 0 : else if( poProperty->GetType() == GMLPT_RealList )
348 0 : eFType = OFTRealList;
349 : else
350 0 : eFType = OFTString;
351 :
352 282 : OGRFieldDefn oField( poProperty->GetName(), eFType );
353 282 : if ( EQUALN(oField.GetNameRef(), "ogr:", 4) )
354 0 : oField.SetName(poProperty->GetName()+4);
355 282 : if( poProperty->GetWidth() > 0 )
356 0 : oField.SetWidth( poProperty->GetWidth() );
357 282 : if( poProperty->GetPrecision() > 0 )
358 0 : oField.SetPrecision( poProperty->GetPrecision() );
359 :
360 282 : poFDefn->AddFieldDefn( &oField );
361 : }
362 :
363 64 : const char* pszGeometryColumnName = poGMLFeatureClass->GetGeometryElement();
364 64 : if (pszGeometryColumnName)
365 64 : osGeometryColumnName = pszGeometryColumnName;
366 :
367 64 : return poFDefn;
368 : }
369 :
370 : /************************************************************************/
371 : /* MakeGetFeatureURL() */
372 : /************************************************************************/
373 :
374 74 : CPLString OGRWFSLayer::MakeGetFeatureURL(int nRequestMaxFeatures, int bRequestHits)
375 : {
376 74 : CPLString osURL(pszBaseURL);
377 74 : osURL = CPLURLAddKVP(osURL, "SERVICE", "WFS");
378 74 : osURL = CPLURLAddKVP(osURL, "VERSION", poDS->GetVersion());
379 74 : osURL = CPLURLAddKVP(osURL, "REQUEST", "GetFeature");
380 74 : osURL = CPLURLAddKVP(osURL, "TYPENAME", WFS_EscapeURL(pszName));
381 74 : if (pszRequiredOutputFormat)
382 0 : osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", WFS_EscapeURL(pszRequiredOutputFormat));
383 :
384 74 : if (poDS->IsPagingAllowed() && !bRequestHits)
385 : {
386 : osURL = CPLURLAddKVP(osURL, "STARTINDEX",
387 : CPLSPrintf("%d", nPagingStartIndex +
388 8 : poDS->GetBaseStartIndex()));
389 8 : nRequestMaxFeatures = poDS->GetPageSize();
390 8 : nFeatureCountRequested = nRequestMaxFeatures;
391 8 : bPagingActive = TRUE;
392 : }
393 :
394 74 : if (nRequestMaxFeatures)
395 : {
396 : osURL = CPLURLAddKVP(osURL,
397 : atoi(poDS->GetVersion()) >= 2 ? "COUNT" : "MAXFEATURES",
398 8 : CPLSPrintf("%d", nRequestMaxFeatures));
399 : }
400 74 : if (pszNS && poDS->GetNeedNAMESPACE())
401 : {
402 : /* Older Deegree version require NAMESPACE (e.g. http://www.nokis.org/deegree2/ogcwebservice) */
403 : /* This has been now corrected */
404 0 : CPLString osValue("xmlns(");
405 0 : osValue += pszNS;
406 0 : osValue += "=";
407 0 : osValue += pszNSVal;
408 0 : osValue += ")";
409 0 : osURL = CPLURLAddKVP(osURL, "NAMESPACE", WFS_EscapeURL(osValue));
410 : }
411 :
412 74 : delete poFetchedFilterGeom;
413 74 : poFetchedFilterGeom = NULL;
414 :
415 74 : CPLString osGeomFilter;
416 :
417 74 : if (m_poFilterGeom != NULL && osGeometryColumnName.size() > 0)
418 : {
419 8 : OGREnvelope oEnvelope;
420 8 : m_poFilterGeom->getEnvelope(&oEnvelope);
421 :
422 8 : poFetchedFilterGeom = m_poFilterGeom->clone();
423 :
424 8 : osGeomFilter = "<BBOX>";
425 8 : if (atoi(poDS->GetVersion()) >= 2)
426 0 : osGeomFilter += "<ValueReference>";
427 : else
428 8 : osGeomFilter += "<PropertyName>";
429 8 : if (pszNS)
430 : {
431 8 : osGeomFilter += pszNS;
432 8 : osGeomFilter += ":";
433 : }
434 8 : osGeomFilter += osGeometryColumnName;
435 8 : if (atoi(poDS->GetVersion()) >= 2)
436 0 : osGeomFilter += "</ValueReference>";
437 : else
438 8 : osGeomFilter += "</PropertyName>";
439 :
440 8 : CPLLocaleC oLocaleEnforcer;
441 :
442 8 : if ( atoi(poDS->GetVersion()) >= 2 )
443 : {
444 0 : osGeomFilter += "<gml:Envelope";
445 :
446 0 : CPLString osSRSName = CPLURLGetValue(pszBaseURL, "SRSNAME");
447 0 : if( osSRSName.size() )
448 : {
449 0 : osGeomFilter += " srsName=\"";
450 0 : osGeomFilter += osSRSName;
451 0 : osGeomFilter += "\"";
452 : }
453 :
454 0 : osGeomFilter += ">";
455 0 : if (bAxisOrderAlreadyInverted)
456 : {
457 : osGeomFilter += CPLSPrintf("<gml:lowerCorner>%.16f %.16f</gml:lowerCorner><gml:upperCorner>%.16f %.16f</gml:upperCorner>",
458 0 : oEnvelope.MinY, oEnvelope.MinX, oEnvelope.MaxY, oEnvelope.MaxX);
459 : }
460 : else
461 : osGeomFilter += CPLSPrintf("<gml:lowerCorner>%.16f %.16f</gml:lowerCorner><gml:upperCorner>%.16f %.16f</gml:upperCorner>",
462 0 : oEnvelope.MinX, oEnvelope.MinY, oEnvelope.MaxX, oEnvelope.MaxY);
463 0 : osGeomFilter += "</gml:Envelope>";
464 : }
465 8 : else if ( poDS->RequiresEnvelopeSpatialFilter() )
466 : {
467 0 : osGeomFilter += "<Envelope xmlns=\"http://www.opengis.net/gml\">";
468 0 : if (bAxisOrderAlreadyInverted)
469 : {
470 : /* We can go here in WFS 1.1 with geographic coordinate systems */
471 : /* that are natively return in lat,long order, but as we have */
472 : /* presented long,lat order to the user, we must switch back */
473 : /* for the server... */
474 : osGeomFilter += CPLSPrintf("<coord><X>%.16f</X><Y>%.16f</Y></coord><coord><X>%.16f</X><Y>%.16f</Y></coord>",
475 0 : oEnvelope.MinY, oEnvelope.MinX, oEnvelope.MaxY, oEnvelope.MaxX);
476 : }
477 : else
478 : osGeomFilter += CPLSPrintf("<coord><X>%.16f</X><Y>%.16f</Y></coord><coord><X>%.16f</X><Y>%.16f</Y></coord>",
479 0 : oEnvelope.MinX, oEnvelope.MinY, oEnvelope.MaxX, oEnvelope.MaxY);
480 0 : osGeomFilter += "</Envelope>";
481 : }
482 : else
483 : {
484 8 : osGeomFilter += "<gml:Box>";
485 8 : osGeomFilter += "<gml:coordinates>";
486 8 : if (bAxisOrderAlreadyInverted)
487 : {
488 : /* We can go here in WFS 1.1 with geographic coordinate systems */
489 : /* that are natively return in lat,long order, but as we have */
490 : /* presented long,lat order to the user, we must switch back */
491 : /* for the server... */
492 0 : osGeomFilter += CPLSPrintf("%.16f,%.16f %.16f,%.16f", oEnvelope.MinY, oEnvelope.MinX, oEnvelope.MaxY, oEnvelope.MaxX);
493 : }
494 : else
495 8 : osGeomFilter += CPLSPrintf("%.16f,%.16f %.16f,%.16f", oEnvelope.MinX, oEnvelope.MinY, oEnvelope.MaxX, oEnvelope.MaxY);
496 8 : osGeomFilter += "</gml:coordinates>";
497 8 : osGeomFilter += "</gml:Box>";
498 : }
499 8 : osGeomFilter += "</BBOX>";
500 : }
501 :
502 74 : if (osGeomFilter.size() != 0 || osWFSWhere.size() != 0)
503 : {
504 30 : CPLString osFilter;
505 30 : if (atoi(poDS->GetVersion()) >= 2)
506 8 : osFilter = "<Filter xmlns=\"http://www.opengis.net/fes/2.0\"";
507 : else
508 22 : osFilter = "<Filter xmlns=\"http://www.opengis.net/ogc\"";
509 30 : if (pszNS)
510 : {
511 25 : osFilter += " xmlns:";
512 25 : osFilter += pszNS;
513 25 : osFilter += "=\"";
514 25 : osFilter += pszNSVal;
515 25 : osFilter += "\"";
516 : }
517 30 : if (atoi(poDS->GetVersion()) >= 2)
518 8 : osFilter += " xmlns:gml=\"http://www.opengis.net/gml/3.2\">";
519 : else
520 22 : osFilter += " xmlns:gml=\"http://www.opengis.net/gml\">";
521 30 : if (osGeomFilter.size() != 0 && osWFSWhere.size() != 0)
522 0 : osFilter += "<And>";
523 30 : osFilter += osWFSWhere;
524 30 : osFilter += osGeomFilter;
525 30 : if (osGeomFilter.size() != 0 && osWFSWhere.size() != 0)
526 0 : osFilter += "</And>";
527 30 : osFilter += "</Filter>";
528 :
529 30 : osURL = CPLURLAddKVP(osURL, "FILTER", WFS_EscapeURL(osFilter));
530 : }
531 :
532 74 : if (bRequestHits)
533 : {
534 8 : osURL = CPLURLAddKVP(osURL, "RESULTTYPE", "hits");
535 : }
536 66 : else if (osFieldToSort.size() != 0)
537 : {
538 2 : CPLString osSortBy(osFieldToSort);
539 2 : if (!bAscFlag)
540 : {
541 2 : if (atoi(poDS->GetVersion()) >= 2)
542 0 : osSortBy += " DESC";
543 : else
544 2 : osSortBy += " D";
545 : }
546 2 : osURL = CPLURLAddKVP(osURL, "SORTBY", WFS_EscapeURL(osSortBy));
547 : }
548 :
549 : /* If no PROPERTYNAME is specified, build one if there are ignored fields */
550 74 : CPLString osPropertyName = CPLURLGetValue(osURL, "PROPERTYNAME");
551 74 : const char* pszPropertyName = osPropertyName.c_str();
552 74 : if (pszPropertyName[0] == 0 && poFeatureDefn != NULL)
553 : {
554 70 : int bHasIgnoredField = FALSE;
555 70 : CPLString osPropertyName;
556 464 : for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
557 : {
558 394 : if (EQUAL(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(), "gml_id"))
559 : {
560 : /* fake field : skip it */
561 : }
562 324 : else if (poFeatureDefn->GetFieldDefn(iField)->IsIgnored())
563 : {
564 8 : bHasIgnoredField = TRUE;
565 : }
566 : else
567 : {
568 316 : if (osPropertyName.size() != 0)
569 249 : osPropertyName += ",";
570 316 : osPropertyName += poFeatureDefn->GetFieldDefn(iField)->GetNameRef();
571 : }
572 : }
573 70 : if (osGeometryColumnName.size() != 0)
574 : {
575 68 : if (poFeatureDefn->IsGeometryIgnored())
576 : {
577 2 : bHasIgnoredField = TRUE;
578 : }
579 : else
580 : {
581 66 : if (osPropertyName.size() != 0)
582 65 : osPropertyName += ",";
583 66 : osPropertyName += osGeometryColumnName;
584 : }
585 : }
586 :
587 70 : if (bHasIgnoredField && osPropertyName.size())
588 : {
589 0 : osPropertyName = "(" + osPropertyName + ")";
590 0 : osURL = CPLURLAddKVP(osURL, "PROPERTYNAME", WFS_EscapeURL(osPropertyName));
591 70 : }
592 : }
593 :
594 74 : return osURL;
595 : }
596 :
597 :
598 : /************************************************************************/
599 : /* OGRWFSFetchContentDispositionFilename() */
600 : /************************************************************************/
601 :
602 6 : const char* OGRWFSFetchContentDispositionFilename(char** papszHeaders)
603 : {
604 6 : char** papszIter = papszHeaders;
605 46 : while(papszIter && *papszIter)
606 : {
607 : /* For multipart, we have in raw format, but without end-of-line characters */
608 35 : if (strncmp(*papszIter, "Content-Disposition: attachment; filename=", 42) == 0)
609 : {
610 0 : return *papszIter + 42;
611 : }
612 : /* For single part, the headers are in KEY=VAL format, but with e-o-l ... */
613 35 : else if (strncmp(*papszIter, "Content-Disposition=attachment; filename=", 41) == 0)
614 : {
615 1 : char* pszVal = (char*)(*papszIter + 41);
616 1 : char* pszEOL = strchr(pszVal, '\r');
617 1 : if (pszEOL) *pszEOL = 0;
618 1 : pszEOL = strchr(pszVal, '\n');
619 1 : if (pszEOL) *pszEOL = 0;
620 1 : return pszVal;
621 : }
622 34 : papszIter ++;
623 : }
624 5 : return NULL;
625 : }
626 :
627 : /************************************************************************/
628 : /* MustRetryIfNonCompliantServer() */
629 : /************************************************************************/
630 :
631 7 : int OGRWFSLayer::MustRetryIfNonCompliantServer(const char* pszServerAnswer)
632 : {
633 7 : int bRetry = FALSE;
634 :
635 : /* Deegree server does not support PropertyIsNotEqualTo */
636 : /* We have to turn it into <Not><PropertyIsEqualTo> */
637 7 : if (osWFSWhere.size() != 0 && poDS->PropertyIsNotEqualToSupported() &&
638 : strstr(pszServerAnswer, "Unknown comparison operation: 'PropertyIsNotEqualTo'") != NULL)
639 : {
640 2 : poDS->SetPropertyIsNotEqualToUnSupported();
641 2 : bRetry = TRUE;
642 : }
643 :
644 : /* Deegree server requires the gml: prefix in GmlObjectId element, but ESRI */
645 : /* doesn't like it at all ! Other servers don't care... */
646 7 : if (osWFSWhere.size() != 0 && !poDS->DoesGmlObjectIdNeedGMLPrefix() &&
647 : strstr(pszServerAnswer, "<GmlObjectId> requires 'gml:id'-attribute!") != NULL)
648 : {
649 0 : poDS->SetGmlObjectIdNeedsGMLPrefix();
650 0 : bRetry = TRUE;
651 : }
652 :
653 : /* GeoServer can return the error 'Only FeatureIds are supported when encoding id filters to SDE' */
654 7 : if (osWFSWhere.size() != 0 && !bUseFeatureIdAtLayerLevel &&
655 : strstr(pszServerAnswer, "Only FeatureIds are supported") != NULL)
656 : {
657 0 : bUseFeatureIdAtLayerLevel = TRUE;
658 0 : bRetry = TRUE;
659 : }
660 :
661 7 : if (bRetry)
662 : {
663 2 : SetAttributeFilter(osSQLWhere);
664 2 : bHasFetched = TRUE;
665 2 : bReloadNeeded = FALSE;
666 : }
667 :
668 7 : return bRetry;
669 : }
670 :
671 : /************************************************************************/
672 : /* FetchGetFeature() */
673 : /************************************************************************/
674 :
675 51 : OGRDataSource* OGRWFSLayer::FetchGetFeature(int nRequestMaxFeatures)
676 : {
677 :
678 51 : CPLString osURL = MakeGetFeatureURL(nRequestMaxFeatures, FALSE);
679 51 : CPLDebug("WFS", "%s", osURL.c_str());
680 :
681 51 : CPLHTTPResult* psResult = NULL;
682 :
683 51 : CPLString osOutputFormat = CPLURLGetValue(osURL, "OUTPUTFORMAT");
684 :
685 : /* Try streaming when the output format is GML and that we have a .xsd */
686 : /* that we are able to understand */
687 51 : CPLString osXSDFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
688 : VSIStatBufL sBuf;
689 51 : OGRSFDriverH hGMLDrv = OGRGetDriverByName("GML");
690 51 : if (CSLTestBoolean(CPLGetConfigOption("OGR_WFS_USE_STREAMING", "YES")) &&
691 : (osOutputFormat.size() == 0 || osOutputFormat.ifind("GML") != std::string::npos) &&
692 : VSIStatL(osXSDFileName, &sBuf) == 0 && hGMLDrv != NULL)
693 : {
694 : const char* pszStreamingName = CPLSPrintf("/vsicurl_streaming/%s",
695 45 : osURL.c_str());
696 : const char* pszStreamingNameWithXSD = CPLSPrintf("%s,xsd=%s",
697 45 : pszStreamingName, osXSDFileName.c_str());
698 : OGRDataSource* poGML_DS = (OGRDataSource*)
699 45 : OGR_Dr_Open(hGMLDrv, pszStreamingNameWithXSD, FALSE);
700 45 : if (poGML_DS)
701 : {
702 43 : bStreamingDS = TRUE;
703 43 : return poGML_DS;
704 : }
705 :
706 : /* In case of failure, read directly the content to examine */
707 : /* it, if it is XML error content */
708 : char szBuffer[2048];
709 2 : int nRead = 0;
710 2 : VSILFILE* fp = VSIFOpenL(pszStreamingName, "rb");
711 2 : if (fp)
712 : {
713 1 : nRead = (int)VSIFReadL(szBuffer, 1, sizeof(szBuffer) - 1, fp);
714 1 : szBuffer[nRead] = '\0';
715 1 : VSIFCloseL(fp);
716 : }
717 :
718 2 : if (nRead != 0)
719 : {
720 1 : if (MustRetryIfNonCompliantServer(szBuffer))
721 1 : return FetchGetFeature(nRequestMaxFeatures);
722 :
723 0 : if (strstr(szBuffer, "<ServiceExceptionReport") != NULL ||
724 : strstr(szBuffer, "<ows:ExceptionReport") != NULL)
725 : {
726 0 : if (poDS->IsOldDeegree(szBuffer))
727 : {
728 0 : return FetchGetFeature(nRequestMaxFeatures);
729 : }
730 :
731 : CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
732 0 : szBuffer);
733 0 : return NULL;
734 : }
735 : }
736 : }
737 :
738 7 : bStreamingDS = FALSE;
739 7 : psResult = poDS->HTTPFetch( osURL, NULL);
740 7 : if (psResult == NULL)
741 : {
742 1 : return NULL;
743 : }
744 :
745 6 : const char* pszContentType = "";
746 6 : if (psResult->pszContentType)
747 6 : pszContentType = psResult->pszContentType;
748 :
749 6 : CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this);
750 6 : VSIMkdir(osTmpDirName, 0);
751 :
752 6 : GByte *pabyData = psResult->pabyData;
753 6 : int nDataLen = psResult->nDataLen;
754 6 : int bIsMultiPart = FALSE;
755 6 : const char* pszAttachementFilename = NULL;
756 :
757 6 : if(strstr(pszContentType,"multipart")
758 : && CPLHTTPParseMultipartMime(psResult) )
759 : {
760 : int i;
761 0 : bIsMultiPart = TRUE;
762 0 : OGRWFSRecursiveUnlink(osTmpDirName);
763 0 : VSIMkdir(osTmpDirName, 0);
764 0 : for(i=0;i<psResult->nMimePartCount;i++)
765 : {
766 0 : CPLString osTmpFileName = osTmpDirName + "/";
767 : pszAttachementFilename =
768 : OGRWFSFetchContentDispositionFilename(
769 0 : psResult->pasMimePart[i].papszHeaders);
770 :
771 0 : if (pszAttachementFilename)
772 0 : osTmpFileName += pszAttachementFilename;
773 : else
774 0 : osTmpFileName += CPLSPrintf("file_%d", i);
775 :
776 0 : GByte* pData = (GByte*)VSIMalloc(psResult->pasMimePart[i].nDataLen);
777 0 : if (pData)
778 : {
779 0 : memcpy(pData, psResult->pasMimePart[i].pabyData, psResult->pasMimePart[i].nDataLen);
780 : VSILFILE *fp = VSIFileFromMemBuffer( osTmpFileName,
781 : pData,
782 0 : psResult->pasMimePart[i].nDataLen, TRUE);
783 0 : VSIFCloseL(fp);
784 : }
785 : }
786 : }
787 : else
788 : pszAttachementFilename =
789 : OGRWFSFetchContentDispositionFilename(
790 6 : psResult->papszHeaders);
791 :
792 6 : int bJSON = FALSE;
793 6 : int bCSV = FALSE;
794 6 : int bKML = FALSE;
795 6 : int bKMZ = FALSE;
796 6 : int bZIP = FALSE;
797 6 : int bGZIP = FALSE;
798 :
799 6 : const char* pszOutputFormat = osOutputFormat.c_str();
800 :
801 6 : if (FindSubStringInsensitive(pszContentType, "json") ||
802 : FindSubStringInsensitive(pszOutputFormat, "json"))
803 : {
804 1 : bJSON = TRUE;
805 : }
806 5 : else if (FindSubStringInsensitive(pszContentType, "csv") ||
807 : FindSubStringInsensitive(pszOutputFormat, "csv"))
808 : {
809 0 : bCSV = TRUE;
810 : }
811 5 : else if (FindSubStringInsensitive(pszContentType, "kml") ||
812 : FindSubStringInsensitive(pszOutputFormat, "kml"))
813 : {
814 0 : bKML = TRUE;
815 : }
816 5 : else if (FindSubStringInsensitive(pszContentType, "kmz") ||
817 : FindSubStringInsensitive(pszOutputFormat, "kmz"))
818 : {
819 0 : bKMZ = TRUE;
820 : }
821 5 : else if (strstr(pszContentType, "application/zip") != NULL)
822 : {
823 1 : bZIP = TRUE;
824 : }
825 4 : else if (strstr(pszContentType, "application/gzip") != NULL)
826 : {
827 0 : bGZIP = TRUE;
828 : }
829 :
830 6 : if (MustRetryIfNonCompliantServer((const char*)pabyData))
831 : {
832 1 : CPLHTTPDestroyResult(psResult);
833 1 : return FetchGetFeature(nRequestMaxFeatures);
834 : }
835 :
836 5 : if (strstr((const char*)pabyData, "<ServiceExceptionReport") != NULL ||
837 : strstr((const char*)pabyData, "<ows:ExceptionReport") != NULL)
838 : {
839 0 : if (poDS->IsOldDeegree((const char*)pabyData))
840 : {
841 0 : CPLHTTPDestroyResult(psResult);
842 0 : return FetchGetFeature(nRequestMaxFeatures);
843 : }
844 :
845 : CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
846 0 : pabyData);
847 0 : CPLHTTPDestroyResult(psResult);
848 0 : return NULL;
849 : }
850 :
851 5 : CPLString osTmpFileName;
852 :
853 5 : if (!bIsMultiPart)
854 : {
855 5 : if (bJSON)
856 1 : osTmpFileName = osTmpDirName + "/file.geojson";
857 4 : else if (bZIP)
858 1 : osTmpFileName = osTmpDirName + "/file.zip";
859 3 : else if (bCSV)
860 0 : osTmpFileName = osTmpDirName + "/file.csv";
861 3 : else if (bKML)
862 0 : osTmpFileName = osTmpDirName + "/file.kml";
863 3 : else if (bKMZ)
864 0 : osTmpFileName = osTmpDirName + "/file.kmz";
865 : /* GML is a special case. It needs the .xsd file that has been saved */
866 : /* as file.xsd, so we cannot used the attachement filename */
867 3 : else if (pszAttachementFilename &&
868 : !EQUAL(CPLGetExtension(pszAttachementFilename), "GML"))
869 : {
870 0 : osTmpFileName = osTmpDirName + "/";
871 0 : osTmpFileName += pszAttachementFilename;
872 : }
873 : else
874 : {
875 3 : osTmpFileName = osTmpDirName + "/file.gfs";
876 3 : VSIUnlink(osTmpFileName);
877 :
878 3 : osTmpFileName = osTmpDirName + "/file.gml";
879 : }
880 :
881 : VSILFILE *fp = VSIFileFromMemBuffer( osTmpFileName, pabyData,
882 5 : nDataLen, TRUE);
883 5 : VSIFCloseL(fp);
884 5 : psResult->pabyData = NULL;
885 :
886 5 : if (bZIP)
887 : {
888 1 : osTmpFileName = "/vsizip/" + osTmpFileName;
889 : }
890 4 : else if (bGZIP)
891 : {
892 0 : osTmpFileName = "/vsigzip/" + osTmpFileName;
893 : }
894 : }
895 : else
896 : {
897 0 : pabyData = NULL;
898 0 : nDataLen = 0;
899 0 : osTmpFileName = osTmpDirName;
900 : }
901 :
902 5 : CPLHTTPDestroyResult(psResult);
903 :
904 : OGRDataSource* poDS;
905 :
906 5 : poDS = (OGRDataSource*) OGROpen(osTmpFileName, FALSE, NULL);
907 5 : if (poDS == NULL && (bZIP || bIsMultiPart))
908 : {
909 0 : char** papszFileList = VSIReadDir(osTmpFileName);
910 : int i;
911 0 : for( i = 0; papszFileList != NULL && papszFileList[i] != NULL; i++ )
912 : {
913 : CPLString osFullFilename =
914 0 : CPLFormFilename( osTmpFileName, papszFileList[i], NULL );
915 0 : poDS = (OGRDataSource*) OGROpen(osFullFilename, FALSE, NULL);
916 0 : if (poDS != NULL)
917 : break;
918 : }
919 :
920 0 : CSLDestroy( papszFileList );
921 : }
922 :
923 5 : if (poDS == NULL)
924 : {
925 0 : if (pabyData != NULL && !bJSON && !bZIP &&
926 : strstr((const char*)pabyData, "<wfs:FeatureCollection") == NULL &&
927 : strstr((const char*)pabyData, "<gml:FeatureCollection") == NULL)
928 : {
929 0 : if (nDataLen > 1000)
930 0 : pabyData[1000] = 0;
931 : CPLError(CE_Failure, CPLE_AppDefined,
932 0 : "Error: cannot parse %s", pabyData);
933 : }
934 0 : return NULL;
935 : }
936 :
937 5 : OGRLayer* poLayer = poDS->GetLayer(0);
938 5 : if (poLayer == NULL)
939 : {
940 0 : OGRDataSource::DestroyDataSource(poDS);
941 0 : return NULL;
942 : }
943 :
944 5 : return poDS;
945 : }
946 :
947 : /************************************************************************/
948 : /* GetLayerDefn() */
949 : /************************************************************************/
950 :
951 960 : OGRFeatureDefn * OGRWFSLayer::GetLayerDefn()
952 : {
953 960 : if (poFeatureDefn)
954 940 : return poFeatureDefn;
955 :
956 20 : poDS->LoadMultipleLayerDefn(GetName(), pszNS, pszNSVal);
957 :
958 20 : if (poFeatureDefn)
959 13 : return poFeatureDefn;
960 :
961 7 : return BuildLayerDefn();
962 : }
963 :
964 : /************************************************************************/
965 : /* BuildLayerDefn() */
966 : /************************************************************************/
967 :
968 64 : OGRFeatureDefn * OGRWFSLayer::BuildLayerDefn(OGRFeatureDefn* poSrcFDefn)
969 : {
970 64 : int bUnsetWidthPrecision = FALSE;
971 :
972 64 : poFeatureDefn = new OGRFeatureDefn( pszName );
973 64 : poFeatureDefn->Reference();
974 :
975 64 : OGRDataSource* poDS = NULL;
976 :
977 64 : if (poSrcFDefn == NULL)
978 7 : poSrcFDefn = DescribeFeatureType();
979 64 : if (poSrcFDefn == NULL)
980 : {
981 0 : poDS = FetchGetFeature(1);
982 0 : if (poDS == NULL)
983 : {
984 0 : return poFeatureDefn;
985 : }
986 0 : poSrcFDefn = poDS->GetLayer(0)->GetLayerDefn();
987 0 : bGotApproximateLayerDefn = TRUE;
988 : /* We cannot trust width and precision based on a single feature */
989 0 : bUnsetWidthPrecision = TRUE;
990 : }
991 :
992 64 : CPLString osPropertyName = CPLURLGetValue(pszBaseURL, "PROPERTYNAME");
993 64 : const char* pszPropertyName = osPropertyName.c_str();
994 :
995 : int i;
996 64 : poFeatureDefn->SetGeomType(poSrcFDefn->GetGeomType());
997 410 : for(i=0;i<poSrcFDefn->GetFieldCount();i++)
998 : {
999 346 : if (pszPropertyName[0] != 0)
1000 : {
1001 0 : if (strstr(pszPropertyName,
1002 : poSrcFDefn->GetFieldDefn(i)->GetNameRef()) != NULL)
1003 0 : poFeatureDefn->AddFieldDefn(poSrcFDefn->GetFieldDefn(i));
1004 : else
1005 0 : bGotApproximateLayerDefn = TRUE;
1006 : }
1007 : else
1008 : {
1009 346 : OGRFieldDefn oFieldDefn(poSrcFDefn->GetFieldDefn(i));
1010 346 : if (bUnsetWidthPrecision)
1011 : {
1012 0 : oFieldDefn.SetWidth(0);
1013 0 : oFieldDefn.SetPrecision(0);
1014 : }
1015 346 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
1016 : }
1017 : }
1018 :
1019 64 : if (poDS)
1020 0 : OGRDataSource::DestroyDataSource(poDS);
1021 : else
1022 64 : delete poSrcFDefn;
1023 :
1024 64 : return poFeatureDefn;
1025 : }
1026 :
1027 : /************************************************************************/
1028 : /* GetSpatialRef() */
1029 : /************************************************************************/
1030 :
1031 8 : OGRSpatialReference *OGRWFSLayer::GetSpatialRef()
1032 : {
1033 8 : GetLayerDefn();
1034 8 : return poSRS;
1035 : }
1036 :
1037 : /************************************************************************/
1038 : /* ResetReading() */
1039 : /************************************************************************/
1040 :
1041 145 : void OGRWFSLayer::ResetReading()
1042 :
1043 : {
1044 145 : GetLayerDefn();
1045 145 : if (bPagingActive)
1046 3 : bReloadNeeded = TRUE;
1047 145 : nPagingStartIndex = 0;
1048 145 : nFeatureRead = 0;
1049 145 : nFeatureCountRequested = 0;
1050 145 : if (bReloadNeeded)
1051 : {
1052 39 : OGRDataSource::DestroyDataSource(poBaseDS);
1053 39 : poBaseDS = NULL;
1054 39 : poBaseLayer = NULL;
1055 39 : bHasFetched = FALSE;
1056 39 : bReloadNeeded = FALSE;
1057 : }
1058 145 : if (poBaseLayer)
1059 60 : poBaseLayer->ResetReading();
1060 145 : }
1061 :
1062 :
1063 : /************************************************************************/
1064 : /* GetNextFeature() */
1065 : /************************************************************************/
1066 :
1067 450 : OGRFeature *OGRWFSLayer::GetNextFeature()
1068 : {
1069 450 : GetLayerDefn();
1070 450 : if (bPagingActive && nFeatureRead == nPagingStartIndex + nFeatureCountRequested)
1071 : {
1072 5 : bReloadNeeded = TRUE;
1073 5 : nPagingStartIndex = nFeatureRead;
1074 : }
1075 450 : if (bReloadNeeded)
1076 : {
1077 6 : OGRDataSource::DestroyDataSource(poBaseDS);
1078 6 : poBaseDS = NULL;
1079 6 : poBaseLayer = NULL;
1080 6 : bHasFetched = FALSE;
1081 6 : bReloadNeeded = FALSE;
1082 : }
1083 450 : if (poBaseDS == NULL && !bHasFetched)
1084 : {
1085 49 : bHasFetched = TRUE;
1086 49 : poBaseDS = FetchGetFeature(0);
1087 49 : if (poBaseDS)
1088 : {
1089 48 : poBaseLayer = poBaseDS->GetLayer(0);
1090 48 : poBaseLayer->ResetReading();
1091 :
1092 : /* Check that the layer field definition is consistant with the one */
1093 : /* we got in BuildLayerDefn() */
1094 48 : if (poFeatureDefn->GetFieldCount() != poBaseLayer->GetLayerDefn()->GetFieldCount())
1095 1 : bGotApproximateLayerDefn = TRUE;
1096 : else
1097 : {
1098 : int iField;
1099 286 : for(iField = 0;iField < poFeatureDefn->GetFieldCount(); iField++)
1100 : {
1101 240 : OGRFieldDefn* poFDefn1 = poFeatureDefn->GetFieldDefn(iField);
1102 240 : OGRFieldDefn* poFDefn2 = poBaseLayer->GetLayerDefn()->GetFieldDefn(iField);
1103 240 : if (strcmp(poFDefn1->GetNameRef(), poFDefn2->GetNameRef()) != 0 ||
1104 : poFDefn1->GetType() != poFDefn2->GetType())
1105 : {
1106 1 : bGotApproximateLayerDefn = TRUE;
1107 1 : break;
1108 : }
1109 : }
1110 : }
1111 : }
1112 : }
1113 450 : if (!poBaseLayer)
1114 1 : return NULL;
1115 :
1116 24 : while(TRUE)
1117 : {
1118 473 : OGRFeature* poSrcFeature = poBaseLayer->GetNextFeature();
1119 473 : if (poSrcFeature == NULL)
1120 34 : return NULL;
1121 439 : nFeatureRead ++;
1122 439 : if( bCountFeaturesInGetNextFeature )
1123 0 : nFeatures ++;
1124 :
1125 439 : OGRGeometry* poGeom = poSrcFeature->GetGeometryRef();
1126 439 : if( m_poFilterGeom != NULL && poGeom != NULL &&
1127 : !FilterGeometry( poGeom ) )
1128 : {
1129 0 : delete poSrcFeature;
1130 0 : continue;
1131 : }
1132 :
1133 : /* Client-side attribue filtering with underlying layer defn */
1134 : /* identical to exposed layer defn */
1135 439 : if( !bGotApproximateLayerDefn &&
1136 : osWFSWhere.size() == 0 &&
1137 : m_poAttrQuery != NULL &&
1138 : !m_poAttrQuery->Evaluate( poSrcFeature ) )
1139 : {
1140 24 : delete poSrcFeature;
1141 24 : continue;
1142 : }
1143 :
1144 415 : OGRFeature* poNewFeature = new OGRFeature(poFeatureDefn);
1145 415 : if (bGotApproximateLayerDefn)
1146 : {
1147 2 : poNewFeature->SetFrom(poSrcFeature);
1148 :
1149 : /* Client-side attribue filtering */
1150 2 : if( m_poAttrQuery != NULL &&
1151 : osWFSWhere.size() == 0 &&
1152 : !m_poAttrQuery->Evaluate( poNewFeature ) )
1153 : {
1154 0 : delete poSrcFeature;
1155 0 : delete poNewFeature;
1156 0 : continue;
1157 : }
1158 : }
1159 : else
1160 : {
1161 : int iField;
1162 2253 : for(iField = 0;iField < poFeatureDefn->GetFieldCount(); iField++)
1163 1840 : poNewFeature->SetField( iField, poSrcFeature->GetRawFieldRef(iField) );
1164 413 : poNewFeature->SetStyleString(poSrcFeature->GetStyleString());
1165 413 : poNewFeature->SetGeometryDirectly(poSrcFeature->StealGeometry());
1166 : }
1167 415 : poNewFeature->SetFID(poSrcFeature->GetFID());
1168 415 : poGeom = poNewFeature->GetGeometryRef();
1169 :
1170 : /* FIXME? I don't really know what we should do with WFS 1.1.0 */
1171 : /* and non-GML format !!! I guess 50% WFS servers must do it wrong anyway */
1172 : /* GeoServer does currently axis inversion for non GML output, but */
1173 : /* apparently this is not correct : http://jira.codehaus.org/browse/GEOS-3657 */
1174 422 : if (poGeom != NULL &&
1175 : bAxisOrderAlreadyInverted &&
1176 7 : strcmp(poBaseDS->GetDriver()->GetName(), "GML") != 0)
1177 : {
1178 2 : poGeom->swapXY();
1179 : }
1180 :
1181 415 : if (poGeom && poSRS)
1182 415 : poGeom->assignSpatialReference(poSRS);
1183 415 : delete poSrcFeature;
1184 415 : return poNewFeature;
1185 : }
1186 : }
1187 :
1188 : /************************************************************************/
1189 : /* SetSpatialFilter() */
1190 : /************************************************************************/
1191 :
1192 26 : void OGRWFSLayer::SetSpatialFilter( OGRGeometry * poGeom )
1193 : {
1194 26 : if (bStreamingDS)
1195 24 : bReloadNeeded = TRUE;
1196 2 : else if (poFetchedFilterGeom == NULL && poBaseDS != NULL)
1197 : {
1198 : /* If there was no filter set, and that we set one */
1199 : /* the new result set can only be a subset of the whole */
1200 : /* so no need to reload from source */
1201 0 : bReloadNeeded = FALSE;
1202 : }
1203 2 : else if (poFetchedFilterGeom != NULL && poGeom != NULL && poBaseDS != NULL)
1204 : {
1205 0 : OGREnvelope oOldEnvelope, oNewEnvelope;
1206 0 : poFetchedFilterGeom->getEnvelope(&oOldEnvelope);
1207 0 : poGeom->getEnvelope(&oNewEnvelope);
1208 : /* Optimization : we don't need to request the server */
1209 : /* if the new BBOX is inside the old BBOX as we have */
1210 : /* already all the features */
1211 0 : bReloadNeeded = ! oOldEnvelope.Contains(oNewEnvelope);
1212 : }
1213 : else
1214 2 : bReloadNeeded = TRUE;
1215 26 : nFeatures = -1;
1216 26 : OGRLayer::SetSpatialFilter(poGeom);
1217 26 : ResetReading();
1218 26 : }
1219 :
1220 : /************************************************************************/
1221 : /* SetAttributeFilter() */
1222 : /************************************************************************/
1223 :
1224 35 : OGRErr OGRWFSLayer::SetAttributeFilter( const char * pszFilter )
1225 : {
1226 35 : if (pszFilter != NULL && pszFilter[0] == 0)
1227 7 : pszFilter = NULL;
1228 :
1229 35 : OGRErr eErr = OGRLayer::SetAttributeFilter(pszFilter);
1230 35 : if (eErr != CE_None)
1231 0 : return eErr;
1232 :
1233 35 : CPLString osOldWFSWhere(osWFSWhere);
1234 35 : if (poDS->HasMinOperators() && pszFilter != NULL)
1235 : {
1236 15 : int bNeedsNullCheck = FALSE;
1237 : int nVersion = (strcmp(poDS->GetVersion(),"1.0.0") == 0) ? 100 :
1238 15 : (atoi(poDS->GetVersion()) >= 2) ? 200 : 110;
1239 : osWFSWhere = WFS_TurnSQLFilterToOGCFilter(pszFilter,
1240 15 : GetLayerDefn(),
1241 : nVersion,
1242 : poDS->PropertyIsNotEqualToSupported(),
1243 : poDS->UseFeatureId() || bUseFeatureIdAtLayerLevel,
1244 : poDS->DoesGmlObjectIdNeedGMLPrefix(),
1245 30 : &bNeedsNullCheck);
1246 15 : if (bNeedsNullCheck && !poDS->HasNullCheck())
1247 0 : osWFSWhere = "";
1248 15 : if (osWFSWhere.size() == 0)
1249 : {
1250 4 : CPLDebug("WFS", "Using client-side only mode for filter \"%s\"", pszFilter);
1251 : }
1252 : }
1253 : else
1254 20 : osWFSWhere = "";
1255 :
1256 35 : osSQLWhere = (pszFilter) ? pszFilter : "";
1257 :
1258 35 : if (osWFSWhere != osOldWFSWhere)
1259 13 : bReloadNeeded = TRUE;
1260 : else
1261 22 : bReloadNeeded = FALSE;
1262 35 : nFeatures = -1;
1263 :
1264 35 : return CE_None;
1265 : }
1266 :
1267 : /************************************************************************/
1268 : /* TestCapability() */
1269 : /************************************************************************/
1270 :
1271 62 : int OGRWFSLayer::TestCapability( const char * pszCap )
1272 :
1273 : {
1274 62 : if( EQUAL(pszCap,OLCFastFeatureCount) )
1275 : {
1276 43 : if (nFeatures >= 0)
1277 2 : return TRUE;
1278 :
1279 : return poBaseLayer != NULL && m_poFilterGeom == NULL &&
1280 41 : m_poAttrQuery == NULL && poBaseLayer->TestCapability(pszCap);
1281 : }
1282 :
1283 19 : else if( EQUAL(pszCap,OLCFastGetExtent) )
1284 : {
1285 2 : if (bHasExtents)
1286 0 : return TRUE;
1287 :
1288 : return poBaseLayer != NULL &&
1289 2 : poBaseLayer->TestCapability(pszCap);
1290 : }
1291 :
1292 17 : else if( EQUAL(pszCap,OLCStringsAsUTF8) )
1293 2 : return poBaseLayer != NULL && poBaseLayer->TestCapability(pszCap);
1294 :
1295 15 : else if( EQUAL(pszCap, OLCSequentialWrite) ||
1296 : EQUAL(pszCap, OLCDeleteFeature) ||
1297 : EQUAL(pszCap, OLCRandomWrite) )
1298 : {
1299 7 : GetLayerDefn();
1300 : return poDS->SupportTransactions() && poDS->UpdateMode() &&
1301 7 : poFeatureDefn->GetFieldIndex("gml_id") == 0;
1302 : }
1303 8 : else if ( EQUAL(pszCap, OLCTransactions) )
1304 : {
1305 0 : return poDS->SupportTransactions() && poDS->UpdateMode();
1306 : }
1307 8 : else if( EQUAL(pszCap,OLCIgnoreFields) )
1308 : {
1309 2 : return poBaseDS == NULL;
1310 : }
1311 :
1312 6 : return FALSE;
1313 : }
1314 :
1315 : /************************************************************************/
1316 : /* ExecuteGetFeatureResultTypeHits() */
1317 : /************************************************************************/
1318 :
1319 8 : int OGRWFSLayer::ExecuteGetFeatureResultTypeHits()
1320 : {
1321 8 : char* pabyData = NULL;
1322 8 : CPLString osURL = MakeGetFeatureURL(0, TRUE);
1323 8 : if (pszRequiredOutputFormat)
1324 0 : osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", WFS_EscapeURL(pszRequiredOutputFormat));
1325 8 : CPLDebug("WFS", "%s", osURL.c_str());
1326 :
1327 8 : CPLHTTPResult* psResult = poDS->HTTPFetch( osURL, NULL);
1328 8 : if (psResult == NULL)
1329 : {
1330 1 : return -1;
1331 : }
1332 :
1333 : /* http://demo.snowflakesoftware.com:8080/Obstacle_AIXM_ZIP/GOPublisherWFS returns */
1334 : /* zip content, including for RESULTTYPE=hits */
1335 7 : if (psResult->pszContentType != NULL &&
1336 : strstr(psResult->pszContentType, "application/zip") != NULL)
1337 : {
1338 0 : CPLString osTmpFileName;
1339 0 : osTmpFileName.Printf("/vsimem/wfstemphits_%p.zip", this);
1340 : VSILFILE *fp = VSIFileFromMemBuffer( osTmpFileName, psResult->pabyData,
1341 0 : psResult->nDataLen, FALSE);
1342 0 : VSIFCloseL(fp);
1343 :
1344 0 : CPLString osZipTmpFileName("/vsizip/" + osTmpFileName);
1345 :
1346 0 : char** papszDirContent = CPLReadDir(osZipTmpFileName);
1347 0 : if (CSLCount(papszDirContent) != 1)
1348 : {
1349 : CPLError(CE_Failure, CPLE_AppDefined,
1350 0 : "Cannot parse result of RESULTTYPE=hits request : more than one file in zip");
1351 0 : CSLDestroy(papszDirContent);
1352 0 : CPLHTTPDestroyResult(psResult);
1353 0 : VSIUnlink(osTmpFileName);
1354 0 : return -1;
1355 : }
1356 :
1357 0 : CPLString osFileInZipTmpFileName = osZipTmpFileName + "/";
1358 0 : osFileInZipTmpFileName += papszDirContent[0];
1359 :
1360 0 : fp = VSIFOpenL(osFileInZipTmpFileName.c_str(), "rb");
1361 0 : if (fp == NULL)
1362 : {
1363 : CPLError(CE_Failure, CPLE_AppDefined,
1364 0 : "Cannot parse result of RESULTTYPE=hits request : cannot open one file in zip");
1365 0 : CSLDestroy(papszDirContent);
1366 0 : CPLHTTPDestroyResult(psResult);
1367 0 : VSIUnlink(osTmpFileName);
1368 0 : return -1;
1369 : }
1370 : VSIStatBufL sBuf;
1371 0 : VSIStatL(osFileInZipTmpFileName.c_str(), &sBuf);
1372 0 : pabyData = (char*) CPLMalloc((size_t)(sBuf.st_size + 1));
1373 0 : pabyData[sBuf.st_size] = 0;
1374 0 : VSIFReadL(pabyData, 1, (size_t)sBuf.st_size, fp);
1375 0 : VSIFCloseL(fp);
1376 :
1377 0 : CSLDestroy(papszDirContent);
1378 0 : VSIUnlink(osTmpFileName);
1379 : }
1380 : else
1381 : {
1382 7 : pabyData = (char*) psResult->pabyData;
1383 7 : psResult->pabyData = NULL;
1384 : }
1385 :
1386 7 : if (strstr(pabyData, "<ServiceExceptionReport") != NULL ||
1387 : strstr(pabyData, "<ows:ExceptionReport") != NULL)
1388 : {
1389 0 : if (poDS->IsOldDeegree(pabyData))
1390 : {
1391 0 : CPLHTTPDestroyResult(psResult);
1392 0 : return ExecuteGetFeatureResultTypeHits();
1393 : }
1394 : CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
1395 0 : pabyData);
1396 0 : CPLHTTPDestroyResult(psResult);
1397 0 : CPLFree(pabyData);
1398 0 : return -1;
1399 : }
1400 :
1401 7 : CPLXMLNode* psXML = CPLParseXMLString( pabyData );
1402 7 : if (psXML == NULL)
1403 : {
1404 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
1405 0 : pabyData);
1406 0 : CPLHTTPDestroyResult(psResult);
1407 0 : CPLFree(pabyData);
1408 0 : return -1;
1409 : }
1410 :
1411 7 : CPLStripXMLNamespace( psXML, NULL, TRUE );
1412 7 : CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=FeatureCollection" );
1413 7 : if (psRoot == NULL)
1414 : {
1415 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <FeatureCollection>");
1416 0 : CPLDestroyXMLNode( psXML );
1417 0 : CPLHTTPDestroyResult(psResult);
1418 0 : CPLFree(pabyData);
1419 0 : return -1;
1420 : }
1421 :
1422 7 : const char* pszValue = CPLGetXMLValue(psRoot, "numberOfFeatures", NULL);
1423 7 : if (pszValue == NULL)
1424 3 : pszValue = CPLGetXMLValue(psRoot, "numberMatched", NULL); /* WFS 2.0.0 */
1425 7 : if (pszValue == NULL)
1426 : {
1427 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find numberOfFeatures");
1428 0 : CPLDestroyXMLNode( psXML );
1429 0 : CPLHTTPDestroyResult(psResult);
1430 0 : CPLFree(pabyData);
1431 :
1432 0 : poDS->DisableSupportHits();
1433 0 : return -1;
1434 : }
1435 :
1436 7 : int nFeatures = atoi(pszValue);
1437 : /* Hum, http://deegree3-testing.deegree.org:80/deegree-inspire-node/services?MAXFEATURES=10&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=ad:Address&OUTPUTFORMAT=text/xml;%20subtype=gml/3.2.1&RESULTTYPE=hits */
1438 : /* returns more than MAXFEATURES features... So truncate to MAXFEATURES */
1439 7 : CPLString osMaxFeatures = CPLURLGetValue(osURL, atoi(poDS->GetVersion()) >= 2 ? "COUNT" : "MAXFEATURES");
1440 7 : if (osMaxFeatures.size() != 0)
1441 : {
1442 2 : int nMaxFeatures = atoi(osMaxFeatures);
1443 2 : if (nFeatures > nMaxFeatures)
1444 : {
1445 0 : CPLDebug("WFS", "Truncating result from %d to %d", nFeatures, nMaxFeatures);
1446 0 : nFeatures = nMaxFeatures;
1447 : }
1448 : }
1449 :
1450 7 : CPLDestroyXMLNode( psXML );
1451 7 : CPLHTTPDestroyResult(psResult);
1452 7 : CPLFree(pabyData);
1453 :
1454 7 : return nFeatures;
1455 : }
1456 : /************************************************************************/
1457 : /* CanRunGetFeatureCountAndGetExtentTogether() */
1458 : /************************************************************************/
1459 :
1460 15 : int OGRWFSLayer::CanRunGetFeatureCountAndGetExtentTogether()
1461 : {
1462 : /* In some cases, we can evaluate the result of GetFeatureCount() */
1463 : /* and GetExtent() with the same data */
1464 15 : CPLString osRequestURL = MakeGetFeatureURL(0, FALSE);
1465 : return( !bHasExtents && nFeatures < 0 &&
1466 : osRequestURL.ifind("FILTER") == std::string::npos &&
1467 : osRequestURL.ifind("MAXFEATURES") == std::string::npos &&
1468 : osRequestURL.ifind("COUNT") == std::string::npos &&
1469 15 : !(GetLayerDefn()->IsGeometryIgnored()) );
1470 : }
1471 :
1472 : /************************************************************************/
1473 : /* GetFeatureCount() */
1474 : /************************************************************************/
1475 :
1476 30 : int OGRWFSLayer::GetFeatureCount( int bForce )
1477 : {
1478 30 : if (nFeatures >= 0)
1479 0 : return nFeatures;
1480 :
1481 30 : if (TestCapability(OLCFastFeatureCount))
1482 4 : return poBaseLayer->GetFeatureCount(bForce);
1483 :
1484 26 : if ((m_poAttrQuery == NULL || osWFSWhere.size() != 0) &&
1485 : poDS->GetFeatureSupportHits())
1486 : {
1487 8 : nFeatures = ExecuteGetFeatureResultTypeHits();
1488 8 : if (nFeatures >= 0)
1489 5 : return nFeatures;
1490 : }
1491 :
1492 : /* If we have not yet the base layer, try to read one */
1493 : /* feature, and then query again OLCFastFeatureCount on the */
1494 : /* base layer. In case the WFS response would contain the */
1495 : /* number of features */
1496 21 : if (poBaseLayer == NULL)
1497 : {
1498 10 : ResetReading();
1499 10 : OGRFeature* poFeature = GetNextFeature();
1500 10 : delete poFeature;
1501 10 : ResetReading();
1502 :
1503 10 : if (TestCapability(OLCFastFeatureCount))
1504 6 : return poBaseLayer->GetFeatureCount(bForce);
1505 : }
1506 :
1507 : /* In some cases, we can evaluate the result of GetFeatureCount() */
1508 : /* and GetExtent() with the same data */
1509 15 : if( CanRunGetFeatureCountAndGetExtentTogether() )
1510 : {
1511 0 : OGREnvelope sDummy;
1512 0 : GetExtent(&sDummy);
1513 : }
1514 :
1515 15 : if( nFeatures < 0 )
1516 15 : nFeatures = OGRLayer::GetFeatureCount(bForce);
1517 :
1518 15 : return nFeatures;
1519 : }
1520 :
1521 :
1522 : /************************************************************************/
1523 : /* SetExtent() */
1524 : /************************************************************************/
1525 :
1526 0 : void OGRWFSLayer::SetExtents(double dfMinX, double dfMinY, double dfMaxX, double dfMaxY)
1527 : {
1528 0 : this->dfMinX = dfMinX;
1529 0 : this->dfMinY = dfMinY;
1530 0 : this->dfMaxX = dfMaxX;
1531 0 : this->dfMaxY = dfMaxY;
1532 0 : bHasExtents = TRUE;
1533 0 : }
1534 :
1535 : /************************************************************************/
1536 : /* GetExtent() */
1537 : /************************************************************************/
1538 :
1539 2 : OGRErr OGRWFSLayer::GetExtent(OGREnvelope *psExtent, int bForce)
1540 : {
1541 2 : if (bHasExtents)
1542 : {
1543 0 : psExtent->MinX = dfMinX;
1544 0 : psExtent->MinY = dfMinY;
1545 0 : psExtent->MaxX = dfMaxX;
1546 0 : psExtent->MaxY = dfMaxY;
1547 0 : return OGRERR_NONE;
1548 : }
1549 :
1550 : /* If we have not yet the base layer, try to read one */
1551 : /* feature, and then query again OLCFastGetExtent on the */
1552 : /* base layer. In case the WFS response would contain the */
1553 : /* global extent */
1554 2 : if (poBaseLayer == NULL)
1555 : {
1556 2 : ResetReading();
1557 2 : OGRFeature* poFeature = GetNextFeature();
1558 2 : delete poFeature;
1559 2 : ResetReading();
1560 : }
1561 :
1562 2 : if (TestCapability(OLCFastGetExtent))
1563 2 : return poBaseLayer->GetExtent(psExtent, bForce);
1564 :
1565 : /* In some cases, we can evaluate the result of GetFeatureCount() */
1566 : /* and GetExtent() with the same data */
1567 0 : if( CanRunGetFeatureCountAndGetExtentTogether() )
1568 : {
1569 0 : bCountFeaturesInGetNextFeature = TRUE;
1570 0 : nFeatures = 0;
1571 : }
1572 :
1573 0 : OGRErr eErr = OGRLayer::GetExtent(psExtent, bForce);
1574 :
1575 0 : if( bCountFeaturesInGetNextFeature )
1576 : {
1577 0 : if( eErr == OGRERR_NONE )
1578 : {
1579 0 : dfMinX = psExtent->MinX;
1580 0 : dfMinY = psExtent->MinY;
1581 0 : dfMaxX = psExtent->MaxX;
1582 0 : dfMaxY = psExtent->MaxY;
1583 0 : bHasExtents = TRUE;
1584 : }
1585 : else
1586 : {
1587 0 : nFeatures = -1;
1588 : }
1589 0 : bCountFeaturesInGetNextFeature = FALSE;
1590 : }
1591 :
1592 0 : return eErr;
1593 : }
1594 :
1595 : /************************************************************************/
1596 : /* GetShortName() */
1597 : /************************************************************************/
1598 :
1599 2147 : const char* OGRWFSLayer::GetShortName()
1600 : {
1601 2147 : const char* pszShortName = strchr(pszName, ':');
1602 2147 : if (pszShortName == NULL)
1603 18 : pszShortName = pszName;
1604 : else
1605 2129 : pszShortName ++;
1606 2147 : return pszShortName;
1607 : }
1608 :
1609 :
1610 : /************************************************************************/
1611 : /* GetPostHeader() */
1612 : /************************************************************************/
1613 :
1614 1 : CPLString OGRWFSLayer::GetPostHeader()
1615 : {
1616 1 : CPLString osPost;
1617 1 : osPost += "<?xml version=\"1.0\"?>\n";
1618 1 : osPost += "<wfs:Transaction xmlns:wfs=\"http://www.opengis.net/wfs\"\n";
1619 1 : osPost += " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
1620 1 : osPost += " service=\"WFS\" version=\""; osPost += poDS->GetVersion(); osPost += "\"\n";
1621 1 : osPost += " xmlns:gml=\"http://www.opengis.net/gml\"\n";
1622 1 : osPost += " xmlns:ogc=\"http://www.opengis.net/ogc\"\n";
1623 1 : osPost += " xsi:schemaLocation=\"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/";
1624 1 : osPost += poDS->GetVersion();
1625 1 : osPost += "/wfs.xsd ";
1626 1 : osPost += osTargetNamespace;
1627 1 : osPost += " ";
1628 :
1629 : char* pszXMLEncoded = CPLEscapeString(
1630 1 : GetDescribeFeatureTypeURL(FALSE), -1, CPLES_XML);
1631 1 : osPost += pszXMLEncoded;
1632 1 : CPLFree(pszXMLEncoded);
1633 :
1634 1 : osPost += "\">\n";
1635 :
1636 0 : return osPost;
1637 : }
1638 :
1639 : /************************************************************************/
1640 : /* CreateFeature() */
1641 : /************************************************************************/
1642 :
1643 1 : OGRErr OGRWFSLayer::CreateFeature( OGRFeature *poFeature )
1644 : {
1645 1 : if (!TestCapability(OLCSequentialWrite))
1646 : {
1647 0 : if (!poDS->SupportTransactions())
1648 : CPLError(CE_Failure, CPLE_AppDefined,
1649 0 : "CreateFeature() not supported: no WMS-T features advertized by server");
1650 0 : else if (!poDS->UpdateMode())
1651 : CPLError(CE_Failure, CPLE_AppDefined,
1652 0 : "CreateFeature() not supported: datasource opened as read-only");
1653 0 : return OGRERR_FAILURE;
1654 : }
1655 :
1656 1 : if (poGMLFeatureClass == NULL)
1657 : {
1658 : CPLError(CE_Failure, CPLE_AppDefined,
1659 0 : "Cannot insert feature because we didn't manage to parse the .XSD schema");
1660 0 : return OGRERR_FAILURE;
1661 : }
1662 :
1663 1 : if (poFeatureDefn->GetFieldIndex("gml_id") != 0)
1664 : {
1665 : CPLError(CE_Failure, CPLE_AppDefined,
1666 0 : "Cannot find gml_id field");
1667 0 : return OGRERR_FAILURE;
1668 : }
1669 :
1670 1 : if (poFeature->IsFieldSet(0))
1671 : {
1672 : CPLError(CE_Failure, CPLE_AppDefined,
1673 0 : "Cannot insert a feature when gml_id field is already set");
1674 0 : return OGRERR_FAILURE;
1675 : }
1676 :
1677 1 : CPLString osPost;
1678 :
1679 1 : const char* pszShortName = GetShortName();
1680 :
1681 1 : if (!bInTransaction)
1682 : {
1683 1 : osPost += GetPostHeader();
1684 1 : osPost += " <wfs:Insert>\n";
1685 : }
1686 1 : osPost += " <feature:"; osPost += pszShortName; osPost += " xmlns:feature=\"";
1687 1 : osPost += osTargetNamespace; osPost += "\">\n";
1688 :
1689 1 : CPLLocaleC oLocaleEnforcer;
1690 :
1691 : int i;
1692 2 : for(i=1; i <= poFeature->GetFieldCount(); i++)
1693 : {
1694 2 : if (poGMLFeatureClass->GetGeometryAttributeIndex() == i - 1)
1695 : {
1696 1 : OGRGeometry* poGeom = poFeature->GetGeometryRef();
1697 1 : if (poGeom != NULL && osGeometryColumnName.size() != 0)
1698 : {
1699 1 : if (poGeom->getSpatialReference() == NULL)
1700 1 : poGeom->assignSpatialReference(poSRS);
1701 : char* pszGML;
1702 1 : if (strcmp(poDS->GetVersion(), "1.1.0") == 0)
1703 : {
1704 1 : char** papszOptions = CSLAddString(NULL, "FORMAT=GML3");
1705 1 : pszGML = OGR_G_ExportToGMLEx((OGRGeometryH)poGeom, papszOptions);
1706 1 : CSLDestroy(papszOptions);
1707 : }
1708 : else
1709 0 : pszGML = OGR_G_ExportToGML((OGRGeometryH)poGeom);
1710 1 : osPost += " <feature:"; osPost += osGeometryColumnName; osPost += ">";
1711 1 : osPost += pszGML;
1712 1 : osPost += "</feature:"; osPost += osGeometryColumnName; osPost += ">\n";
1713 1 : CPLFree(pszGML);
1714 : }
1715 : }
1716 2 : if (i == poFeature->GetFieldCount())
1717 1 : break;
1718 :
1719 1 : if (poFeature->IsFieldSet(i))
1720 : {
1721 1 : OGRFieldDefn* poFDefn = poFeature->GetFieldDefnRef(i);
1722 1 : osPost += " <feature:";
1723 1 : osPost += poFDefn->GetNameRef();
1724 1 : osPost += ">";
1725 1 : if (poFDefn->GetType() == OFTInteger)
1726 0 : osPost += CPLSPrintf("%d", poFeature->GetFieldAsInteger(i));
1727 1 : else if (poFDefn->GetType() == OFTReal)
1728 0 : osPost += CPLSPrintf("%.16g", poFeature->GetFieldAsDouble(i));
1729 : else
1730 : {
1731 : char* pszXMLEncoded = CPLEscapeString(poFeature->GetFieldAsString(i),
1732 1 : -1, CPLES_XML);
1733 1 : osPost += pszXMLEncoded;
1734 1 : CPLFree(pszXMLEncoded);
1735 : }
1736 1 : osPost += "</feature:";
1737 1 : osPost += poFDefn->GetNameRef();
1738 1 : osPost += ">\n";
1739 : }
1740 :
1741 : }
1742 :
1743 1 : osPost += " </feature:"; osPost += pszShortName; osPost += ">\n";
1744 :
1745 1 : if (!bInTransaction)
1746 : {
1747 1 : osPost += " </wfs:Insert>\n";
1748 1 : osPost += "</wfs:Transaction>\n";
1749 : }
1750 : else
1751 : {
1752 0 : osGlobalInsert += osPost;
1753 0 : nExpectedInserts ++;
1754 0 : return OGRERR_NONE;
1755 : }
1756 :
1757 2 : CPLDebug("WFS", "Post : %s", osPost.c_str());
1758 :
1759 1 : char** papszOptions = NULL;
1760 1 : papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
1761 : papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
1762 1 : "Content-Type: application/xml; charset=UTF-8");
1763 :
1764 1 : CPLHTTPResult* psResult = poDS->HTTPFetch(poDS->GetPostTransactionURL(), papszOptions);
1765 1 : CSLDestroy(papszOptions);
1766 :
1767 1 : if (psResult == NULL)
1768 : {
1769 0 : return OGRERR_FAILURE;
1770 : }
1771 :
1772 1 : if (strstr((const char*)psResult->pabyData,
1773 : "<ServiceExceptionReport") != NULL ||
1774 : strstr((const char*)psResult->pabyData,
1775 : "<ows:ExceptionReport") != NULL)
1776 : {
1777 : CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
1778 1 : psResult->pabyData);
1779 1 : CPLHTTPDestroyResult(psResult);
1780 1 : return OGRERR_FAILURE;
1781 : }
1782 :
1783 0 : CPLDebug("WFS", "Response: %s", psResult->pabyData);
1784 :
1785 0 : CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
1786 0 : if (psXML == NULL)
1787 : {
1788 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
1789 0 : psResult->pabyData);
1790 0 : CPLHTTPDestroyResult(psResult);
1791 0 : return OGRERR_FAILURE;
1792 : }
1793 :
1794 0 : CPLStripXMLNamespace( psXML, NULL, TRUE );
1795 0 : int bUse100Schema = FALSE;
1796 0 : CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TransactionResponse" );
1797 0 : if (psRoot == NULL)
1798 : {
1799 0 : psRoot = CPLGetXMLNode( psXML, "=WFS_TransactionResponse" );
1800 0 : if (psRoot)
1801 0 : bUse100Schema = TRUE;
1802 : }
1803 :
1804 0 : if (psRoot == NULL)
1805 : {
1806 : CPLError(CE_Failure, CPLE_AppDefined,
1807 0 : "Cannot find <TransactionResponse>");
1808 0 : CPLDestroyXMLNode( psXML );
1809 0 : CPLHTTPDestroyResult(psResult);
1810 0 : return OGRERR_FAILURE;
1811 : }
1812 :
1813 0 : CPLXMLNode* psFeatureID = NULL;
1814 :
1815 0 : if (bUse100Schema)
1816 : {
1817 0 : if (CPLGetXMLNode( psRoot, "TransactionResult.Status.FAILED" ))
1818 : {
1819 : CPLError(CE_Failure, CPLE_AppDefined,
1820 : "Insert failed : %s",
1821 0 : psResult->pabyData);
1822 0 : CPLDestroyXMLNode( psXML );
1823 0 : CPLHTTPDestroyResult(psResult);
1824 0 : return OGRERR_FAILURE;
1825 : }
1826 :
1827 : psFeatureID =
1828 0 : CPLGetXMLNode( psRoot, "InsertResult.FeatureId");
1829 0 : if (psFeatureID == NULL)
1830 : {
1831 : CPLError(CE_Failure, CPLE_AppDefined,
1832 0 : "Cannot find InsertResult.FeatureId");
1833 0 : CPLDestroyXMLNode( psXML );
1834 0 : CPLHTTPDestroyResult(psResult);
1835 0 : return OGRERR_FAILURE;
1836 : }
1837 : }
1838 : else
1839 : {
1840 : psFeatureID =
1841 0 : CPLGetXMLNode( psRoot, "InsertResults.Feature.FeatureId");
1842 0 : if (psFeatureID == NULL)
1843 : {
1844 : CPLError(CE_Failure, CPLE_AppDefined,
1845 0 : "Cannot find InsertResults.Feature.FeatureId");
1846 0 : CPLDestroyXMLNode( psXML );
1847 0 : CPLHTTPDestroyResult(psResult);
1848 0 : return OGRERR_FAILURE;
1849 : }
1850 : }
1851 :
1852 0 : const char* pszFID = CPLGetXMLValue(psFeatureID, "fid", NULL);
1853 0 : if (pszFID == NULL)
1854 : {
1855 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find fid");
1856 0 : CPLDestroyXMLNode( psXML );
1857 0 : CPLHTTPDestroyResult(psResult);
1858 0 : return OGRERR_FAILURE;
1859 : }
1860 :
1861 0 : poFeature->SetField("gml_id", pszFID);
1862 :
1863 : /* If the returned fid is of the form layer_name.num, then use */
1864 : /* num as the OGR FID */
1865 0 : if (strncmp(pszFID, pszShortName, strlen(pszShortName)) == 0 &&
1866 0 : pszFID[strlen(pszShortName)] == '.')
1867 : {
1868 0 : int nFID = atoi(pszFID + strlen(pszShortName) + 1);
1869 : char szTemp[12];
1870 0 : sprintf(szTemp, "%d", nFID);
1871 : /* Check that it fits on a int32 */
1872 0 : if (strcmp(szTemp, pszFID + strlen(pszShortName) + 1) == 0)
1873 0 : poFeature->SetFID(nFID);
1874 : }
1875 :
1876 0 : CPLDebug("WFS", "Got FID = %ld", poFeature->GetFID());
1877 :
1878 0 : CPLDestroyXMLNode( psXML );
1879 0 : CPLHTTPDestroyResult(psResult);
1880 :
1881 : /* Invalidate layer */
1882 0 : bReloadNeeded = TRUE;
1883 0 : nFeatures = -1;
1884 0 : bHasExtents = FALSE;
1885 :
1886 0 : return OGRERR_NONE;
1887 : }
1888 :
1889 :
1890 : /************************************************************************/
1891 : /* SetFeature() */
1892 : /************************************************************************/
1893 :
1894 0 : OGRErr OGRWFSLayer::SetFeature( OGRFeature *poFeature )
1895 : {
1896 0 : if (!TestCapability(OLCRandomWrite))
1897 : {
1898 0 : if (!poDS->SupportTransactions())
1899 : CPLError(CE_Failure, CPLE_AppDefined,
1900 0 : "SetFeature() not supported: no WMS-T features advertized by server");
1901 0 : else if (!poDS->UpdateMode())
1902 : CPLError(CE_Failure, CPLE_AppDefined,
1903 0 : "SetFeature() not supported: datasource opened as read-only");
1904 0 : return OGRERR_FAILURE;
1905 : }
1906 :
1907 0 : if (poFeatureDefn->GetFieldIndex("gml_id") != 0)
1908 : {
1909 : CPLError(CE_Failure, CPLE_AppDefined,
1910 0 : "Cannot find gml_id field");
1911 0 : return OGRERR_FAILURE;
1912 : }
1913 :
1914 0 : if (poFeature->IsFieldSet(0) == FALSE)
1915 : {
1916 : CPLError(CE_Failure, CPLE_AppDefined,
1917 0 : "Cannot update a feature when gml_id field is not set");
1918 0 : return OGRERR_FAILURE;
1919 : }
1920 :
1921 0 : if (bInTransaction)
1922 : {
1923 : CPLError(CE_Warning, CPLE_AppDefined,
1924 0 : "SetFeature() not yet dealt in transaction. Issued immediately");
1925 : }
1926 :
1927 0 : const char* pszShortName = GetShortName();
1928 :
1929 0 : CPLString osPost;
1930 0 : osPost += GetPostHeader();
1931 :
1932 0 : osPost += " <wfs:Update typeName=\"feature:"; osPost += pszShortName; osPost += "\" xmlns:feature=\"";
1933 0 : osPost += osTargetNamespace; osPost += "\">\n";
1934 :
1935 0 : CPLLocaleC oLocaleEnforcer;
1936 :
1937 0 : OGRGeometry* poGeom = poFeature->GetGeometryRef();
1938 0 : if ( osGeometryColumnName.size() != 0 )
1939 : {
1940 0 : osPost += " <wfs:Property>\n";
1941 0 : osPost += " <wfs:Name>"; osPost += osGeometryColumnName; osPost += "</wfs:Name>\n";
1942 0 : if (poGeom != NULL)
1943 : {
1944 0 : if (poGeom->getSpatialReference() == NULL)
1945 0 : poGeom->assignSpatialReference(poSRS);
1946 : char* pszGML;
1947 0 : if (strcmp(poDS->GetVersion(), "1.1.0") == 0)
1948 : {
1949 0 : char** papszOptions = CSLAddString(NULL, "FORMAT=GML3");
1950 0 : pszGML = OGR_G_ExportToGMLEx((OGRGeometryH)poGeom, papszOptions);
1951 0 : CSLDestroy(papszOptions);
1952 : }
1953 : else
1954 0 : pszGML = OGR_G_ExportToGML((OGRGeometryH)poGeom);
1955 0 : osPost += " <wfs:Value>";
1956 0 : osPost += pszGML;
1957 0 : osPost += "</wfs:Value>\n";
1958 0 : CPLFree(pszGML);
1959 : }
1960 0 : osPost += " </wfs:Property>\n";
1961 : }
1962 :
1963 : int i;
1964 0 : for(i=1; i < poFeature->GetFieldCount(); i++)
1965 : {
1966 0 : OGRFieldDefn* poFDefn = poFeature->GetFieldDefnRef(i);
1967 :
1968 0 : osPost += " <wfs:Property>\n";
1969 0 : osPost += " <wfs:Name>"; osPost += poFDefn->GetNameRef(); osPost += "</wfs:Name>\n";
1970 0 : if (poFeature->IsFieldSet(i))
1971 : {
1972 0 : osPost += " <wfs:Value>";
1973 0 : if (poFDefn->GetType() == OFTInteger)
1974 0 : osPost += CPLSPrintf("%d", poFeature->GetFieldAsInteger(i));
1975 0 : else if (poFDefn->GetType() == OFTReal)
1976 0 : osPost += CPLSPrintf("%.16g", poFeature->GetFieldAsDouble(i));
1977 : else
1978 : {
1979 : char* pszXMLEncoded = CPLEscapeString(poFeature->GetFieldAsString(i),
1980 0 : -1, CPLES_XML);
1981 0 : osPost += pszXMLEncoded;
1982 0 : CPLFree(pszXMLEncoded);
1983 : }
1984 0 : osPost += "</wfs:Value>\n";
1985 : }
1986 0 : osPost += " </wfs:Property>\n";
1987 : }
1988 0 : osPost += " <ogc:Filter>\n";
1989 0 : if (poDS->UseFeatureId() || bUseFeatureIdAtLayerLevel)
1990 0 : osPost += " <ogc:FeatureId fid=\"";
1991 0 : else if (atoi(poDS->GetVersion()) >= 2)
1992 0 : osPost += " <ogc:ResourceId rid=\"";
1993 : else
1994 0 : osPost += " <ogc:GmlObjectId gml:id=\"";
1995 0 : osPost += poFeature->GetFieldAsString(0); osPost += "\"/>\n";
1996 0 : osPost += " </ogc:Filter>\n";
1997 0 : osPost += " </wfs:Update>\n";
1998 0 : osPost += "</wfs:Transaction>\n";
1999 :
2000 0 : CPLDebug("WFS", "Post : %s", osPost.c_str());
2001 :
2002 0 : char** papszOptions = NULL;
2003 0 : papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
2004 : papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
2005 0 : "Content-Type: application/xml; charset=UTF-8");
2006 :
2007 0 : CPLHTTPResult* psResult = poDS->HTTPFetch(poDS->GetPostTransactionURL(), papszOptions);
2008 0 : CSLDestroy(papszOptions);
2009 :
2010 0 : if (psResult == NULL)
2011 : {
2012 0 : return OGRERR_FAILURE;
2013 : }
2014 :
2015 0 : if (strstr((const char*)psResult->pabyData,
2016 : "<ServiceExceptionReport") != NULL ||
2017 : strstr((const char*)psResult->pabyData,
2018 : "<ows:ExceptionReport") != NULL)
2019 : {
2020 : CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
2021 0 : psResult->pabyData);
2022 0 : CPLHTTPDestroyResult(psResult);
2023 0 : return OGRERR_FAILURE;
2024 : }
2025 :
2026 0 : CPLDebug("WFS", "Response: %s", psResult->pabyData);
2027 :
2028 0 : CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
2029 0 : if (psXML == NULL)
2030 : {
2031 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
2032 0 : psResult->pabyData);
2033 0 : CPLHTTPDestroyResult(psResult);
2034 0 : return OGRERR_FAILURE;
2035 : }
2036 :
2037 0 : CPLStripXMLNamespace( psXML, NULL, TRUE );
2038 0 : int bUse100Schema = FALSE;
2039 0 : CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TransactionResponse" );
2040 0 : if (psRoot == NULL)
2041 : {
2042 0 : psRoot = CPLGetXMLNode( psXML, "=WFS_TransactionResponse" );
2043 0 : if (psRoot)
2044 0 : bUse100Schema = TRUE;
2045 : }
2046 0 : if (psRoot == NULL)
2047 : {
2048 : CPLError(CE_Failure, CPLE_AppDefined,
2049 0 : "Cannot find <TransactionResponse>");
2050 0 : CPLDestroyXMLNode( psXML );
2051 0 : CPLHTTPDestroyResult(psResult);
2052 0 : return OGRERR_FAILURE;
2053 : }
2054 :
2055 0 : if (bUse100Schema)
2056 : {
2057 0 : if (CPLGetXMLNode( psRoot, "TransactionResult.Status.FAILED" ))
2058 : {
2059 : CPLError(CE_Failure, CPLE_AppDefined,
2060 : "Update failed : %s",
2061 0 : psResult->pabyData);
2062 0 : CPLDestroyXMLNode( psXML );
2063 0 : CPLHTTPDestroyResult(psResult);
2064 0 : return OGRERR_FAILURE;
2065 : }
2066 : }
2067 :
2068 0 : CPLDestroyXMLNode( psXML );
2069 0 : CPLHTTPDestroyResult(psResult);
2070 :
2071 : /* Invalidate layer */
2072 0 : bReloadNeeded = TRUE;
2073 0 : nFeatures = -1;
2074 0 : bHasExtents = FALSE;
2075 :
2076 0 : return OGRERR_NONE;
2077 : }
2078 : /************************************************************************/
2079 : /* GetFeature() */
2080 : /************************************************************************/
2081 :
2082 4 : OGRFeature* OGRWFSLayer::GetFeature(long nFID)
2083 : {
2084 4 : GetLayerDefn();
2085 4 : if (poBaseLayer == NULL && poFeatureDefn->GetFieldIndex("gml_id") == 0)
2086 : {
2087 : /* This is lovely hackish. We assume that then gml_id will be */
2088 : /* layer_name.number. This is actually what we can observe with */
2089 : /* GeoServer and TinyOWS */
2090 0 : CPLString osVal = CPLSPrintf("gml_id = '%s.%ld'", GetShortName(), nFID);
2091 0 : CPLString osOldSQLWhere(osSQLWhere);
2092 0 : SetAttributeFilter(osVal);
2093 0 : OGRFeature* poFeature = GetNextFeature();
2094 0 : const char* pszOldFilter = osOldSQLWhere.size() ? osOldSQLWhere.c_str() : NULL;
2095 0 : SetAttributeFilter(pszOldFilter);
2096 0 : if (poFeature)
2097 0 : return poFeature;
2098 : }
2099 :
2100 4 : return OGRLayer::GetFeature(nFID);
2101 : }
2102 :
2103 : /************************************************************************/
2104 : /* DeleteFromFilter() */
2105 : /************************************************************************/
2106 :
2107 0 : OGRErr OGRWFSLayer::DeleteFromFilter( CPLString osOGCFilter )
2108 : {
2109 0 : if (!TestCapability(OLCDeleteFeature))
2110 : {
2111 0 : if (!poDS->SupportTransactions())
2112 : CPLError(CE_Failure, CPLE_AppDefined,
2113 0 : "DeleteFromFilter() not supported: no WMS-T features advertized by server");
2114 0 : else if (!poDS->UpdateMode())
2115 : CPLError(CE_Failure, CPLE_AppDefined,
2116 0 : "DeleteFromFilter() not supported: datasource opened as read-only");
2117 0 : return OGRERR_FAILURE;
2118 : }
2119 :
2120 0 : if (poFeatureDefn->GetFieldIndex("gml_id") != 0)
2121 : {
2122 : CPLError(CE_Failure, CPLE_AppDefined,
2123 0 : "Cannot find gml_id field");
2124 0 : return OGRERR_FAILURE;
2125 : }
2126 0 : const char* pszShortName = GetShortName();
2127 :
2128 0 : CPLString osPost;
2129 0 : osPost += GetPostHeader();
2130 :
2131 0 : osPost += " <wfs:Delete xmlns:feature=\""; osPost += osTargetNamespace;
2132 0 : osPost += "\" typeName=\"feature:"; osPost += pszShortName; osPost += "\">\n";
2133 0 : osPost += " <ogc:Filter>\n";
2134 0 : osPost += osOGCFilter;
2135 0 : osPost += " </ogc:Filter>\n";
2136 0 : osPost += " </wfs:Delete>\n";
2137 0 : osPost += "</wfs:Transaction>\n";
2138 :
2139 0 : CPLDebug("WFS", "Post : %s", osPost.c_str());
2140 :
2141 0 : char** papszOptions = NULL;
2142 0 : papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
2143 : papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
2144 0 : "Content-Type: application/xml; charset=UTF-8");
2145 :
2146 0 : CPLHTTPResult* psResult = poDS->HTTPFetch(poDS->GetPostTransactionURL(), papszOptions);
2147 0 : CSLDestroy(papszOptions);
2148 :
2149 0 : if (psResult == NULL)
2150 : {
2151 0 : return OGRERR_FAILURE;
2152 : }
2153 :
2154 0 : if (strstr((const char*)psResult->pabyData, "<ServiceExceptionReport") != NULL ||
2155 : strstr((const char*)psResult->pabyData, "<ows:ExceptionReport") != NULL)
2156 : {
2157 : CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
2158 0 : psResult->pabyData);
2159 0 : CPLHTTPDestroyResult(psResult);
2160 0 : return OGRERR_FAILURE;
2161 : }
2162 :
2163 0 : CPLDebug("WFS", "Response: %s", psResult->pabyData);
2164 :
2165 0 : CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
2166 0 : if (psXML == NULL)
2167 : {
2168 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
2169 0 : psResult->pabyData);
2170 0 : CPLHTTPDestroyResult(psResult);
2171 0 : return OGRERR_FAILURE;
2172 : }
2173 :
2174 0 : CPLStripXMLNamespace( psXML, NULL, TRUE );
2175 0 : int bUse100Schema = FALSE;
2176 0 : CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TransactionResponse" );
2177 0 : if (psRoot == NULL)
2178 : {
2179 0 : psRoot = CPLGetXMLNode( psXML, "=WFS_TransactionResponse" );
2180 0 : if (psRoot)
2181 0 : bUse100Schema = TRUE;
2182 : }
2183 0 : if (psRoot == NULL)
2184 : {
2185 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <TransactionResponse>");
2186 0 : CPLDestroyXMLNode( psXML );
2187 0 : CPLHTTPDestroyResult(psResult);
2188 0 : return OGRERR_FAILURE;
2189 : }
2190 :
2191 0 : if (bUse100Schema)
2192 : {
2193 0 : if (CPLGetXMLNode( psRoot, "TransactionResult.Status.FAILED" ))
2194 : {
2195 : CPLError(CE_Failure, CPLE_AppDefined,
2196 : "Delete failed : %s",
2197 0 : psResult->pabyData);
2198 0 : CPLDestroyXMLNode( psXML );
2199 0 : CPLHTTPDestroyResult(psResult);
2200 0 : return OGRERR_FAILURE;
2201 : }
2202 : }
2203 :
2204 0 : CPLDestroyXMLNode( psXML );
2205 0 : CPLHTTPDestroyResult(psResult);
2206 :
2207 : /* Invalidate layer */
2208 0 : bReloadNeeded = TRUE;
2209 0 : nFeatures = -1;
2210 0 : bHasExtents = FALSE;
2211 :
2212 0 : return OGRERR_NONE;
2213 : }
2214 :
2215 : /************************************************************************/
2216 : /* DeleteFeature() */
2217 : /************************************************************************/
2218 :
2219 0 : OGRErr OGRWFSLayer::DeleteFeature( long nFID )
2220 : {
2221 0 : if (!TestCapability(OLCDeleteFeature))
2222 : {
2223 0 : if (!poDS->SupportTransactions())
2224 : CPLError(CE_Failure, CPLE_AppDefined,
2225 0 : "DeleteFeature() not supported: no WMS-T features advertized by server");
2226 0 : else if (!poDS->UpdateMode())
2227 : CPLError(CE_Failure, CPLE_AppDefined,
2228 0 : "DeleteFeature() not supported: datasource opened as read-only");
2229 0 : return OGRERR_FAILURE;
2230 : }
2231 :
2232 0 : if (poFeatureDefn->GetFieldIndex("gml_id") != 0)
2233 : {
2234 : CPLError(CE_Failure, CPLE_AppDefined,
2235 0 : "Cannot find gml_id field");
2236 0 : return OGRERR_FAILURE;
2237 : }
2238 :
2239 0 : OGRFeature* poFeature = GetFeature(nFID);
2240 0 : if (poFeature == NULL)
2241 : {
2242 : CPLError(CE_Failure, CPLE_AppDefined,
2243 0 : "Cannot find feature %ld", nFID);
2244 0 : return OGRERR_FAILURE;
2245 : }
2246 :
2247 0 : const char* pszGMLID = poFeature->GetFieldAsString("gml_id");
2248 0 : if (pszGMLID == NULL)
2249 : {
2250 : CPLError(CE_Failure, CPLE_AppDefined,
2251 0 : "Cannot delete a feature with gml_id unset");
2252 0 : delete poFeature;
2253 0 : return OGRERR_FAILURE;
2254 : }
2255 :
2256 0 : if (bInTransaction)
2257 : {
2258 : CPLError(CE_Warning, CPLE_AppDefined,
2259 0 : "DeleteFeature() not yet dealt in transaction. Issued immediately");
2260 : }
2261 :
2262 0 : CPLString osGMLID = pszGMLID;
2263 0 : pszGMLID = NULL;
2264 0 : delete poFeature;
2265 0 : poFeature = NULL;
2266 :
2267 0 : CPLString osFilter;
2268 0 : osFilter = "<ogc:FeatureId fid=\""; osFilter += osGMLID; osFilter += "\"/>\n";
2269 0 : return DeleteFromFilter(osFilter);
2270 : }
2271 :
2272 :
2273 : /************************************************************************/
2274 : /* StartTransaction() */
2275 : /************************************************************************/
2276 :
2277 0 : OGRErr OGRWFSLayer::StartTransaction()
2278 : {
2279 0 : if (!TestCapability(OLCTransactions))
2280 : {
2281 0 : if (!poDS->SupportTransactions())
2282 : CPLError(CE_Failure, CPLE_AppDefined,
2283 0 : "StartTransaction() not supported: no WMS-T features advertized by server");
2284 0 : else if (!poDS->UpdateMode())
2285 : CPLError(CE_Failure, CPLE_AppDefined,
2286 0 : "StartTransaction() not supported: datasource opened as read-only");
2287 0 : return OGRERR_FAILURE;
2288 : }
2289 :
2290 0 : if (bInTransaction)
2291 : {
2292 : CPLError(CE_Failure, CPLE_AppDefined,
2293 0 : "StartTransaction() has already been called");
2294 0 : return OGRERR_FAILURE;
2295 : }
2296 :
2297 0 : bInTransaction = TRUE;
2298 0 : osGlobalInsert = "";
2299 0 : nExpectedInserts = 0;
2300 0 : aosFIDList.resize(0);
2301 :
2302 0 : return OGRERR_NONE;
2303 : }
2304 :
2305 : /************************************************************************/
2306 : /* CommitTransaction() */
2307 : /************************************************************************/
2308 :
2309 0 : OGRErr OGRWFSLayer::CommitTransaction()
2310 : {
2311 0 : if (!TestCapability(OLCTransactions))
2312 : {
2313 0 : if (!poDS->SupportTransactions())
2314 : CPLError(CE_Failure, CPLE_AppDefined,
2315 0 : "CommitTransaction() not supported: no WMS-T features advertized by server");
2316 0 : else if (!poDS->UpdateMode())
2317 : CPLError(CE_Failure, CPLE_AppDefined,
2318 0 : "CommitTransaction() not supported: datasource opened as read-only");
2319 0 : return OGRERR_FAILURE;
2320 : }
2321 :
2322 0 : if (!bInTransaction)
2323 : {
2324 : CPLError(CE_Failure, CPLE_AppDefined,
2325 0 : "StartTransaction() has not yet been called");
2326 0 : return OGRERR_FAILURE;
2327 : }
2328 :
2329 0 : if (osGlobalInsert.size() != 0)
2330 : {
2331 0 : CPLString osPost = GetPostHeader();
2332 0 : osPost += " <wfs:Insert>\n";
2333 0 : osPost += osGlobalInsert;
2334 0 : osPost += " </wfs:Insert>\n";
2335 0 : osPost += "</wfs:Transaction>\n";
2336 :
2337 0 : bInTransaction = FALSE;
2338 0 : osGlobalInsert = "";
2339 0 : int nExpectedInserts = this->nExpectedInserts;
2340 0 : this->nExpectedInserts = 0;
2341 :
2342 0 : CPLDebug("WFS", "Post : %s", osPost.c_str());
2343 :
2344 0 : char** papszOptions = NULL;
2345 0 : papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
2346 : papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
2347 0 : "Content-Type: application/xml; charset=UTF-8");
2348 :
2349 0 : CPLHTTPResult* psResult = poDS->HTTPFetch(poDS->GetPostTransactionURL(), papszOptions);
2350 0 : CSLDestroy(papszOptions);
2351 :
2352 0 : if (psResult == NULL)
2353 : {
2354 0 : return OGRERR_FAILURE;
2355 : }
2356 :
2357 0 : if (strstr((const char*)psResult->pabyData,
2358 : "<ServiceExceptionReport") != NULL ||
2359 : strstr((const char*)psResult->pabyData,
2360 : "<ows:ExceptionReport") != NULL)
2361 : {
2362 : CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
2363 0 : psResult->pabyData);
2364 0 : CPLHTTPDestroyResult(psResult);
2365 0 : return OGRERR_FAILURE;
2366 : }
2367 :
2368 0 : CPLDebug("WFS", "Response: %s", psResult->pabyData);
2369 :
2370 0 : CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
2371 0 : if (psXML == NULL)
2372 : {
2373 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
2374 0 : psResult->pabyData);
2375 0 : CPLHTTPDestroyResult(psResult);
2376 0 : return OGRERR_FAILURE;
2377 : }
2378 :
2379 0 : CPLStripXMLNamespace( psXML, NULL, TRUE );
2380 0 : int bUse100Schema = FALSE;
2381 0 : CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TransactionResponse" );
2382 0 : if (psRoot == NULL)
2383 : {
2384 0 : psRoot = CPLGetXMLNode( psXML, "=WFS_TransactionResponse" );
2385 0 : if (psRoot)
2386 0 : bUse100Schema = TRUE;
2387 : }
2388 :
2389 0 : if (psRoot == NULL)
2390 : {
2391 : CPLError(CE_Failure, CPLE_AppDefined,
2392 0 : "Cannot find <TransactionResponse>");
2393 0 : CPLDestroyXMLNode( psXML );
2394 0 : CPLHTTPDestroyResult(psResult);
2395 0 : return OGRERR_FAILURE;
2396 : }
2397 :
2398 0 : if (bUse100Schema)
2399 : {
2400 0 : if (CPLGetXMLNode( psRoot, "TransactionResult.Status.FAILED" ))
2401 : {
2402 : CPLError(CE_Failure, CPLE_AppDefined,
2403 : "Insert failed : %s",
2404 0 : psResult->pabyData);
2405 0 : CPLDestroyXMLNode( psXML );
2406 0 : CPLHTTPDestroyResult(psResult);
2407 0 : return OGRERR_FAILURE;
2408 : }
2409 :
2410 : /* TODO */
2411 : }
2412 : else
2413 : {
2414 0 : int nGotInserted = atoi(CPLGetXMLValue(psRoot, "TransactionSummary.totalInserted", ""));
2415 0 : if (nGotInserted != nExpectedInserts)
2416 : {
2417 : CPLError(CE_Failure, CPLE_AppDefined,
2418 : "Only %d features were inserted whereas %d where expected",
2419 0 : nGotInserted, nExpectedInserts);
2420 0 : CPLDestroyXMLNode( psXML );
2421 0 : CPLHTTPDestroyResult(psResult);
2422 0 : return OGRERR_FAILURE;
2423 : }
2424 :
2425 : CPLXMLNode* psInsertResults =
2426 0 : CPLGetXMLNode( psRoot, "InsertResults");
2427 0 : if (psInsertResults == NULL)
2428 : {
2429 : CPLError(CE_Failure, CPLE_AppDefined,
2430 0 : "Cannot find node InsertResults");
2431 0 : CPLDestroyXMLNode( psXML );
2432 0 : CPLHTTPDestroyResult(psResult);
2433 0 : return OGRERR_FAILURE;
2434 : }
2435 :
2436 0 : aosFIDList.resize(0);
2437 :
2438 0 : CPLXMLNode* psChild = psInsertResults->psChild;
2439 0 : while(psChild)
2440 : {
2441 0 : const char* pszFID = CPLGetXMLValue(psChild, "FeatureId.fid", NULL);
2442 0 : if (pszFID == NULL)
2443 : {
2444 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find fid");
2445 0 : CPLDestroyXMLNode( psXML );
2446 0 : CPLHTTPDestroyResult(psResult);
2447 0 : return OGRERR_FAILURE;
2448 : }
2449 0 : aosFIDList.push_back(pszFID);
2450 :
2451 0 : psChild = psChild->psNext;
2452 : }
2453 :
2454 0 : if ((int)aosFIDList.size() != nGotInserted)
2455 : {
2456 : CPLError(CE_Failure, CPLE_AppDefined,
2457 0 : "Inconsistant InsertResults: did not get expected FID count");
2458 0 : CPLDestroyXMLNode( psXML );
2459 0 : CPLHTTPDestroyResult(psResult);
2460 0 : return OGRERR_FAILURE;
2461 : }
2462 : }
2463 :
2464 0 : CPLDestroyXMLNode( psXML );
2465 0 : CPLHTTPDestroyResult(psResult);
2466 : }
2467 :
2468 0 : bInTransaction = FALSE;
2469 0 : osGlobalInsert = "";
2470 0 : nExpectedInserts = 0;
2471 :
2472 0 : return OGRERR_NONE;
2473 : }
2474 :
2475 : /************************************************************************/
2476 : /* RollbackTransaction() */
2477 : /************************************************************************/
2478 :
2479 0 : OGRErr OGRWFSLayer::RollbackTransaction()
2480 : {
2481 0 : if (!TestCapability(OLCTransactions))
2482 : {
2483 0 : if (!poDS->SupportTransactions())
2484 : CPLError(CE_Failure, CPLE_AppDefined,
2485 0 : "RollbackTransaction() not supported: no WMS-T features advertized by server");
2486 0 : else if (!poDS->UpdateMode())
2487 : CPLError(CE_Failure, CPLE_AppDefined,
2488 0 : "RollbackTransaction() not supported: datasource opened as read-only");
2489 0 : return OGRERR_FAILURE;
2490 : }
2491 :
2492 0 : if (!bInTransaction)
2493 : {
2494 : CPLError(CE_Failure, CPLE_AppDefined,
2495 0 : "StartTransaction() has not yet been called");
2496 0 : return OGRERR_FAILURE;
2497 : }
2498 :
2499 0 : bInTransaction = FALSE;
2500 0 : osGlobalInsert = "";
2501 0 : nExpectedInserts = 0;
2502 :
2503 0 : return OGRERR_NONE;
2504 : }
2505 :
2506 : /************************************************************************/
2507 : /* SetRequiredOutputFormat() */
2508 : /************************************************************************/
2509 :
2510 0 : void OGRWFSLayer::SetRequiredOutputFormat(const char* pszRequiredOutputFormatIn)
2511 : {
2512 0 : CPLFree(pszRequiredOutputFormat);
2513 0 : if (pszRequiredOutputFormatIn)
2514 : {
2515 0 : pszRequiredOutputFormat = CPLStrdup(pszRequiredOutputFormatIn);
2516 : }
2517 : else
2518 : {
2519 0 : pszRequiredOutputFormat = NULL;
2520 : }
2521 0 : }
2522 :
2523 : /************************************************************************/
2524 : /* SetOrderBy() */
2525 : /************************************************************************/
2526 :
2527 1 : void OGRWFSLayer::SetOrderBy(const char* pszFieldToSort, int bAscFlag)
2528 : {
2529 1 : osFieldToSort = pszFieldToSort ? pszFieldToSort : "";
2530 1 : this->bAscFlag = bAscFlag;
2531 1 : }
|