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