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