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