1 : /******************************************************************************
2 : * $Id: ogrwfsdatasource.cpp 23702 2012-01-05 00:02:12Z rouault $
3 : *
4 : * Project: WFS Translator
5 : * Purpose: Implements OGRWFSDataSource 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 "gmlutils.h"
36 : #include "parsexsd.h"
37 : #include "swq.h"
38 : #include "ogr_p.h"
39 :
40 : CPL_CVSID("$Id: ogrwfsdatasource.cpp 23702 2012-01-05 00:02:12Z rouault $");
41 :
42 :
43 : /************************************************************************/
44 : /* WFSFindNode() */
45 : /************************************************************************/
46 :
47 32 : CPLXMLNode* WFSFindNode(CPLXMLNode* psXML, const char* pszRootName)
48 : {
49 32 : CPLXMLNode* psIter = psXML;
50 92 : while(psIter)
51 : {
52 58 : if (psIter->eType == CXT_Element)
53 : {
54 52 : const char* pszNodeName = psIter->pszValue;
55 52 : const char* pszSep = strchr(pszNodeName, ':');
56 52 : if (pszSep)
57 18 : pszNodeName = pszSep + 1;
58 52 : if (EQUAL(pszNodeName, pszRootName))
59 : {
60 30 : return psIter;
61 : }
62 : }
63 28 : psIter = psIter->psNext;
64 : }
65 :
66 2 : psIter = psXML->psChild;
67 6 : while(psIter)
68 : {
69 4 : if (psIter->eType == CXT_Element)
70 : {
71 4 : const char* pszNodeName = psIter->pszValue;
72 4 : const char* pszSep = strchr(pszNodeName, ':');
73 4 : if (pszSep)
74 0 : pszNodeName = pszSep + 1;
75 4 : if (EQUAL(pszNodeName, pszRootName))
76 : {
77 2 : return psIter;
78 : }
79 : }
80 2 : psIter = psIter->psNext;
81 : }
82 0 : return NULL;
83 : }
84 :
85 : /************************************************************************/
86 : /* OGRWFSWrappedResultLayer */
87 : /************************************************************************/
88 :
89 : class OGRWFSWrappedResultLayer : public OGRLayer
90 : {
91 : OGRDataSource *poDS;
92 : OGRLayer *poLayer;
93 :
94 : public:
95 0 : OGRWFSWrappedResultLayer(OGRDataSource* poDS, OGRLayer* poLayer)
96 0 : {
97 0 : this->poDS = poDS;
98 0 : this->poLayer = poLayer;
99 0 : }
100 0 : ~OGRWFSWrappedResultLayer()
101 0 : {
102 0 : delete poDS;
103 0 : }
104 :
105 0 : virtual void ResetReading() { poLayer->ResetReading(); }
106 0 : virtual OGRFeature *GetNextFeature() { return poLayer->GetNextFeature(); }
107 0 : virtual OGRErr SetNextByIndex( long nIndex ) { return poLayer->SetNextByIndex(nIndex); }
108 0 : virtual OGRFeature *GetFeature( long nFID ) { return poLayer->GetFeature(nFID); }
109 0 : virtual OGRFeatureDefn *GetLayerDefn() { return poLayer->GetLayerDefn(); }
110 0 : virtual int GetFeatureCount( int bForce = TRUE ) { return poLayer->GetFeatureCount(bForce); }
111 0 : virtual int TestCapability( const char * pszCap ) { return poLayer->TestCapability(pszCap); }
112 : };
113 :
114 :
115 : /************************************************************************/
116 : /* OGRWFSDataSource() */
117 : /************************************************************************/
118 :
119 226 : OGRWFSDataSource::OGRWFSDataSource()
120 :
121 : {
122 226 : papoLayers = NULL;
123 226 : nLayers = 0;
124 :
125 226 : pszName = NULL;
126 :
127 226 : bUpdate = FALSE;
128 226 : bGetFeatureSupportHits = FALSE;
129 226 : bNeedNAMESPACE = FALSE;
130 226 : bHasMinOperators = FALSE;
131 226 : bHasNullCheck = FALSE;
132 226 : bPropertyIsNotEqualToSupported = TRUE; /* advertized by deegree but not implemented */
133 226 : bTransactionSupport = FALSE;
134 226 : papszIdGenMethods = NULL;
135 226 : bUseFeatureId = FALSE; /* CubeWerx doesn't like GmlObjectId */
136 226 : bGmlObjectIdNeedsGMLPrefix = FALSE;
137 226 : bRequiresEnvelopeSpatialFilter = FALSE;
138 :
139 226 : bRewriteFile = FALSE;
140 226 : psFileXML = NULL;
141 :
142 226 : bUseHttp10 = FALSE;
143 226 : papszHttpOptions = NULL;
144 :
145 226 : bPagingAllowed = CSLTestBoolean(CPLGetConfigOption("OGR_WFS_PAGING_ALLOWED", "OFF"));
146 226 : nPageSize = 0;
147 226 : if (bPagingAllowed)
148 : {
149 0 : nPageSize = atoi(CPLGetConfigOption("OGR_WFS_PAGE_SIZE", "100"));
150 0 : if (nPageSize <= 0)
151 0 : nPageSize = 100;
152 : }
153 :
154 226 : bIsGEOSERVER = FALSE;
155 :
156 226 : bLoadMultipleLayerDefn = CSLTestBoolean(CPLGetConfigOption("OGR_WFS_LOAD_MULTIPLE_LAYER_DEFN", "TRUE"));
157 :
158 226 : poLayerMetadataDS = NULL;
159 226 : poLayerMetadataLayer = NULL;
160 :
161 226 : poLayerGetCapabilitiesDS = NULL;
162 226 : poLayerGetCapabilitiesLayer = NULL;
163 :
164 226 : bKeepLayerNamePrefix = FALSE;
165 226 : }
166 :
167 : /************************************************************************/
168 : /* ~OGRWFSDataSource() */
169 : /************************************************************************/
170 :
171 226 : OGRWFSDataSource::~OGRWFSDataSource()
172 :
173 : {
174 226 : if (psFileXML)
175 : {
176 2 : if (bRewriteFile)
177 : {
178 0 : CPLSerializeXMLTreeToFile(psFileXML, pszName);
179 : }
180 :
181 2 : CPLDestroyXMLNode(psFileXML);
182 : }
183 :
184 : int i;
185 720 : for( i = 0; i < nLayers; i++ )
186 494 : delete papoLayers[i];
187 226 : CPLFree( papoLayers );
188 :
189 226 : if (osLayerMetadataTmpFileName.size() != 0)
190 2 : VSIUnlink(osLayerMetadataTmpFileName);
191 226 : delete poLayerMetadataDS;
192 226 : delete poLayerGetCapabilitiesDS;
193 :
194 226 : CPLFree( pszName );
195 226 : CSLDestroy( papszIdGenMethods );
196 226 : CSLDestroy( papszHttpOptions );
197 226 : }
198 :
199 : /************************************************************************/
200 : /* TestCapability() */
201 : /************************************************************************/
202 :
203 2 : int OGRWFSDataSource::TestCapability( const char * pszCap )
204 :
205 : {
206 2 : return FALSE;
207 : }
208 :
209 : /************************************************************************/
210 : /* GetLayer() */
211 : /************************************************************************/
212 :
213 10 : OGRLayer *OGRWFSDataSource::GetLayer( int iLayer )
214 :
215 : {
216 10 : if( iLayer < 0 || iLayer >= nLayers )
217 4 : return NULL;
218 : else
219 6 : return papoLayers[iLayer];
220 : }
221 :
222 : /************************************************************************/
223 : /* GetLayerByName() */
224 : /************************************************************************/
225 :
226 120 : OGRLayer* OGRWFSDataSource::GetLayerByName(const char* pszName)
227 : {
228 120 : if ( ! pszName )
229 0 : return NULL;
230 :
231 120 : if (EQUAL(pszName, "WFSLayerMetadata"))
232 : {
233 2 : if (osLayerMetadataTmpFileName.size() != 0)
234 0 : return poLayerMetadataLayer;
235 :
236 2 : osLayerMetadataTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/WFSLayerMetadata.csv", this);
237 4 : osLayerMetadataCSV = "layer_name,title,abstract\n" + osLayerMetadataCSV;
238 :
239 : VSIFCloseL(VSIFileFromMemBuffer(osLayerMetadataTmpFileName,
240 : (GByte*) osLayerMetadataCSV.c_str(),
241 2 : osLayerMetadataCSV.size(), FALSE));
242 : poLayerMetadataDS = (OGRDataSource*) OGROpen(osLayerMetadataTmpFileName,
243 2 : FALSE, NULL);
244 2 : if (poLayerMetadataDS)
245 2 : poLayerMetadataLayer = poLayerMetadataDS->GetLayer(0);
246 2 : return poLayerMetadataLayer;
247 : }
248 118 : else if (EQUAL(pszName, "WFSGetCapabilities"))
249 : {
250 2 : if (poLayerGetCapabilitiesLayer != NULL)
251 0 : return poLayerGetCapabilitiesLayer;
252 :
253 2 : OGRSFDriver* poMEMDrv = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("Memory");
254 2 : if (poMEMDrv == NULL)
255 : {
256 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot load 'Memory' driver");
257 0 : return NULL;
258 : }
259 :
260 2 : poLayerGetCapabilitiesDS = poMEMDrv->CreateDataSource("WFSGetCapabilities", NULL);
261 2 : poLayerGetCapabilitiesLayer = poLayerGetCapabilitiesDS->CreateLayer("WFSGetCapabilities", NULL, wkbNone, NULL);
262 2 : OGRFieldDefn oFDefn("content", OFTString);
263 2 : poLayerGetCapabilitiesLayer->CreateField(&oFDefn);
264 2 : OGRFeature* poFeature = new OGRFeature(poLayerGetCapabilitiesLayer->GetLayerDefn());
265 4 : poFeature->SetField(0, osGetCapabilities);
266 2 : poLayerGetCapabilitiesLayer->CreateFeature(poFeature);
267 2 : delete poFeature;
268 :
269 2 : return poLayerGetCapabilitiesLayer;
270 : }
271 :
272 116 : int nIndex = GetLayerIndex(pszName);
273 116 : if (nIndex < 0)
274 2 : return NULL;
275 : else
276 114 : return papoLayers[nIndex];
277 : }
278 :
279 :
280 : /************************************************************************/
281 : /* GetLayerIndex() */
282 : /************************************************************************/
283 :
284 120 : int OGRWFSDataSource::GetLayerIndex(const char* pszName)
285 : {
286 : int i;
287 120 : int bHasFoundLayerWithColon = FALSE;
288 :
289 : /* first a case sensitive check */
290 1460 : for( i = 0; i < nLayers; i++ )
291 : {
292 1386 : OGRWFSLayer *poLayer = papoLayers[i];
293 :
294 1386 : if( strcmp( pszName, poLayer->GetName() ) == 0 )
295 46 : return i;
296 :
297 1340 : bHasFoundLayerWithColon |= (strchr( poLayer->GetName(), ':') != NULL);
298 : }
299 :
300 : /* then case insensitive */
301 1402 : for( i = 0; i < nLayers; i++ )
302 : {
303 1328 : OGRWFSLayer *poLayer = papoLayers[i];
304 :
305 1328 : if( EQUAL( pszName, poLayer->GetName() ) )
306 0 : return i;
307 : }
308 :
309 : /* now try looking after the colon character */
310 74 : if (!bKeepLayerNamePrefix && bHasFoundLayerWithColon && strchr(pszName, ':') == NULL)
311 : {
312 684 : for( i = 0; i < nLayers; i++ )
313 : {
314 684 : OGRWFSLayer *poLayer = papoLayers[i];
315 :
316 684 : const char* pszAfterColon = strchr( poLayer->GetName(), ':');
317 684 : if( pszAfterColon && EQUAL( pszName, pszAfterColon + 1 ) )
318 72 : return i;
319 : }
320 : }
321 :
322 2 : return -1;
323 : }
324 :
325 : /************************************************************************/
326 : /* FindSubStringInsensitive() */
327 : /************************************************************************/
328 :
329 400 : const char* FindSubStringInsensitive(const char* pszStr,
330 : const char* pszSubStr)
331 : {
332 400 : size_t nSubStrPos = CPLString(pszStr).ifind(pszSubStr);
333 400 : if (nSubStrPos == std::string::npos)
334 400 : return NULL;
335 0 : return pszStr + nSubStrPos;
336 : }
337 :
338 : /************************************************************************/
339 : /* DetectIfGetFeatureSupportHits() */
340 : /************************************************************************/
341 :
342 16 : static int DetectIfGetFeatureSupportHits(CPLXMLNode* psRoot)
343 : {
344 : CPLXMLNode* psOperationsMetadata =
345 16 : CPLGetXMLNode(psRoot, "OperationsMetadata");
346 16 : if (!psOperationsMetadata)
347 : {
348 0 : CPLDebug("WFS", "Could not find <OperationsMetadata>");
349 0 : return FALSE;
350 : }
351 :
352 16 : CPLXMLNode* psChild = psOperationsMetadata->psChild;
353 64 : while(psChild)
354 : {
355 48 : if (psChild->eType == CXT_Element &&
356 : strcmp(psChild->pszValue, "Operation") == 0 &&
357 : strcmp(CPLGetXMLValue(psChild, "name", ""), "GetFeature") == 0)
358 : {
359 16 : break;
360 : }
361 32 : psChild = psChild->psNext;
362 : }
363 16 : if (!psChild)
364 : {
365 0 : CPLDebug("WFS", "Could not find <Operation name=\"GetFeature\">");
366 0 : return FALSE;
367 : }
368 :
369 16 : psChild = psChild->psChild;
370 66 : while(psChild)
371 : {
372 44 : if (psChild->eType == CXT_Element &&
373 : strcmp(psChild->pszValue, "Parameter") == 0 &&
374 : strcmp(CPLGetXMLValue(psChild, "name", ""), "resultType") == 0)
375 : {
376 10 : break;
377 : }
378 34 : psChild = psChild->psNext;
379 : }
380 16 : if (!psChild)
381 : {
382 6 : CPLDebug("WFS", "Could not find <Parameter name=\"resultType\">");
383 6 : return FALSE;
384 : }
385 :
386 10 : psChild = psChild->psChild;
387 40 : while(psChild)
388 : {
389 26 : if (psChild->eType == CXT_Element &&
390 : strcmp(psChild->pszValue, "Value") == 0)
391 : {
392 16 : CPLXMLNode* psChild2 = psChild->psChild;
393 42 : while(psChild2)
394 : {
395 16 : if (psChild2->eType == CXT_Text &&
396 : strcmp(psChild2->pszValue, "hits") == 0)
397 : {
398 6 : CPLDebug("WFS", "GetFeature operation supports hits");
399 6 : return TRUE;
400 : }
401 10 : psChild2 = psChild2->psNext;
402 : }
403 : }
404 20 : psChild = psChild->psNext;
405 : }
406 :
407 4 : return FALSE;
408 : }
409 :
410 : /************************************************************************/
411 : /* DetectRequiresEnvelopeSpatialFilter() */
412 : /************************************************************************/
413 :
414 18 : int OGRWFSDataSource::DetectRequiresEnvelopeSpatialFilter(CPLXMLNode* psRoot)
415 : {
416 : /* This is a heuristic to detect Deegree 3 servers, such as */
417 : /* http://deegree3-demo.deegree.org:80/deegree-utah-demo/services */
418 : /* that are very GML3 strict, and don't like <gml:Box> in a <Filter><BBOX> */
419 : /* request, but requires instead <gml:Envelope>, but some servers (such as MapServer) */
420 : /* don't like <gml:Envelope> so we are obliged to detect the kind of server */
421 :
422 : int nCount;
423 : CPLXMLNode* psChild;
424 :
425 : CPLXMLNode* psGeometryOperands =
426 18 : CPLGetXMLNode(psRoot, "Filter_Capabilities.Spatial_Capabilities.GeometryOperands");
427 18 : if (!psGeometryOperands)
428 : {
429 0 : return FALSE;
430 : }
431 :
432 18 : nCount = 0;
433 18 : psChild = psGeometryOperands->psChild;
434 168 : while(psChild)
435 : {
436 132 : nCount ++;
437 132 : psChild = psChild->psNext;
438 : }
439 : /* Magic number... Might be fragile */
440 18 : return (nCount == 19);
441 : }
442 :
443 : /************************************************************************/
444 : /* GetPostTransactionURL() */
445 : /************************************************************************/
446 :
447 0 : CPLString OGRWFSDataSource::GetPostTransactionURL()
448 : {
449 0 : if (osPostTransactionURL.size())
450 0 : return osPostTransactionURL;
451 :
452 0 : osPostTransactionURL = osBaseURL;
453 0 : const char* pszPostTransactionURL = osPostTransactionURL.c_str();
454 0 : const char* pszEsperluet = strchr(pszPostTransactionURL, '?');
455 0 : if (pszEsperluet)
456 0 : osPostTransactionURL.resize(pszEsperluet - pszPostTransactionURL);
457 :
458 0 : return osPostTransactionURL;
459 : }
460 :
461 : /************************************************************************/
462 : /* DetectTransactionSupport() */
463 : /************************************************************************/
464 :
465 18 : int OGRWFSDataSource::DetectTransactionSupport(CPLXMLNode* psRoot)
466 : {
467 : CPLXMLNode* psTransactionWFS100 =
468 18 : CPLGetXMLNode(psRoot, "Capability.Request.Transaction");
469 18 : if (psTransactionWFS100)
470 : {
471 0 : CPLXMLNode* psPostURL = CPLGetXMLNode(psTransactionWFS100, "DCPType.HTTP.Post");
472 0 : if (psPostURL)
473 : {
474 0 : const char* pszPOSTURL = CPLGetXMLValue(psPostURL, "onlineResource", NULL);
475 0 : if (pszPOSTURL)
476 : {
477 0 : osPostTransactionURL = pszPOSTURL;
478 : }
479 : }
480 :
481 0 : bTransactionSupport = TRUE;
482 0 : return TRUE;
483 : }
484 :
485 : CPLXMLNode* psOperationsMetadata =
486 18 : CPLGetXMLNode(psRoot, "OperationsMetadata");
487 18 : if (!psOperationsMetadata)
488 : {
489 0 : return FALSE;
490 : }
491 :
492 18 : CPLXMLNode* psChild = psOperationsMetadata->psChild;
493 148 : while(psChild)
494 : {
495 122 : if (psChild->eType == CXT_Element &&
496 : strcmp(psChild->pszValue, "Operation") == 0 &&
497 : strcmp(CPLGetXMLValue(psChild, "name", ""), "Transaction") == 0)
498 : {
499 10 : break;
500 : }
501 112 : psChild = psChild->psNext;
502 : }
503 18 : if (!psChild)
504 : {
505 8 : CPLDebug("WFS", "No transaction support");
506 8 : return FALSE;
507 : }
508 :
509 10 : bTransactionSupport = TRUE;
510 10 : CPLDebug("WFS", "Transaction support !");
511 :
512 :
513 10 : CPLXMLNode* psPostURL = CPLGetXMLNode(psChild, "DCP.HTTP.Post");
514 10 : if (psPostURL)
515 : {
516 8 : const char* pszPOSTURL = CPLGetXMLValue(psPostURL, "href", NULL);
517 8 : if (pszPOSTURL)
518 8 : osPostTransactionURL = pszPOSTURL;
519 : }
520 :
521 10 : psChild = psChild->psChild;
522 52 : while(psChild)
523 : {
524 42 : if (psChild->eType == CXT_Element &&
525 : strcmp(psChild->pszValue, "Parameter") == 0 &&
526 : strcmp(CPLGetXMLValue(psChild, "name", ""), "idgen") == 0)
527 : {
528 10 : break;
529 : }
530 32 : psChild = psChild->psNext;
531 : }
532 10 : if (!psChild)
533 : {
534 0 : papszIdGenMethods = CSLAddString(NULL, "GenerateNew");
535 0 : return TRUE;
536 : }
537 :
538 10 : psChild = psChild->psChild;
539 52 : while(psChild)
540 : {
541 32 : if (psChild->eType == CXT_Element &&
542 : strcmp(psChild->pszValue, "Value") == 0)
543 : {
544 22 : CPLXMLNode* psChild2 = psChild->psChild;
545 66 : while(psChild2)
546 : {
547 22 : if (psChild2->eType == CXT_Text)
548 : {
549 : papszIdGenMethods = CSLAddString(papszIdGenMethods,
550 22 : psChild2->pszValue);
551 : }
552 22 : psChild2 = psChild2->psNext;
553 : }
554 : }
555 32 : psChild = psChild->psNext;
556 : }
557 :
558 10 : return TRUE;
559 : }
560 :
561 : /************************************************************************/
562 : /* FindComparisonOperator() */
563 : /************************************************************************/
564 :
565 150 : static int FindComparisonOperator(CPLXMLNode* psNode, const char* pszVal)
566 : {
567 150 : CPLXMLNode* psChild = psNode->psChild;
568 910 : while(psChild)
569 : {
570 750 : if (psChild->eType == CXT_Element &&
571 : strcmp(psChild->pszValue, "ComparisonOperator") == 0)
572 : {
573 750 : if (strcmp(CPLGetXMLValue(psChild, NULL, ""), pszVal) == 0)
574 124 : return TRUE;
575 :
576 : /* For WFS 2.0.0 */
577 626 : const char* pszName = CPLGetXMLValue(psChild, "name", NULL);
578 626 : if (pszName != NULL && strncmp(pszName, "PropertyIs", 10) == 0 &&
579 : strcmp(pszName + 10, pszVal) == 0)
580 16 : return TRUE;
581 : }
582 610 : psChild = psChild->psNext;
583 : }
584 10 : return FALSE;
585 : }
586 :
587 : /************************************************************************/
588 : /* LoadFromFile() */
589 : /************************************************************************/
590 :
591 226 : CPLXMLNode* OGRWFSDataSource::LoadFromFile( const char * pszFilename )
592 : {
593 : VSILFILE *fp;
594 : char achHeader[1024];
595 :
596 : VSIStatBufL sStatBuf;
597 226 : if (VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) != 0 ||
598 : VSI_ISDIR(sStatBuf.st_mode))
599 100 : return NULL;
600 :
601 126 : fp = VSIFOpenL( pszFilename, "rb" );
602 :
603 126 : if( fp == NULL )
604 0 : return NULL;
605 :
606 : int nRead;
607 126 : if( (nRead = VSIFReadL( achHeader, 1, sizeof(achHeader) - 1, fp )) == 0 )
608 : {
609 0 : VSIFCloseL( fp );
610 0 : return NULL;
611 : }
612 126 : achHeader[nRead] = 0;
613 :
614 126 : if( !EQUALN(achHeader,"<OGRWFSDataSource>",18) &&
615 : strstr(achHeader,"<WFS_Capabilities") == NULL &&
616 : strstr(achHeader,"<wfs:WFS_Capabilities") == NULL)
617 : {
618 124 : VSIFCloseL( fp );
619 124 : return NULL;
620 : }
621 :
622 : /* -------------------------------------------------------------------- */
623 : /* It is the right file, now load the full XML definition. */
624 : /* -------------------------------------------------------------------- */
625 : int nLen;
626 :
627 2 : VSIFSeekL( fp, 0, SEEK_END );
628 2 : nLen = (int) VSIFTellL( fp );
629 2 : VSIFSeekL( fp, 0, SEEK_SET );
630 :
631 2 : char* pszXML = (char *) VSIMalloc(nLen+1);
632 2 : if (pszXML == NULL)
633 : {
634 0 : VSIFCloseL( fp );
635 0 : return NULL;
636 : }
637 2 : pszXML[nLen] = '\0';
638 2 : if( ((int) VSIFReadL( pszXML, 1, nLen, fp )) != nLen )
639 : {
640 0 : CPLFree( pszXML );
641 0 : VSIFCloseL( fp );
642 :
643 0 : return NULL;
644 : }
645 2 : VSIFCloseL( fp );
646 :
647 2 : if (strstr(pszXML, "CubeWerx"))
648 : {
649 : /* At least true for CubeWerx Suite 4.15.1 */
650 0 : bUseFeatureId = TRUE;
651 : }
652 2 : else if (strstr(pszXML, "deegree"))
653 : {
654 0 : bGmlObjectIdNeedsGMLPrefix = TRUE;
655 : }
656 :
657 2 : CPLXMLNode* psXML = CPLParseXMLString( pszXML );
658 2 : CPLFree( pszXML );
659 :
660 2 : return psXML;
661 : }
662 :
663 : /************************************************************************/
664 : /* SendGetCapabilities() */
665 : /************************************************************************/
666 :
667 16 : CPLHTTPResult* OGRWFSDataSource::SendGetCapabilities(const char* pszBaseURL,
668 : CPLString& osTypeName)
669 : {
670 16 : CPLString osURL(pszBaseURL);
671 16 : osURL = CPLURLAddKVP(osURL, "SERVICE", "WFS");
672 16 : osURL = CPLURLAddKVP(osURL, "REQUEST", "GetCapabilities");
673 16 : osTypeName = CPLURLGetValue(osURL, "TYPENAME");
674 16 : osURL = CPLURLAddKVP(osURL, "TYPENAME", NULL);
675 16 : osURL = CPLURLAddKVP(osURL, "FILTER", NULL);
676 16 : osURL = CPLURLAddKVP(osURL, "PROPERTYNAME", NULL);
677 16 : osURL = CPLURLAddKVP(osURL, "MAXFEATURES", NULL);
678 16 : osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", NULL);
679 :
680 : /* Don't accept WFS 2.0.0 for now, unless explicitely specified */
681 16 : if (CPLURLGetValue(osURL, "ACCEPTVERSIONS").size() == 0 &&
682 : CPLURLGetValue(osURL, "VERSION").size() == 0)
683 14 : osURL = CPLURLAddKVP(osURL, "ACCEPTVERSIONS", "1.1.0,1.0.0");
684 :
685 16 : CPLDebug("WFS", "%s", osURL.c_str());
686 :
687 16 : CPLHTTPResult* psResult = HTTPFetch( osURL, NULL);
688 16 : if (psResult == NULL)
689 : {
690 0 : return NULL;
691 : }
692 :
693 16 : if (strstr((const char*)psResult->pabyData,
694 : "<ServiceExceptionReport") != NULL ||
695 : strstr((const char*)psResult->pabyData,
696 : "<ows:ExceptionReport") != NULL)
697 : {
698 : CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
699 0 : psResult->pabyData);
700 0 : CPLHTTPDestroyResult(psResult);
701 0 : return NULL;
702 : }
703 :
704 16 : return psResult;
705 : }
706 :
707 : /************************************************************************/
708 : /* Open() */
709 : /************************************************************************/
710 :
711 226 : int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn)
712 :
713 : {
714 226 : bUpdate = bUpdateIn;
715 226 : CPLFree(pszName);
716 226 : pszName = CPLStrdup(pszFilename);
717 :
718 226 : CPLXMLNode* psWFSCapabilities = NULL;
719 226 : CPLXMLNode* psXML = LoadFromFile(pszFilename);
720 226 : CPLString osTypeName;
721 226 : const char* pszBaseURL = NULL;
722 :
723 226 : if (psXML == NULL)
724 : {
725 224 : if (!EQUALN(pszFilename, "WFS:", 4) &&
726 : FindSubStringInsensitive(pszFilename, "SERVICE=WFS") == NULL)
727 : {
728 208 : return FALSE;
729 : }
730 :
731 16 : pszBaseURL = pszFilename;
732 16 : if (EQUALN(pszFilename, "WFS:", 4))
733 16 : pszBaseURL += 4;
734 :
735 16 : osBaseURL = pszBaseURL;
736 :
737 16 : if (strncmp(pszBaseURL, "http://", 7) != 0 &&
738 : strncmp(pszBaseURL, "https://", 8) != 0)
739 0 : return FALSE;
740 :
741 : CPLHTTPResult* psResult = SendGetCapabilities(pszBaseURL,
742 16 : osTypeName);
743 16 : if (psResult == NULL)
744 : {
745 0 : return FALSE;
746 : }
747 :
748 16 : if (strstr((const char*) psResult->pabyData, "CubeWerx"))
749 : {
750 : /* At least true for CubeWerx Suite 4.15.1 */
751 0 : bUseFeatureId = TRUE;
752 : }
753 16 : else if (strstr((const char*) psResult->pabyData, "deegree"))
754 : {
755 12 : bGmlObjectIdNeedsGMLPrefix = TRUE;
756 : }
757 :
758 16 : psXML = CPLParseXMLString( (const char*) psResult->pabyData );
759 16 : if (psXML == NULL)
760 : {
761 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
762 0 : psResult->pabyData);
763 0 : CPLHTTPDestroyResult(psResult);
764 0 : return FALSE;
765 : }
766 16 : osGetCapabilities = (const char*) psResult->pabyData;
767 :
768 16 : CPLHTTPDestroyResult(psResult);
769 : }
770 2 : else if ( WFSFindNode( psXML, "OGRWFSDataSource" ) == NULL &&
771 : WFSFindNode( psXML, "WFS_Capabilities" ) != NULL )
772 : {
773 : /* This is directly the Capabilities document */
774 0 : char* pszXML = CPLSerializeXMLTree(WFSFindNode( psXML, "WFS_Capabilities" ));
775 0 : osGetCapabilities = pszXML;
776 0 : CPLFree(pszXML);
777 : }
778 : else
779 : {
780 2 : CPLXMLNode* psRoot = WFSFindNode( psXML, "OGRWFSDataSource" );
781 2 : if (psRoot == NULL)
782 : {
783 : CPLError(CE_Failure, CPLE_AppDefined,
784 0 : "Cannot find <OGRWFSDataSource>");
785 0 : CPLDestroyXMLNode( psXML );
786 0 : return FALSE;
787 : }
788 :
789 2 : pszBaseURL = CPLGetXMLValue(psRoot, "URL", NULL);
790 2 : if (pszBaseURL == NULL)
791 : {
792 : CPLError(CE_Failure, CPLE_AppDefined,
793 0 : "Cannot find <URL>");
794 0 : CPLDestroyXMLNode( psXML );
795 0 : return FALSE;
796 : }
797 2 : osBaseURL = pszBaseURL;
798 :
799 : /* -------------------------------------------------------------------- */
800 : /* Capture other parameters. */
801 : /* -------------------------------------------------------------------- */
802 : const char *pszParm;
803 :
804 2 : pszParm = CPLGetXMLValue( psRoot, "Timeout", NULL );
805 2 : if( pszParm )
806 : papszHttpOptions =
807 : CSLSetNameValue(papszHttpOptions,
808 0 : "TIMEOUT", pszParm );
809 :
810 2 : pszParm = CPLGetXMLValue( psRoot, "HTTPAUTH", NULL );
811 2 : if( pszParm )
812 : papszHttpOptions =
813 : CSLSetNameValue( papszHttpOptions,
814 0 : "HTTPAUTH", pszParm );
815 :
816 2 : pszParm = CPLGetXMLValue( psRoot, "USERPWD", NULL );
817 2 : if( pszParm )
818 : papszHttpOptions =
819 : CSLSetNameValue( papszHttpOptions,
820 0 : "USERPWD", pszParm );
821 :
822 2 : pszParm = CPLGetXMLValue( psRoot, "Version", NULL );
823 2 : if( pszParm )
824 0 : osVersion = pszParm;
825 :
826 2 : pszParm = CPLGetXMLValue( psRoot, "PagingAllowed", NULL );
827 2 : if( pszParm )
828 0 : bPagingAllowed = CSLTestBoolean(pszParm);
829 :
830 2 : pszParm = CPLGetXMLValue( psRoot, "PageSize", NULL );
831 2 : if( pszParm )
832 : {
833 0 : nPageSize = atoi(pszParm);
834 0 : if (nPageSize <= 0)
835 0 : nPageSize = 100;
836 : }
837 :
838 2 : osTypeName = CPLURLGetValue(pszBaseURL, "TYPENAME");
839 :
840 2 : psWFSCapabilities = WFSFindNode( psRoot, "WFS_Capabilities" );
841 2 : if (psWFSCapabilities == NULL)
842 : {
843 : CPLHTTPResult* psResult = SendGetCapabilities(pszBaseURL,
844 0 : osTypeName);
845 0 : if (psResult == NULL)
846 : {
847 0 : CPLDestroyXMLNode( psXML );
848 0 : return FALSE;
849 : }
850 :
851 0 : CPLXMLNode* psXML2 = CPLParseXMLString( (const char*) psResult->pabyData );
852 0 : if (psXML2 == NULL)
853 : {
854 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
855 0 : psResult->pabyData);
856 0 : CPLHTTPDestroyResult(psResult);
857 0 : CPLDestroyXMLNode( psXML );
858 0 : return FALSE;
859 : }
860 :
861 0 : CPLHTTPDestroyResult(psResult);
862 :
863 0 : psWFSCapabilities = WFSFindNode( psXML2, "WFS_Capabilities" );
864 0 : if (psWFSCapabilities == NULL )
865 : {
866 : CPLError(CE_Failure, CPLE_AppDefined,
867 0 : "Cannot find <WFS_Capabilities>");
868 0 : CPLDestroyXMLNode( psXML );
869 0 : CPLDestroyXMLNode( psXML2 );
870 0 : return FALSE;
871 : }
872 :
873 0 : CPLAddXMLChild(psXML, CPLCloneXMLTree(psWFSCapabilities));
874 :
875 0 : int bOK = CPLSerializeXMLTreeToFile(psXML, pszFilename);
876 :
877 0 : CPLDestroyXMLNode( psXML );
878 0 : CPLDestroyXMLNode( psXML2 );
879 :
880 0 : if (bOK)
881 0 : return Open(pszFilename, bUpdate);
882 : else
883 0 : return FALSE;
884 : }
885 : else
886 : {
887 2 : psFileXML = psXML;
888 :
889 : /* To avoid to have nodes after WFSCapabilities */
890 2 : CPLXMLNode* psAfterWFSCapabilities = psWFSCapabilities->psNext;
891 2 : psWFSCapabilities->psNext = NULL;
892 2 : char* pszXML = CPLSerializeXMLTree(psWFSCapabilities);
893 2 : psWFSCapabilities->psNext = psAfterWFSCapabilities;
894 2 : osGetCapabilities = pszXML;
895 2 : CPLFree(pszXML);
896 : }
897 : }
898 :
899 : int bInvertAxisOrderIfLatLong = CSLTestBoolean(CPLGetConfigOption(
900 18 : "GML_INVERT_AXIS_ORDER_IF_LAT_LONG", "YES"));
901 :
902 18 : CPLXMLNode* psStrippedXML = CPLCloneXMLTree(psXML);
903 18 : CPLStripXMLNamespace( psStrippedXML, NULL, TRUE );
904 18 : psWFSCapabilities = CPLGetXMLNode( psStrippedXML, "=WFS_Capabilities" );
905 18 : if (psWFSCapabilities == NULL)
906 : {
907 2 : psWFSCapabilities = CPLGetXMLNode( psStrippedXML, "=OGRWFSDataSource.WFS_Capabilities" );
908 : }
909 18 : if (psWFSCapabilities == NULL)
910 : {
911 : CPLError(CE_Failure, CPLE_AppDefined,
912 0 : "Cannot find <WFS_Capabilities>");
913 0 : if (!psFileXML) CPLDestroyXMLNode( psXML );
914 0 : CPLDestroyXMLNode( psStrippedXML );
915 0 : return FALSE;
916 : }
917 :
918 18 : if (pszBaseURL == NULL)
919 : {
920 : /* This is directly the Capabilities document */
921 0 : pszBaseURL = CPLGetXMLValue( psWFSCapabilities, "OperationsMetadata.Operation.DCP.HTTP.Get.href", NULL );
922 0 : if (pszBaseURL == NULL) /* WFS 1.0.0 variant */
923 0 : pszBaseURL = CPLGetXMLValue( psWFSCapabilities, "Capability.Request.GetCapabilities.DCPType.HTTP.Get.onlineResource", NULL );
924 :
925 0 : if (pszBaseURL == NULL)
926 : {
927 : CPLError(CE_Failure, CPLE_AppDefined,
928 0 : "Cannot find base URL");
929 0 : CPLDestroyXMLNode( psStrippedXML );
930 0 : return FALSE;
931 : }
932 :
933 0 : osBaseURL = pszBaseURL;
934 : }
935 :
936 18 : if (osVersion.size() == 0)
937 18 : osVersion = CPLGetXMLValue(psWFSCapabilities, "version", "1.0.0");
938 18 : if (strcmp(osVersion.c_str(), "1.0.0") == 0)
939 0 : bUseFeatureId = TRUE;
940 : else
941 : {
942 : /* Some servers happen to support RESULTTYPE=hits in 1.0.0, but there */
943 : /* is no way to advertisze this */
944 18 : if (atoi(osVersion) >= 2)
945 2 : bGetFeatureSupportHits = TRUE; /* WFS >= 2.0.0 supports hits */
946 : else
947 16 : bGetFeatureSupportHits = DetectIfGetFeatureSupportHits(psWFSCapabilities);
948 18 : bRequiresEnvelopeSpatialFilter = DetectRequiresEnvelopeSpatialFilter(psWFSCapabilities);
949 : }
950 :
951 18 : DetectTransactionSupport(psWFSCapabilities);
952 :
953 : /* Detect if server is GEOSERVER */
954 18 : CPLXMLNode* psKeywords = CPLGetXMLNode(psWFSCapabilities, "ServiceIdentification.Keywords");
955 18 : if (psKeywords)
956 : {
957 6 : CPLXMLNode* psKeyword = psKeywords->psChild;
958 36 : for(;psKeyword != NULL;psKeyword=psKeyword->psNext)
959 : {
960 30 : if (psKeyword->eType == CXT_Element &&
961 : psKeyword->pszValue != NULL &&
962 : EQUAL(psKeyword->pszValue, "Keyword") &&
963 : psKeyword->psChild != NULL &&
964 : psKeyword->psChild->pszValue != NULL &&
965 : EQUALN(psKeyword->psChild->pszValue, "GEOSERVER", 9))
966 : {
967 0 : bIsGEOSERVER = TRUE;
968 0 : break;
969 : }
970 : }
971 : }
972 :
973 18 : if (bUpdate && !bTransactionSupport)
974 : {
975 : CPLError(CE_Failure, CPLE_AppDefined,
976 0 : "Server is read-only WFS; no WFS-T feature advertized");
977 0 : if (!psFileXML) CPLDestroyXMLNode( psXML );
978 0 : CPLDestroyXMLNode( psStrippedXML );
979 0 : return FALSE;
980 : }
981 :
982 18 : CPLXMLNode* psFilterCap = CPLGetXMLNode(psWFSCapabilities, "Filter_Capabilities.Scalar_Capabilities");
983 18 : if (psFilterCap)
984 : {
985 : bHasMinOperators = CPLGetXMLNode(psFilterCap, "LogicalOperators") != NULL ||
986 18 : CPLGetXMLNode(psFilterCap, "Logical_Operators") != NULL;
987 18 : if (CPLGetXMLNode(psFilterCap, "ComparisonOperators"))
988 18 : psFilterCap = CPLGetXMLNode(psFilterCap, "ComparisonOperators");
989 0 : else if (CPLGetXMLNode(psFilterCap, "Comparison_Operators"))
990 0 : psFilterCap = CPLGetXMLNode(psFilterCap, "Comparison_Operators");
991 : else
992 0 : psFilterCap = NULL;
993 18 : if (psFilterCap)
994 : {
995 18 : if (CPLGetXMLNode(psFilterCap, "Simple_Comparisons") == NULL)
996 : {
997 18 : bHasMinOperators &= FindComparisonOperator(psFilterCap, "LessThan");
998 18 : bHasMinOperators &= FindComparisonOperator(psFilterCap, "GreaterThan");
999 18 : if (atoi(osVersion) >= 2)
1000 : {
1001 2 : bHasMinOperators &= FindComparisonOperator(psFilterCap, "LessThanOrEqualTo");
1002 2 : bHasMinOperators &= FindComparisonOperator(psFilterCap, "GreaterThanOrEqualTo");
1003 : }
1004 : else
1005 : {
1006 16 : bHasMinOperators &= FindComparisonOperator(psFilterCap, "LessThanEqualTo");
1007 16 : bHasMinOperators &= FindComparisonOperator(psFilterCap, "GreaterThanEqualTo");
1008 : }
1009 18 : bHasMinOperators &= FindComparisonOperator(psFilterCap, "EqualTo");
1010 18 : bHasMinOperators &= FindComparisonOperator(psFilterCap, "NotEqualTo");
1011 18 : bHasMinOperators &= FindComparisonOperator(psFilterCap, "Like");
1012 : }
1013 : else
1014 : {
1015 : bHasMinOperators &= CPLGetXMLNode(psFilterCap, "Simple_Comparisons") != NULL &&
1016 0 : CPLGetXMLNode(psFilterCap, "Like") != NULL;
1017 : }
1018 : bHasNullCheck = FindComparisonOperator(psFilterCap, "NullCheck") ||
1019 : FindComparisonOperator(psFilterCap, "Null") || /* WFS 2.0.0 */
1020 18 : CPLGetXMLNode(psFilterCap, "NullCheck") != NULL;
1021 : }
1022 : else
1023 : {
1024 0 : bHasMinOperators = FALSE;
1025 : }
1026 : }
1027 :
1028 18 : CPLXMLNode* psChild = CPLGetXMLNode(psWFSCapabilities, "FeatureTypeList");
1029 18 : if (psChild == NULL)
1030 : {
1031 : CPLError(CE_Failure, CPLE_AppDefined,
1032 0 : "Cannot find <FeatureTypeList>");
1033 0 : if (!psFileXML) CPLDestroyXMLNode( psXML );
1034 0 : CPLDestroyXMLNode( psStrippedXML );
1035 0 : return FALSE;
1036 : }
1037 :
1038 : CPLXMLNode* psChildIter;
1039 :
1040 : /* Check if there are layer names whose identical except their prefix */
1041 18 : std::set<CPLString> aosSetLayerNames;
1042 316 : for(psChildIter = psChild->psChild;
1043 : psChildIter != NULL;
1044 : psChildIter = psChildIter->psNext)
1045 : {
1046 306 : if (psChildIter->eType == CXT_Element &&
1047 : strcmp(psChildIter->pszValue, "FeatureType") == 0)
1048 : {
1049 300 : const char* pszName = CPLGetXMLValue(psChildIter, "Name", NULL);
1050 300 : if (pszName != NULL)
1051 : {
1052 300 : const char* pszShortName = strchr(pszName, ':');
1053 300 : if (pszShortName)
1054 288 : pszName = pszShortName + 1;
1055 300 : if (aosSetLayerNames.find(pszName) != aosSetLayerNames.end())
1056 : {
1057 8 : bKeepLayerNamePrefix = TRUE;
1058 8 : CPLDebug("WFS", "At least 2 layers have names that are only distinguishable by keeping the prefix");
1059 8 : break;
1060 : }
1061 292 : aosSetLayerNames.insert(pszName);
1062 : }
1063 : }
1064 : }
1065 :
1066 518 : for(psChildIter = psChild->psChild;
1067 : psChildIter != NULL;
1068 : psChildIter = psChildIter->psNext)
1069 : {
1070 500 : if (psChildIter->eType == CXT_Element &&
1071 : strcmp(psChildIter->pszValue, "FeatureType") == 0)
1072 : {
1073 494 : const char* pszNS = NULL;
1074 494 : const char* pszNSVal = NULL;
1075 494 : CPLXMLNode* psFeatureTypeIter = psChildIter->psChild;
1076 4178 : while(psFeatureTypeIter != NULL)
1077 : {
1078 3190 : if (psFeatureTypeIter->eType == CXT_Attribute)
1079 : {
1080 102 : pszNS = psFeatureTypeIter->pszValue;
1081 102 : pszNSVal = psFeatureTypeIter->psChild->pszValue;
1082 : }
1083 3190 : psFeatureTypeIter = psFeatureTypeIter->psNext;
1084 : }
1085 :
1086 494 : const char* pszName = CPLGetXMLValue(psChildIter, "Name", NULL);
1087 494 : const char* pszTitle = CPLGetXMLValue(psChildIter, "Title", NULL);
1088 494 : const char* pszAbstract = CPLGetXMLValue(psChildIter, "Abstract", NULL);
1089 494 : if (pszName != NULL &&
1090 : (osTypeName.size() == 0 ||
1091 : strcmp(osTypeName.c_str(), pszName) == 0))
1092 : {
1093 : const char* pszDefaultSRS =
1094 494 : CPLGetXMLValue(psChildIter, "DefaultSRS", NULL);
1095 494 : if (pszDefaultSRS == NULL)
1096 36 : pszDefaultSRS = CPLGetXMLValue(psChildIter, "SRS", NULL);
1097 494 : if (pszDefaultSRS == NULL)
1098 36 : pszDefaultSRS = CPLGetXMLValue(psChildIter, "DefaultCRS", NULL); /* WFS 2.0.0 */
1099 :
1100 494 : CPLXMLNode* psOutputFormats = CPLGetXMLNode(psChildIter, "OutputFormats");
1101 494 : CPLString osOutputFormat;
1102 494 : if (psOutputFormats)
1103 : {
1104 488 : std::vector<CPLString> osFormats;
1105 488 : CPLXMLNode* psOutputFormatIter = psOutputFormats->psChild;
1106 2626 : while(psOutputFormatIter)
1107 : {
1108 1650 : if (psOutputFormatIter->eType == CXT_Element &&
1109 : EQUAL(psOutputFormatIter->pszValue, "Format") &&
1110 : psOutputFormatIter->psChild != NULL &&
1111 : psOutputFormatIter->psChild->eType == CXT_Text)
1112 : {
1113 1306 : osFormats.push_back(psOutputFormatIter->psChild->pszValue);
1114 : }
1115 1650 : psOutputFormatIter = psOutputFormatIter->psNext;
1116 : }
1117 :
1118 488 : if (strcmp(osVersion.c_str(), "1.1.0") == 0 && osFormats.size() > 0)
1119 : {
1120 452 : int bFoundGML31 = FALSE;
1121 1146 : for(size_t i=0;i<osFormats.size();i++)
1122 : {
1123 838 : if (strstr(osFormats[i].c_str(), "3.1") != NULL)
1124 : {
1125 144 : bFoundGML31 = TRUE;
1126 144 : break;
1127 : }
1128 : }
1129 :
1130 : /* If we didn't find any mention to GML 3.1, then arbitrarily */
1131 : /* use the first output format */
1132 452 : if (!bFoundGML31)
1133 308 : osOutputFormat = osFormats[0].c_str();
1134 488 : }
1135 : }
1136 :
1137 494 : OGRSpatialReference* poSRS = NULL;
1138 494 : int bAxisOrderAlreadyInverted = FALSE;
1139 :
1140 : /* If a SRSNAME parameter has been encoded in the URL, use it as the SRS */
1141 494 : CPLString osSRSName = CPLURLGetValue(pszBaseURL, "SRSNAME");
1142 494 : if (osSRSName.size() != 0)
1143 : {
1144 0 : pszDefaultSRS = osSRSName.c_str();
1145 : }
1146 :
1147 494 : if (pszDefaultSRS)
1148 : {
1149 494 : OGRSpatialReference oSRS;
1150 494 : if (oSRS.SetFromUserInput(pszDefaultSRS) == OGRERR_NONE)
1151 : {
1152 494 : poSRS = oSRS.Clone();
1153 494 : if (bInvertAxisOrderIfLatLong &&
1154 : GML_IsSRSLatLongOrder(pszDefaultSRS))
1155 : {
1156 310 : bAxisOrderAlreadyInverted = TRUE;
1157 :
1158 : OGR_SRSNode *poGEOGCS =
1159 310 : poSRS->GetAttrNode( "GEOGCS" );
1160 310 : if( poGEOGCS != NULL )
1161 : {
1162 310 : poGEOGCS->StripNodes( "AXIS" );
1163 : }
1164 : }
1165 494 : }
1166 : }
1167 :
1168 494 : CPLXMLNode* psBBox = NULL;
1169 494 : CPLXMLNode* psLatLongBBox = NULL;
1170 494 : int bFoundBBox = FALSE;
1171 494 : double dfMinX = 0, dfMinY = 0, dfMaxX = 0, dfMaxY = 0;
1172 494 : if ((psBBox = CPLGetXMLNode(psChildIter, "WGS84BoundingBox")) != NULL)
1173 : {
1174 494 : const char* pszLC = CPLGetXMLValue(psBBox, "LowerCorner", NULL);
1175 494 : const char* pszUC = CPLGetXMLValue(psBBox, "UpperCorner", NULL);
1176 494 : if (pszLC != NULL && pszUC != NULL)
1177 : {
1178 494 : CPLString osConcat(pszLC);
1179 494 : osConcat += " ";
1180 494 : osConcat += pszUC;
1181 : char** papszTokens;
1182 : papszTokens = CSLTokenizeStringComplex(
1183 494 : osConcat, " ,", FALSE, FALSE );
1184 494 : if (CSLCount(papszTokens) == 4)
1185 : {
1186 494 : bFoundBBox = TRUE;
1187 494 : dfMinX = CPLAtof(papszTokens[0]);
1188 494 : dfMinY = CPLAtof(papszTokens[1]);
1189 494 : dfMaxX = CPLAtof(papszTokens[2]);
1190 494 : dfMaxY = CPLAtof(papszTokens[3]);
1191 : }
1192 494 : CSLDestroy(papszTokens);
1193 : }
1194 : }
1195 0 : else if ((psLatLongBBox = CPLGetXMLNode(psChildIter,
1196 : "LatLongBoundingBox")) != NULL)
1197 : {
1198 : const char* pszMinX =
1199 0 : CPLGetXMLValue(psLatLongBBox, "minx", NULL);
1200 : const char* pszMinY =
1201 0 : CPLGetXMLValue(psLatLongBBox, "miny", NULL);
1202 : const char* pszMaxX =
1203 0 : CPLGetXMLValue(psLatLongBBox, "maxx", NULL);
1204 : const char* pszMaxY =
1205 0 : CPLGetXMLValue(psLatLongBBox, "maxy", NULL);
1206 0 : if (pszMinX != NULL && pszMinY != NULL &&
1207 : pszMaxX != NULL && pszMaxY != NULL)
1208 : {
1209 0 : bFoundBBox = TRUE;
1210 0 : dfMinX = CPLAtof(pszMinX);
1211 0 : dfMinY = CPLAtof(pszMinY);
1212 0 : dfMaxX = CPLAtof(pszMaxX);
1213 0 : dfMaxY = CPLAtof(pszMaxY);
1214 : }
1215 : }
1216 :
1217 494 : osLayerMetadataCSV += "\"";
1218 494 : osLayerMetadataCSV += pszName;
1219 494 : osLayerMetadataCSV += "\"";
1220 494 : osLayerMetadataCSV += ",";
1221 494 : if (pszTitle)
1222 : {
1223 494 : osLayerMetadataCSV += "\"";
1224 494 : osLayerMetadataCSV += pszTitle;
1225 494 : osLayerMetadataCSV += "\"";
1226 : }
1227 494 : osLayerMetadataCSV += ",";
1228 494 : if (pszAbstract)
1229 : {
1230 14 : osLayerMetadataCSV += "\"";
1231 14 : osLayerMetadataCSV += pszAbstract;
1232 14 : osLayerMetadataCSV += "\"";
1233 : }
1234 494 : osLayerMetadataCSV += "\n";
1235 :
1236 : OGRWFSLayer* poLayer = new OGRWFSLayer(
1237 : this, poSRS, bAxisOrderAlreadyInverted,
1238 494 : pszBaseURL, pszName, pszNS, pszNSVal);
1239 988 : if (osOutputFormat.size())
1240 308 : poLayer->SetRequiredOutputFormat(osOutputFormat);
1241 :
1242 494 : if (poSRS)
1243 : {
1244 494 : char* pszProj4 = NULL;
1245 494 : if (poSRS->exportToProj4(&pszProj4) == OGRERR_NONE)
1246 : {
1247 : /* See http://trac.osgeo.org/gdal/ticket/4041 */
1248 : /* For now, we restrict to GEOSERVER as apparently the order is always longitude,latitude */
1249 : /* other servers might also qualify, so this should be relaxed */
1250 : /* Also accept when <wfs:DefaultCRS>urn:ogc:def:crs:OGC:1.3:CRS84</wfs:DefaultCRS> */
1251 494 : if ((bIsGEOSERVER &&
1252 : (strcmp(pszProj4, "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ") == 0 ||
1253 : strcmp(pszProj4, "+proj=longlat +datum=WGS84 +no_defs ") == 0)) ||
1254 : strcmp(pszDefaultSRS, "urn:ogc:def:crs:OGC:1.3:CRS84") == 0)
1255 : {
1256 0 : poLayer->SetExtents(dfMinX, dfMinY, dfMaxX, dfMaxY);
1257 : }
1258 : #if 0
1259 : else
1260 : {
1261 : OGRSpatialReference oWGS84;
1262 : oWGS84.SetWellKnownGeogCS("WGS84");
1263 : OGRCoordinateTransformation* poCT;
1264 : poCT = OGRCreateCoordinateTransformation(&oWGS84, poSRS);
1265 : if (poCT)
1266 : {
1267 : double dfULX = dfMinX;
1268 : double dfULY = dfMaxY;
1269 : double dfURX = dfMaxX;
1270 : double dfURY = dfMaxY;
1271 : double dfLLX = dfMinX;
1272 : double dfLLY = dfMinY;
1273 : double dfLRX = dfMaxX;
1274 : double dfLRY = dfMinY;
1275 : if (poCT->Transform(1, &dfULX, &dfULY, NULL) &&
1276 : poCT->Transform(1, &dfURX, &dfURY, NULL) &&
1277 : poCT->Transform(1, &dfLLX, &dfLLY, NULL) &&
1278 : poCT->Transform(1, &dfLRX, &dfLRY, NULL))
1279 : {
1280 : dfMinX = dfULX;
1281 : dfMinX = MIN(dfMinX, dfURX);
1282 : dfMinX = MIN(dfMinX, dfLLX);
1283 : dfMinX = MIN(dfMinX, dfLRX);
1284 :
1285 : dfMinY = dfULY;
1286 : dfMinY = MIN(dfMinY, dfURY);
1287 : dfMinY = MIN(dfMinY, dfLLY);
1288 : dfMinY = MIN(dfMinY, dfLRY);
1289 :
1290 : dfMaxX = dfULX;
1291 : dfMaxX = MAX(dfMaxX, dfURX);
1292 : dfMaxX = MAX(dfMaxX, dfLLX);
1293 : dfMaxX = MAX(dfMaxX, dfLRX);
1294 :
1295 : dfMaxY = dfULY;
1296 : dfMaxY = MAX(dfMaxY, dfURY);
1297 : dfMaxY = MAX(dfMaxY, dfLLY);
1298 : dfMaxY = MAX(dfMaxY, dfLRY);
1299 :
1300 : poLayer->SetExtents(dfMinX, dfMinY, dfMaxX, dfMaxY);
1301 : }
1302 : }
1303 : delete poCT;
1304 : }
1305 : #endif
1306 : }
1307 494 : CPLFree(pszProj4);
1308 : }
1309 :
1310 : papoLayers = (OGRWFSLayer **)CPLRealloc(papoLayers,
1311 494 : sizeof(OGRWFSLayer*) * (nLayers + 1));
1312 494 : papoLayers[nLayers ++] = poLayer;
1313 :
1314 494 : if (psFileXML != NULL)
1315 : {
1316 6 : CPLXMLNode* psIter = psXML->psChild;
1317 30 : while(psIter)
1318 : {
1319 24 : if (psIter->eType == CXT_Element &&
1320 : EQUAL(psIter->pszValue, "OGRWFSLayer") &&
1321 : strcmp(CPLGetXMLValue(psIter, "name", ""), pszName) == 0)
1322 : {
1323 6 : CPLXMLNode* psSchema = WFSFindNode( psIter->psChild, "schema" );
1324 6 : if (psSchema)
1325 : {
1326 6 : OGRFeatureDefn* poSrcFDefn = poLayer->ParseSchema(psSchema);
1327 6 : if (poSrcFDefn)
1328 6 : poLayer->BuildLayerDefn(poSrcFDefn);
1329 : }
1330 6 : break;
1331 : }
1332 18 : psIter = psIter->psNext;
1333 : }
1334 494 : }
1335 : }
1336 : }
1337 : }
1338 :
1339 18 : if (!psFileXML) CPLDestroyXMLNode( psXML );
1340 18 : CPLDestroyXMLNode( psStrippedXML );
1341 :
1342 18 : return TRUE;
1343 : }
1344 :
1345 : /************************************************************************/
1346 : /* LoadMultipleLayerDefn() */
1347 : /************************************************************************/
1348 :
1349 : /* TinyOWS doesn't support POST, but MapServer, GeoServer and Deegree do */
1350 : #define USE_GET_FOR_DESCRIBE_FEATURE_TYPE 1
1351 :
1352 14 : void OGRWFSDataSource::LoadMultipleLayerDefn(const char* pszLayerName,
1353 : char* pszNS, char* pszNSVal)
1354 : {
1355 : /*if (!bIsGEOSERVER)
1356 : return;*/
1357 :
1358 14 : if (!bLoadMultipleLayerDefn)
1359 2 : return;
1360 :
1361 12 : if (aoSetAlreadyTriedLayers.find(pszLayerName) != aoSetAlreadyTriedLayers.end())
1362 0 : return;
1363 :
1364 12 : char* pszPrefix = CPLStrdup(pszLayerName);
1365 12 : char* pszColumn = strchr(pszPrefix, ':');
1366 12 : if (pszColumn)
1367 10 : *pszColumn = 0;
1368 : else
1369 2 : *pszPrefix = 0;
1370 :
1371 12 : OGRWFSLayer* poRefLayer = (OGRWFSLayer*)GetLayerByName(pszLayerName);
1372 12 : if (poRefLayer == NULL)
1373 0 : return;
1374 12 : const char* pszRequiredOutputFormatURL = poRefLayer->GetRequiredOutputFormatURL();
1375 :
1376 : #if USE_GET_FOR_DESCRIBE_FEATURE_TYPE == 1
1377 12 : CPLString osLayerToFetch(pszLayerName);
1378 : #else
1379 : CPLString osTypeNameToPost;
1380 : osTypeNameToPost += " <TypeName>";
1381 : osTypeNameToPost += pszLayerName;
1382 : osTypeNameToPost += "</TypeName>\n";
1383 : #endif
1384 :
1385 12 : int nLayersToFetch = 1;
1386 12 : aoSetAlreadyTriedLayers.insert(pszLayerName);
1387 :
1388 184 : for(int i=0;i<nLayers;i++)
1389 : {
1390 172 : if (!papoLayers[i]->HasLayerDefn())
1391 : {
1392 : /* We must be careful to requests only layers with the same prefix/namespace */
1393 172 : const char* pszName = papoLayers[i]->GetName();
1394 644 : if (((pszPrefix[0] == 0 && strchr(pszName, ':') == NULL) ||
1395 168 : (pszPrefix[0] != 0 && strncmp(pszName, pszPrefix, strlen(pszPrefix)) == 0 &&
1396 150 : pszName[strlen(pszPrefix)] == ':')) &&
1397 154 : ((pszRequiredOutputFormatURL == NULL && papoLayers[i]->GetRequiredOutputFormatURL() == NULL) ||
1398 0 : (pszRequiredOutputFormatURL != NULL && papoLayers[i]->GetRequiredOutputFormatURL() != NULL &&
1399 0 : strcmp(pszRequiredOutputFormatURL, papoLayers[i]->GetRequiredOutputFormatURL()) == 0)))
1400 : {
1401 154 : if (aoSetAlreadyTriedLayers.find(pszName) != aoSetAlreadyTriedLayers.end())
1402 12 : continue;
1403 142 : aoSetAlreadyTriedLayers.insert(pszName);
1404 :
1405 : #if USE_GET_FOR_DESCRIBE_FEATURE_TYPE == 1
1406 142 : if (nLayersToFetch > 0)
1407 142 : osLayerToFetch += ",";
1408 142 : osLayerToFetch += papoLayers[i]->GetName();
1409 : #else
1410 : osTypeNameToPost += " <TypeName>";
1411 : osTypeNameToPost += pszName;
1412 : osTypeNameToPost += "</TypeName>\n";
1413 : #endif
1414 142 : nLayersToFetch ++;
1415 :
1416 : /* Avoid fetching to many layer definition at a time */
1417 142 : if (nLayersToFetch >= 50)
1418 0 : break;
1419 : }
1420 : }
1421 : }
1422 :
1423 12 : CPLFree(pszPrefix);
1424 12 : pszPrefix = NULL;
1425 :
1426 : #if USE_GET_FOR_DESCRIBE_FEATURE_TYPE == 1
1427 12 : CPLString osURL(osBaseURL);
1428 12 : osURL = CPLURLAddKVP(osURL, "SERVICE", "WFS");
1429 12 : osURL = CPLURLAddKVP(osURL, "VERSION", GetVersion());
1430 12 : osURL = CPLURLAddKVP(osURL, "REQUEST", "DescribeFeatureType");
1431 12 : osURL = CPLURLAddKVP(osURL, "TYPENAME", osLayerToFetch);
1432 12 : osURL = CPLURLAddKVP(osURL, "PROPERTYNAME", NULL);
1433 12 : osURL = CPLURLAddKVP(osURL, "MAXFEATURES", NULL);
1434 12 : osURL = CPLURLAddKVP(osURL, "FILTER", NULL);
1435 12 : osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", pszRequiredOutputFormatURL);
1436 :
1437 12 : if (pszNS && GetNeedNAMESPACE())
1438 : {
1439 : /* Older Deegree version require NAMESPACE */
1440 : /* This has been now corrected */
1441 0 : CPLString osValue("xmlns(");
1442 0 : osValue += pszNS;
1443 0 : osValue += "=";
1444 0 : osValue += pszNSVal;
1445 0 : osValue += ")";
1446 0 : osURL = CPLURLAddKVP(osURL, "NAMESPACE", osValue);
1447 : }
1448 :
1449 12 : CPLHTTPResult* psResult = HTTPFetch( osURL, NULL);
1450 : #else
1451 : CPLString osPost;
1452 : osPost += "<?xml version=\"1.0\"?>\n";
1453 : osPost += "<wfs:DescribeFeatureType xmlns:wfs=\"http://www.opengis.net/wfs\"\n";
1454 : osPost += " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
1455 : osPost += " service=\"WFS\" version=\""; osPost += GetVersion(); osPost += "\"\n";
1456 : osPost += " xmlns:gml=\"http://www.opengis.net/gml\"\n";
1457 : osPost += " xmlns:ogc=\"http://www.opengis.net/ogc\"\n";
1458 : if (pszNS && pszNSVal)
1459 : {
1460 : osPost += " xmlns:";
1461 : osPost += pszNS;
1462 : osPost += "=\"";
1463 : osPost += pszNSVal;
1464 : osPost += "\"\n";
1465 : }
1466 : osPost += " xsi:schemaLocation=\"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/";
1467 : osPost += GetVersion();
1468 : osPost += "/wfs.xsd\"";
1469 : const char* pszRequiredOutputFormat = poRefLayer->GetRequiredOutputFormat();
1470 : if (pszRequiredOutputFormat)
1471 : {
1472 : osPost += "\n";
1473 : osPost += " outputFormat=\"";
1474 : osPost += pszRequiredOutputFormat;
1475 : osPost += "\"";
1476 : }
1477 : osPost += ">\n";
1478 : osPost += osTypeNameToPost;
1479 : osPost += "</wfs:DescribeFeatureType>\n";
1480 :
1481 : //CPLDebug("WFS", "%s", osPost.c_str());
1482 :
1483 : char** papszOptions = NULL;
1484 : papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
1485 : papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
1486 : "Content-Type: application/xml; charset=UTF-8");
1487 :
1488 : CPLHTTPResult* psResult = HTTPFetch(GetPostTransactionURL(), papszOptions);
1489 : CSLDestroy(papszOptions);
1490 : #endif
1491 :
1492 12 : if (psResult == NULL)
1493 : {
1494 0 : bLoadMultipleLayerDefn = FALSE;
1495 : return;
1496 : }
1497 :
1498 12 : if (strstr((const char*)psResult->pabyData, "<ServiceExceptionReport") != NULL)
1499 : {
1500 0 : if (IsOldDeegree((const char*)psResult->pabyData))
1501 : {
1502 : /* just silently forgive */
1503 : }
1504 : else
1505 : {
1506 : CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
1507 0 : psResult->pabyData);
1508 : }
1509 0 : CPLHTTPDestroyResult(psResult);
1510 0 : bLoadMultipleLayerDefn = FALSE;
1511 : return;
1512 : }
1513 :
1514 12 : CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
1515 12 : if (psXML == NULL)
1516 : {
1517 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
1518 0 : psResult->pabyData);
1519 0 : CPLHTTPDestroyResult(psResult);
1520 0 : bLoadMultipleLayerDefn = FALSE;
1521 : return;
1522 : }
1523 12 : CPLHTTPDestroyResult(psResult);
1524 :
1525 12 : CPLXMLNode* psSchema = WFSFindNode(psXML, "schema");
1526 12 : if (psSchema == NULL)
1527 : {
1528 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <Schema>");
1529 0 : CPLDestroyXMLNode( psXML );
1530 0 : bLoadMultipleLayerDefn = FALSE;
1531 : return;
1532 : }
1533 :
1534 12 : CPLString osTmpFileName;
1535 :
1536 12 : osTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
1537 12 : CPLSerializeXMLTreeToFile(psSchema, osTmpFileName);
1538 :
1539 12 : std::vector<GMLFeatureClass*> aosClasses;
1540 12 : GMLParseXSD( osTmpFileName, aosClasses );
1541 :
1542 12 : if ((int)aosClasses.size() == nLayersToFetch)
1543 : {
1544 6 : std::vector<GMLFeatureClass*>::const_iterator iter = aosClasses.begin();
1545 6 : std::vector<GMLFeatureClass*>::const_iterator eiter = aosClasses.end();
1546 88 : while (iter != eiter)
1547 : {
1548 76 : GMLFeatureClass* poClass = *iter;
1549 76 : iter ++;
1550 :
1551 : OGRWFSLayer* poLayer;
1552 :
1553 76 : if (bKeepLayerNamePrefix && pszNS != NULL && strchr(poClass->GetName(), ':') == NULL)
1554 : {
1555 0 : CPLString osWithPrefix(pszNS);
1556 0 : osWithPrefix += ":";
1557 0 : osWithPrefix += poClass->GetName();
1558 0 : poLayer = (OGRWFSLayer* )GetLayerByName(osWithPrefix);
1559 : }
1560 : else
1561 76 : poLayer = (OGRWFSLayer* )GetLayerByName(poClass->GetName());
1562 :
1563 76 : if (poLayer)
1564 : {
1565 76 : if (!poLayer->HasLayerDefn())
1566 : {
1567 76 : CPLXMLNode* psSchemaForLayer = CPLCloneXMLTree(psSchema);
1568 76 : CPLStripXMLNamespace( psSchemaForLayer, NULL, TRUE );
1569 76 : CPLXMLNode* psIter = psSchemaForLayer->psChild;
1570 76 : int bHasAlreadyImportedGML = FALSE;
1571 76 : int bFoundComplexType = FALSE;
1572 76 : int bFoundElement = FALSE;
1573 2076 : while(psIter != NULL)
1574 : {
1575 1924 : CPLXMLNode* psIterNext = psIter->psNext;
1576 1932 : if (psIter->eType == CXT_Element &&
1577 : strcmp(psIter->pszValue,"complexType") == 0)
1578 : {
1579 8 : const char* pszName = CPLGetXMLValue(psIter, "name", "");
1580 8 : CPLString osExpectedName(poLayer->GetShortName());
1581 8 : osExpectedName += "Type";
1582 8 : CPLString osExpectedName2(poLayer->GetShortName());
1583 8 : osExpectedName2 += "_Type";
1584 8 : if (strcmp(pszName, osExpectedName) == 0 ||
1585 : strcmp(pszName, osExpectedName2) == 0 ||
1586 : strcmp(pszName, poLayer->GetShortName()) == 0)
1587 : {
1588 4 : bFoundComplexType = TRUE;
1589 : }
1590 : else
1591 : {
1592 4 : CPLRemoveXMLChild( psSchemaForLayer, psIter );
1593 4 : CPLDestroyXMLNode(psIter);
1594 8 : }
1595 : }
1596 3220 : else if (psIter->eType == CXT_Element &&
1597 : strcmp(psIter->pszValue,"element") == 0)
1598 : {
1599 1304 : const char* pszName = CPLGetXMLValue(psIter, "name", "");
1600 1304 : CPLString osExpectedName(poLayer->GetShortName());
1601 1304 : osExpectedName += "Type";
1602 1304 : CPLString osExpectedName2(poLayer->GetShortName());
1603 1304 : osExpectedName2 += "_Type";
1604 :
1605 1304 : const char* pszType = CPLGetXMLValue(psIter, "type", "");
1606 1304 : CPLString osExpectedType(poLayer->GetName());
1607 1304 : osExpectedType += "Type";
1608 1304 : CPLString osExpectedType2(poLayer->GetName());
1609 1304 : osExpectedType2 += "_Type";
1610 2608 : if (strcmp(pszType, osExpectedType) == 0 ||
1611 : strcmp(pszType, osExpectedType2) == 0 ||
1612 1304 : strcmp(pszType, poLayer->GetName()) == 0 ||
1613 : (strchr(pszType, ':') &&
1614 : (strcmp(strchr(pszType, ':') + 1, osExpectedType) == 0 ||
1615 : strcmp(strchr(pszType, ':') + 1, osExpectedType2) == 0)))
1616 : {
1617 4 : bFoundElement = TRUE;
1618 : }
1619 1300 : else if (*pszType == '\0' &&
1620 : CPLGetXMLNode(psIter, "complexType") != NULL &&
1621 : (strcmp(pszName, osExpectedName) == 0 ||
1622 : strcmp(pszName, osExpectedName2) == 0 ||
1623 : strcmp(pszName, poLayer->GetShortName()) == 0) )
1624 : {
1625 72 : bFoundElement = TRUE;
1626 72 : bFoundComplexType = TRUE;
1627 : }
1628 : else
1629 : {
1630 1228 : CPLRemoveXMLChild( psSchemaForLayer, psIter );
1631 1228 : CPLDestroyXMLNode(psIter);
1632 1304 : }
1633 : }
1634 612 : else if (psIter->eType == CXT_Element &&
1635 : strcmp(psIter->pszValue,"import") == 0 &&
1636 : strcmp(CPLGetXMLValue(psIter, "namespace", ""),
1637 : "http://www.opengis.net/gml") == 0)
1638 : {
1639 40 : if (bHasAlreadyImportedGML)
1640 : {
1641 0 : CPLRemoveXMLChild( psSchemaForLayer, psIter );
1642 0 : CPLDestroyXMLNode(psIter);
1643 : }
1644 : else
1645 40 : bHasAlreadyImportedGML = TRUE;
1646 : }
1647 1924 : psIter = psIterNext;
1648 : }
1649 :
1650 76 : if (bFoundComplexType && bFoundElement)
1651 : {
1652 76 : OGRFeatureDefn* poSrcFDefn = poLayer->ParseSchema(psSchemaForLayer);
1653 76 : if (poSrcFDefn)
1654 : {
1655 76 : poLayer->BuildLayerDefn(poSrcFDefn);
1656 76 : SaveLayerSchema(poLayer->GetName(), psSchemaForLayer);
1657 : }
1658 : }
1659 :
1660 76 : CPLDestroyXMLNode(psSchemaForLayer);
1661 : }
1662 : else
1663 : {
1664 : CPLDebug("WFS", "Found several time schema for layer %s in server response. Shouldn't happen",
1665 0 : poClass->GetName());
1666 : }
1667 : }
1668 : else
1669 : {
1670 : CPLDebug("WFS", "Cannot find layer %s. Shouldn't happen",
1671 0 : poClass->GetName());
1672 : }
1673 76 : delete poClass;
1674 : }
1675 : }
1676 6 : else if (aosClasses.size() > 0)
1677 : {
1678 0 : std::vector<GMLFeatureClass*>::const_iterator iter = aosClasses.begin();
1679 0 : std::vector<GMLFeatureClass*>::const_iterator eiter = aosClasses.end();
1680 0 : while (iter != eiter)
1681 : {
1682 0 : GMLFeatureClass* poClass = *iter;
1683 0 : iter ++;
1684 0 : delete poClass;
1685 : }
1686 : }
1687 : else
1688 : {
1689 6 : CPLDebug("WFS", "Turn off loading of multiple layer definitions at a single time");
1690 6 : bLoadMultipleLayerDefn = FALSE;
1691 : }
1692 :
1693 12 : VSIUnlink(osTmpFileName);
1694 :
1695 12 : CPLDestroyXMLNode( psXML );
1696 : }
1697 :
1698 : /************************************************************************/
1699 : /* SaveLayerSchema() */
1700 : /************************************************************************/
1701 :
1702 84 : void OGRWFSDataSource::SaveLayerSchema(const char* pszLayerName, CPLXMLNode* psSchema)
1703 : {
1704 84 : if (psFileXML != NULL)
1705 : {
1706 0 : bRewriteFile = TRUE;
1707 0 : CPLXMLNode* psLayerNode = CPLCreateXMLNode(NULL, CXT_Element, "OGRWFSLayer");
1708 0 : CPLSetXMLValue(psLayerNode, "#name", pszLayerName);
1709 0 : CPLAddXMLChild(psLayerNode, CPLCloneXMLTree(psSchema));
1710 0 : CPLAddXMLChild(psFileXML, psLayerNode);
1711 : }
1712 84 : }
1713 :
1714 : /************************************************************************/
1715 : /* IsOldDeegree() */
1716 : /************************************************************************/
1717 :
1718 0 : int OGRWFSDataSource::IsOldDeegree(const char* pszErrorString)
1719 : {
1720 0 : if (!bNeedNAMESPACE &&
1721 : strstr(pszErrorString, "Invalid \"TYPENAME\" parameter. No binding for prefix") != NULL)
1722 : {
1723 0 : bNeedNAMESPACE = TRUE;
1724 0 : return TRUE;
1725 : }
1726 0 : return FALSE;
1727 : }
1728 :
1729 : /************************************************************************/
1730 : /* WFS_EscapeURL() */
1731 : /************************************************************************/
1732 :
1733 72 : static CPLString WFS_EscapeURL(CPLString osURL)
1734 : {
1735 72 : CPLString osNewURL;
1736 : size_t i;
1737 :
1738 72 : int bNeedsEscaping = FALSE;
1739 13088 : for(i=0;i<osURL.size();i++)
1740 : {
1741 13036 : char ch = osURL[i];
1742 13036 : if (ch == '<' || ch == '>' || ch == ' ' || ch == '"')
1743 : {
1744 20 : bNeedsEscaping = TRUE;
1745 20 : break;
1746 : }
1747 : }
1748 :
1749 72 : if (!bNeedsEscaping)
1750 52 : return osURL;
1751 :
1752 8866 : for(i=0;i<osURL.size();i++)
1753 : {
1754 8846 : char ch = osURL[i];
1755 8846 : if (ch == '<')
1756 242 : osNewURL += "%3C";
1757 8604 : else if (ch == '>')
1758 242 : osNewURL += "%3E";
1759 8362 : else if (ch == ' ')
1760 58 : osNewURL += "%20";
1761 8304 : else if (ch == '"')
1762 108 : osNewURL += "%22";
1763 8196 : else if (ch == '%')
1764 0 : osNewURL += "%25";
1765 : else
1766 8196 : osNewURL += ch;
1767 : }
1768 20 : return osNewURL;
1769 : }
1770 :
1771 : /************************************************************************/
1772 : /* HTTPFetch() */
1773 : /************************************************************************/
1774 :
1775 72 : CPLHTTPResult* OGRWFSDataSource::HTTPFetch( const char* pszURL, char** papszOptions )
1776 : {
1777 72 : char** papszNewOptions = CSLDuplicate(papszOptions);
1778 72 : if (bUseHttp10)
1779 0 : papszNewOptions = CSLAddNameValue(papszNewOptions, "HTTP_VERSION", "1.0");
1780 72 : if (papszHttpOptions)
1781 0 : papszNewOptions = CSLMerge(papszNewOptions, papszHttpOptions);
1782 72 : CPLHTTPResult* psResult = CPLHTTPFetch( WFS_EscapeURL(pszURL), papszNewOptions );
1783 72 : CSLDestroy(papszNewOptions);
1784 :
1785 72 : if (psResult == NULL)
1786 : {
1787 0 : return NULL;
1788 : }
1789 72 : if (psResult->nStatus != 0 || psResult->pszErrBuf != NULL)
1790 : {
1791 : /* A few buggy servers return chunked data with errouneous remaining bytes value */
1792 : /* curl doesn't like this. Retry with HTTP 1.0 protocol instead that doesn't support */
1793 : /* chunked data */
1794 0 : if (psResult->pszErrBuf &&
1795 : strstr(psResult->pszErrBuf, "transfer closed with outstanding read data remaining") &&
1796 : !bUseHttp10)
1797 : {
1798 0 : CPLDebug("WFS", "Probably buggy remote server. Retrying with HTTP 1.0 protocol");
1799 0 : bUseHttp10 = TRUE;
1800 0 : return HTTPFetch(pszURL, papszOptions);
1801 : }
1802 :
1803 : CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s (%d)",
1804 0 : (psResult->pszErrBuf) ? psResult->pszErrBuf : "unknown", psResult->nStatus);
1805 0 : CPLHTTPDestroyResult(psResult);
1806 0 : return NULL;
1807 : }
1808 72 : if (psResult->pabyData == NULL)
1809 : {
1810 0 : CPLError(CE_Failure, CPLE_AppDefined, "Empty content returned by server");
1811 0 : CPLHTTPDestroyResult(psResult);
1812 0 : return NULL;
1813 : }
1814 72 : return psResult;
1815 : }
1816 :
1817 : /************************************************************************/
1818 : /* ExecuteSQL() */
1819 : /************************************************************************/
1820 :
1821 6 : OGRLayer * OGRWFSDataSource::ExecuteSQL( const char *pszSQLCommand,
1822 : OGRGeometry *poSpatialFilter,
1823 : const char *pszDialect )
1824 :
1825 : {
1826 : /* -------------------------------------------------------------------- */
1827 : /* Use generic implementation for OGRSQL dialect. */
1828 : /* -------------------------------------------------------------------- */
1829 6 : if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
1830 : {
1831 : OGRLayer* poResLayer = OGRDataSource::ExecuteSQL( pszSQLCommand,
1832 : poSpatialFilter,
1833 0 : pszDialect );
1834 0 : oMap[poResLayer] = NULL;
1835 0 : return poResLayer;
1836 : }
1837 :
1838 : /* -------------------------------------------------------------------- */
1839 : /* Deal with "SELECT _LAST_INSERTED_FIDS_ FROM layername" statement */
1840 : /* -------------------------------------------------------------------- */
1841 6 : if( EQUALN(pszSQLCommand, "SELECT _LAST_INSERTED_FIDS_ FROM ", 33) )
1842 : {
1843 0 : const char* pszIter = pszSQLCommand + 33;
1844 0 : while(*pszIter && *pszIter != ' ')
1845 0 : pszIter ++;
1846 :
1847 0 : CPLString osName = pszSQLCommand + 33;
1848 0 : osName.resize(pszIter - (pszSQLCommand + 33));
1849 0 : OGRWFSLayer* poLayer = (OGRWFSLayer*)GetLayerByName(osName);
1850 0 : if (poLayer == NULL)
1851 : {
1852 : CPLError(CE_Failure, CPLE_AppDefined,
1853 0 : "Unknown layer : %s", osName.c_str());
1854 0 : return NULL;
1855 : }
1856 :
1857 0 : OGRSFDriver* poMEMDrv = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("Memory");
1858 0 : if (poMEMDrv == NULL)
1859 : {
1860 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot load 'Memory' driver");
1861 0 : return NULL;
1862 : }
1863 :
1864 0 : OGRDataSource* poMEMDS = poMEMDrv->CreateDataSource("dummy_name", NULL);
1865 0 : OGRLayer* poMEMLayer = poMEMDS->CreateLayer("FID_LIST", NULL, wkbNone, NULL);
1866 0 : OGRFieldDefn oFDefn("gml_id", OFTString);
1867 0 : poMEMLayer->CreateField(&oFDefn);
1868 :
1869 0 : const std::vector<CPLString>& aosFIDList = poLayer->GetLastInsertedFIDList();
1870 0 : std::vector<CPLString>::const_iterator iter = aosFIDList.begin();
1871 0 : std::vector<CPLString>::const_iterator eiter = aosFIDList.end();
1872 0 : while (iter != eiter)
1873 : {
1874 0 : const CPLString& osFID = *iter;
1875 0 : OGRFeature* poFeature = new OGRFeature(poMEMLayer->GetLayerDefn());
1876 0 : poFeature->SetField(0, osFID);
1877 0 : poMEMLayer->CreateFeature(poFeature);
1878 0 : delete poFeature;
1879 0 : iter ++;
1880 : }
1881 :
1882 0 : OGRLayer* poResLayer = new OGRWFSWrappedResultLayer(poMEMDS, poMEMLayer);
1883 0 : oMap[poResLayer] = NULL;
1884 0 : return poResLayer;
1885 : }
1886 :
1887 : /* -------------------------------------------------------------------- */
1888 : /* Deal with "DELETE FROM layer_name WHERE expression" statement */
1889 : /* -------------------------------------------------------------------- */
1890 6 : if( EQUALN(pszSQLCommand, "DELETE FROM ", 12) )
1891 : {
1892 0 : const char* pszIter = pszSQLCommand + 12;
1893 0 : while(*pszIter && *pszIter != ' ')
1894 0 : pszIter ++;
1895 0 : if (*pszIter == 0)
1896 : {
1897 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid statement");
1898 0 : return NULL;
1899 : }
1900 :
1901 0 : CPLString osName = pszSQLCommand + 12;
1902 0 : osName.resize(pszIter - (pszSQLCommand + 12));
1903 0 : OGRWFSLayer* poLayer = (OGRWFSLayer*)GetLayerByName(osName);
1904 0 : if (poLayer == NULL)
1905 : {
1906 : CPLError(CE_Failure, CPLE_AppDefined,
1907 0 : "Unknown layer : %s", osName.c_str());
1908 0 : return NULL;
1909 : }
1910 :
1911 0 : while(*pszIter && *pszIter == ' ')
1912 0 : pszIter ++;
1913 0 : if (!EQUALN(pszIter, "WHERE ", 5))
1914 : {
1915 0 : CPLError(CE_Failure, CPLE_AppDefined, "WHERE clause missing");
1916 0 : return NULL;
1917 : }
1918 0 : pszIter += 5;
1919 :
1920 0 : const char* pszQuery = pszIter;
1921 :
1922 : /* Check with the generic SQL engine that this is a valid WHERE clause */
1923 0 : OGRFeatureQuery oQuery;
1924 0 : OGRErr eErr = oQuery.Compile( poLayer->GetLayerDefn(), pszQuery );
1925 0 : if( eErr != OGRERR_NONE )
1926 : {
1927 0 : return NULL;
1928 : }
1929 :
1930 : /* Now turn this into OGC Filter language if possible */
1931 0 : int bNeedsNullCheck = FALSE;
1932 0 : int nVersion = (strcmp(GetVersion(),"1.0.0") == 0) ? 100 : 110;
1933 : CPLString osOGCFilter = WFS_TurnSQLFilterToOGCFilter(pszQuery,
1934 : nVersion,
1935 : bPropertyIsNotEqualToSupported,
1936 : bUseFeatureId,
1937 : bGmlObjectIdNeedsGMLPrefix,
1938 0 : &bNeedsNullCheck);
1939 0 : if (bNeedsNullCheck && !HasNullCheck())
1940 0 : osOGCFilter = "";
1941 :
1942 0 : if (osOGCFilter.size() == 0)
1943 : {
1944 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot convert WHERE clause into a OGC filter");
1945 0 : return NULL;
1946 : }
1947 :
1948 0 : poLayer->DeleteFromFilter(osOGCFilter);
1949 :
1950 0 : return NULL;
1951 : }
1952 :
1953 : /* -------------------------------------------------------------------- */
1954 : /* Deal with "SELECT xxxx ORDER BY" statement */
1955 : /* -------------------------------------------------------------------- */
1956 6 : if (EQUALN(pszSQLCommand, "SELECT", 6))
1957 : {
1958 4 : swq_select* psSelectInfo = new swq_select();
1959 4 : if( psSelectInfo->preparse( pszSQLCommand ) != CPLE_None )
1960 : {
1961 0 : delete psSelectInfo;
1962 0 : return NULL;
1963 : }
1964 : int iLayer;
1965 12 : if( strcmp(GetVersion(),"1.0.0") != 0 &&
1966 : psSelectInfo->table_count == 1 &&
1967 4 : psSelectInfo->table_defs[0].data_source == NULL &&
1968 4 : (iLayer = GetLayerIndex( psSelectInfo->table_defs[0].table_name )) >= 0 &&
1969 : psSelectInfo->join_count == 0 &&
1970 : psSelectInfo->order_specs == 1 )
1971 : {
1972 2 : OGRWFSLayer* poSrcLayer = papoLayers[iLayer];
1973 2 : int nFieldIndex = poSrcLayer->GetLayerDefn()->GetFieldIndex(
1974 4 : psSelectInfo->order_defs[0].field_name);
1975 2 : if (!poSrcLayer->HasGotApproximateLayerDefn() && nFieldIndex >= 0)
1976 : {
1977 2 : OGRWFSLayer* poDupLayer = poSrcLayer->Clone();
1978 :
1979 : /* Make sure to have the right case */
1980 2 : const char* pszFieldName = poDupLayer->GetLayerDefn()->
1981 2 : GetFieldDefn(nFieldIndex)->GetNameRef();
1982 :
1983 : poDupLayer->SetOrderBy(pszFieldName,
1984 2 : psSelectInfo->order_defs[0].ascending_flag);
1985 2 : delete psSelectInfo;
1986 2 : psSelectInfo = NULL;
1987 :
1988 : /* Just set poDupLayer in the papoLayers for the time of the */
1989 : /* base ExecuteSQL(), so that the OGRGenSQLResultsLayer references */
1990 : /* that temporary layer */
1991 2 : papoLayers[iLayer] = poDupLayer;
1992 : OGRLayer* poResLayer = OGRDataSource::ExecuteSQL( pszSQLCommand,
1993 : poSpatialFilter,
1994 2 : pszDialect );
1995 2 : papoLayers[iLayer] = poSrcLayer;
1996 :
1997 2 : if (poResLayer != NULL)
1998 2 : oMap[poResLayer] = poDupLayer;
1999 : else
2000 0 : delete poDupLayer;
2001 2 : return poResLayer;
2002 : }
2003 : }
2004 :
2005 2 : delete psSelectInfo;
2006 : }
2007 :
2008 : OGRLayer* poResLayer = OGRDataSource::ExecuteSQL( pszSQLCommand,
2009 : poSpatialFilter,
2010 4 : pszDialect );
2011 4 : oMap[poResLayer] = NULL;
2012 4 : return poResLayer;
2013 : }
2014 :
2015 : /************************************************************************/
2016 : /* ReleaseResultSet() */
2017 : /************************************************************************/
2018 :
2019 4 : void OGRWFSDataSource::ReleaseResultSet( OGRLayer * poResultsSet )
2020 : {
2021 4 : if (poResultsSet == NULL)
2022 0 : return;
2023 :
2024 4 : std::map<OGRLayer*, OGRLayer*>::iterator oIter = oMap.find(poResultsSet);
2025 4 : if (oIter != oMap.end())
2026 : {
2027 : /* Destroy first the result layer, because it still references */
2028 : /* the poDupLayer (oIter->second) */
2029 4 : delete poResultsSet;
2030 :
2031 4 : delete oIter->second;
2032 4 : oMap.erase(oIter);
2033 : }
2034 : else
2035 : {
2036 0 : CPLError(CE_Failure, CPLE_AppDefined, "Trying to destroy an invalid result set !");
2037 : }
2038 : }
|