1 : /******************************************************************************
2 : * $Id: ogrgmldatasource.cpp 24294 2012-04-22 20:49:52Z rouault $
3 : *
4 : * Project: OGR
5 : * Purpose: Implements OGRGMLDataSource class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
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 : * Contributor: Alessandro Furieri, a.furieri@lqt.it
31 : * Portions of this module implenting GML_SKIP_RESOLVE_ELEMS HUGE
32 : * Developed for Faunalia ( http://www.faunalia.it) with funding from
33 : * Regione Toscana - Settore SISTEMA INFORMATIVO TERRITORIALE ED AMBIENTALE
34 : *
35 : ****************************************************************************/
36 :
37 : #include "ogr_gml.h"
38 : #include "parsexsd.h"
39 : #include "cpl_conv.h"
40 : #include "cpl_string.h"
41 : #include "gmlutils.h"
42 : #include "ogr_p.h"
43 :
44 : #include <vector>
45 :
46 : CPL_CVSID("$Id: ogrgmldatasource.cpp 24294 2012-04-22 20:49:52Z rouault $");
47 :
48 : /************************************************************************/
49 : /* OGRGMLDataSource() */
50 : /************************************************************************/
51 :
52 718 : OGRGMLDataSource::OGRGMLDataSource()
53 :
54 : {
55 718 : pszName = NULL;
56 718 : papoLayers = NULL;
57 718 : nLayers = 0;
58 :
59 718 : poReader = NULL;
60 718 : fpOutput = NULL;
61 718 : bFpOutputIsNonSeekable = FALSE;
62 718 : bFpOutputSingleFile = FALSE;
63 718 : bIsOutputGML3 = FALSE;
64 718 : bIsOutputGML3Deegree = FALSE;
65 718 : bIsOutputGML32 = FALSE;
66 718 : bIsLongSRSRequired = FALSE;
67 718 : bWriteSpaceIndentation = TRUE;
68 :
69 718 : papszCreateOptions = NULL;
70 718 : bOutIsTempFile = FALSE;
71 :
72 718 : bExposeGMLId = FALSE;
73 718 : bExposeFid = FALSE;
74 718 : nSchemaInsertLocation = -1;
75 718 : nBoundedByLocation = -1;
76 718 : bBBOX3D = FALSE;
77 :
78 718 : poGlobalSRS = NULL;
79 718 : bIsWFS = FALSE;
80 :
81 718 : eReadMode = STANDARD;
82 718 : poStoredGMLFeature = NULL;
83 718 : poLastReadLayer = NULL;
84 :
85 718 : m_bInvertAxisOrderIfLatLong = FALSE;
86 718 : m_bConsiderEPSGAsURN = FALSE;
87 718 : m_bGetSecondaryGeometryOption = FALSE;
88 718 : }
89 :
90 : /************************************************************************/
91 : /* ~OGRGMLDataSource() */
92 : /************************************************************************/
93 :
94 718 : OGRGMLDataSource::~OGRGMLDataSource()
95 :
96 : {
97 :
98 718 : if( fpOutput != NULL )
99 : {
100 : PrintLine( fpOutput, "%s",
101 18 : "</ogr:FeatureCollection>" );
102 :
103 18 : if( bFpOutputIsNonSeekable)
104 : {
105 0 : VSIFCloseL( fpOutput );
106 0 : fpOutput = NULL;
107 : }
108 :
109 18 : InsertHeader();
110 :
111 18 : if( !bFpOutputIsNonSeekable
112 : && nBoundedByLocation != -1
113 : && sBoundingRect.IsInit()
114 : && VSIFSeekL( fpOutput, nBoundedByLocation, SEEK_SET ) == 0 )
115 : {
116 10 : if (IsGML3Output())
117 : {
118 8 : int bCoordSwap = FALSE;
119 : char* pszSRSName;
120 8 : if (poGlobalSRS)
121 8 : pszSRSName = GML_GetSRSName(poGlobalSRS, IsLongSRSRequired(), &bCoordSwap);
122 : else
123 0 : pszSRSName = CPLStrdup("");
124 : char szLowerCorner[75], szUpperCorner[75];
125 8 : if (bCoordSwap)
126 : {
127 6 : OGRMakeWktCoordinate(szLowerCorner, sBoundingRect.MinY, sBoundingRect.MinX, sBoundingRect.MinZ, (bBBOX3D) ? 3 : 2);
128 6 : OGRMakeWktCoordinate(szUpperCorner, sBoundingRect.MaxY, sBoundingRect.MaxX, sBoundingRect.MaxZ, (bBBOX3D) ? 3 : 2);
129 : }
130 : else
131 : {
132 2 : OGRMakeWktCoordinate(szLowerCorner, sBoundingRect.MinX, sBoundingRect.MinY, sBoundingRect.MinZ, (bBBOX3D) ? 3 : 2);
133 2 : OGRMakeWktCoordinate(szUpperCorner, sBoundingRect.MaxX, sBoundingRect.MaxY, sBoundingRect.MaxZ, (bBBOX3D) ? 3 : 2);
134 : }
135 8 : if (bWriteSpaceIndentation)
136 8 : VSIFPrintfL( fpOutput, " ");
137 : PrintLine( fpOutput, "<gml:boundedBy><gml:Envelope%s%s><gml:lowerCorner>%s</gml:lowerCorner><gml:upperCorner>%s</gml:upperCorner></gml:Envelope></gml:boundedBy>",
138 8 : (bBBOX3D) ? " srsDimension=\"3\"" : "", pszSRSName, szLowerCorner, szUpperCorner);
139 8 : CPLFree(pszSRSName);
140 : }
141 : else
142 : {
143 2 : if (bWriteSpaceIndentation)
144 2 : VSIFPrintfL( fpOutput, " ");
145 2 : PrintLine( fpOutput, "<gml:boundedBy>" );
146 2 : if (bWriteSpaceIndentation)
147 2 : VSIFPrintfL( fpOutput, " ");
148 2 : PrintLine( fpOutput, "<gml:Box>" );
149 2 : if (bWriteSpaceIndentation)
150 2 : VSIFPrintfL( fpOutput, " ");
151 : VSIFPrintfL( fpOutput,
152 : "<gml:coord><gml:X>%.16g</gml:X>"
153 : "<gml:Y>%.16g</gml:Y>",
154 2 : sBoundingRect.MinX, sBoundingRect.MinY );
155 2 : if (bBBOX3D)
156 : VSIFPrintfL( fpOutput, "<gml:Z>%.16g</gml:Z>",
157 2 : sBoundingRect.MinZ );
158 2 : PrintLine( fpOutput, "</gml:coord>");
159 2 : if (bWriteSpaceIndentation)
160 2 : VSIFPrintfL( fpOutput, " ");
161 : VSIFPrintfL( fpOutput,
162 : "<gml:coord><gml:X>%.16g</gml:X>"
163 : "<gml:Y>%.16g</gml:Y>",
164 2 : sBoundingRect.MaxX, sBoundingRect.MaxY );
165 2 : if (bBBOX3D)
166 : VSIFPrintfL( fpOutput, "<gml:Z>%.16g</gml:Z>",
167 2 : sBoundingRect.MaxZ );
168 2 : PrintLine( fpOutput, "</gml:coord>");
169 2 : if (bWriteSpaceIndentation)
170 2 : VSIFPrintfL( fpOutput, " ");
171 2 : PrintLine( fpOutput, "</gml:Box>" );
172 2 : if (bWriteSpaceIndentation)
173 2 : VSIFPrintfL( fpOutput, " ");
174 2 : PrintLine( fpOutput, "</gml:boundedBy>" );
175 : }
176 : }
177 :
178 18 : if (fpOutput)
179 18 : VSIFCloseL( fpOutput );
180 : }
181 :
182 718 : CSLDestroy( papszCreateOptions );
183 718 : CPLFree( pszName );
184 :
185 934 : for( int i = 0; i < nLayers; i++ )
186 216 : delete papoLayers[i];
187 :
188 718 : CPLFree( papoLayers );
189 :
190 718 : if( poReader )
191 : {
192 144 : if (bOutIsTempFile)
193 0 : VSIUnlink(poReader->GetSourceFileName());
194 144 : delete poReader;
195 : }
196 :
197 718 : delete poGlobalSRS;
198 :
199 718 : delete poStoredGMLFeature;
200 718 : }
201 :
202 : /************************************************************************/
203 : /* Open() */
204 : /************************************************************************/
205 :
206 700 : int OGRGMLDataSource::Open( const char * pszNewName, int bTestOpen )
207 :
208 : {
209 : VSILFILE *fp;
210 : char szHeader[2048];
211 700 : int nNumberOfFeatures = 0;
212 700 : CPLString osWithVsiGzip;
213 :
214 700 : pszName = CPLStrdup( pszNewName );
215 :
216 : /* -------------------------------------------------------------------- */
217 : /* Open the source file. */
218 : /* -------------------------------------------------------------------- */
219 700 : fp = VSIFOpenL( pszNewName, "r" );
220 700 : if( fp == NULL )
221 : {
222 148 : if( !bTestOpen )
223 : CPLError( CE_Failure, CPLE_OpenFailed,
224 : "Failed to open GML file `%s'.",
225 0 : pszNewName );
226 :
227 148 : return FALSE;
228 : }
229 :
230 552 : int bExpatCompatibleEncoding = FALSE;
231 552 : int bHas3D = FALSE;
232 552 : int bHintConsiderEPSGAsURN = FALSE;
233 :
234 : /* -------------------------------------------------------------------- */
235 : /* If we aren't sure it is GML, load a header chunk and check */
236 : /* for signs it is GML */
237 : /* -------------------------------------------------------------------- */
238 552 : if( bTestOpen )
239 : {
240 552 : size_t nRead = VSIFReadL( szHeader, 1, sizeof(szHeader), fp );
241 552 : if (nRead <= 0)
242 : {
243 16 : VSIFCloseL( fp );
244 16 : return FALSE;
245 : }
246 536 : szHeader[MIN(nRead, sizeof(szHeader))-1] = '\0';
247 :
248 : /* Might be a OS-Mastermap gzipped GML, so let be nice and try to open */
249 : /* it transparently with /vsigzip/ */
250 536 : if ( ((GByte*)szHeader)[0] == 0x1f && ((GByte*)szHeader)[1] == 0x8b &&
251 : EQUAL(CPLGetExtension(pszNewName), "gz") &&
252 : strncmp(pszNewName, "/vsigzip/", strlen("/vsigzip/")) != 0 )
253 : {
254 0 : VSIFCloseL( fp );
255 0 : osWithVsiGzip = "/vsigzip/";
256 0 : osWithVsiGzip += pszNewName;
257 :
258 0 : pszNewName = osWithVsiGzip;
259 :
260 0 : fp = VSIFOpenL( pszNewName, "r" );
261 0 : if( fp == NULL )
262 0 : return FALSE;
263 :
264 0 : nRead = VSIFReadL( szHeader, 1, sizeof(szHeader), fp );
265 0 : if (nRead <= 0)
266 : {
267 0 : VSIFCloseL( fp );
268 0 : return FALSE;
269 : }
270 0 : szHeader[MIN(nRead, sizeof(szHeader))-1] = '\0';
271 : }
272 :
273 : /* -------------------------------------------------------------------- */
274 : /* Check for a UTF-8 BOM and skip if found */
275 : /* */
276 : /* TODO: BOM is variable-lenght parameter and depends on encoding. */
277 : /* Add BOM detection for other encodings. */
278 : /* -------------------------------------------------------------------- */
279 :
280 : // Used to skip to actual beginning of XML data
281 536 : char* szPtr = szHeader;
282 :
283 540 : if( ( (unsigned char)szHeader[0] == 0xEF )
284 2 : && ( (unsigned char)szHeader[1] == 0xBB )
285 2 : && ( (unsigned char)szHeader[2] == 0xBF) )
286 : {
287 2 : szPtr += 3;
288 : }
289 :
290 536 : const char* pszEncoding = strstr(szPtr, "encoding=");
291 536 : if (pszEncoding)
292 352 : bExpatCompatibleEncoding = (pszEncoding[9] == '\'' || pszEncoding[9] == '"') &&
293 : (EQUALN(pszEncoding + 10, "UTF-8", 5) ||
294 532 : EQUALN(pszEncoding + 10, "ISO-8859-1", 10));
295 : else
296 356 : bExpatCompatibleEncoding = TRUE; /* utf-8 is the default */
297 :
298 536 : bHas3D = strstr(szPtr, "srsDimension=\"3\"") != NULL || strstr(szPtr, "<gml:Z>") != NULL;
299 :
300 : /* -------------------------------------------------------------------- */
301 : /* Here, we expect the opening chevrons of GML tree root element */
302 : /* -------------------------------------------------------------------- */
303 536 : if( szPtr[0] != '<'
304 : || strstr(szPtr,"opengis.net/gml") == NULL )
305 : {
306 384 : VSIFCloseL( fp );
307 384 : return FALSE;
308 : }
309 :
310 : /* Ignore GeoRSS documents. They will be recognized by the GeoRSS driver */
311 152 : if( strstr(szPtr, "<rss") != NULL && strstr(szPtr, "xmlns:georss") != NULL )
312 : {
313 8 : VSIFCloseL( fp );
314 8 : return FALSE;
315 : }
316 :
317 : /* Small optimization: if we parse a <wfs:FeatureCollection> and */
318 : /* that numberOfFeatures is set, we can use it to set the FeatureCount */
319 : /* but *ONLY* if there's just one class ! */
320 144 : const char* pszFeatureCollection = strstr(szPtr, "wfs:FeatureCollection");
321 144 : if (pszFeatureCollection == NULL)
322 108 : pszFeatureCollection = strstr(szPtr, "gml:FeatureCollection"); /* GML 3.2.1 output */
323 144 : if (pszFeatureCollection)
324 : {
325 56 : bExposeGMLId = TRUE;
326 56 : bIsWFS = TRUE;
327 56 : const char* pszNumberOfFeatures = strstr(szPtr, "numberOfFeatures=");
328 56 : if (pszNumberOfFeatures)
329 : {
330 22 : pszNumberOfFeatures += 17;
331 22 : char ch = pszNumberOfFeatures[0];
332 22 : if ((ch == '\'' || ch == '"') && strchr(pszNumberOfFeatures + 1, ch) != NULL)
333 : {
334 22 : nNumberOfFeatures = atoi(pszNumberOfFeatures + 1);
335 : }
336 : }
337 34 : else if ((pszNumberOfFeatures = strstr(szPtr, "numberReturned=")) != NULL) /* WFS 2.0.0 */
338 : {
339 4 : pszNumberOfFeatures += 15;
340 4 : char ch = pszNumberOfFeatures[0];
341 4 : if ((ch == '\'' || ch == '"') && strchr(pszNumberOfFeatures + 1, ch) != NULL)
342 : {
343 : /* 'unknown' might be a valid value in a corrected version of WFS 2.0 */
344 : /* but it will also evaluate to 0, that is considered as unknown, so nothing */
345 : /* particular to do */
346 4 : nNumberOfFeatures = atoi(pszNumberOfFeatures + 1);
347 : }
348 : }
349 : }
350 88 : else if (strncmp(pszNewName, "/vsimem/tempwfs_", strlen("/vsimem/tempwfs_")) == 0)
351 : {
352 : /* http://regis.intergraph.com/wfs/dcmetro/request.asp? returns a <G:FeatureCollection> */
353 : /* Who knows what servers can return ? Ok, so when in the context of the WFS driver */
354 : /* always expose the gml:id to avoid later crashes */
355 0 : bExposeGMLId = TRUE;
356 0 : bIsWFS = TRUE;
357 : }
358 : else
359 : {
360 : bExposeGMLId = strstr(szPtr, " gml:id=\"") != NULL ||
361 88 : strstr(szPtr, " gml:id='") != NULL;
362 : bExposeFid = strstr(szPtr, " fid=\"") != NULL ||
363 88 : strstr(szPtr, " fid='") != NULL;
364 :
365 88 : const char* pszExposeGMLId = CPLGetConfigOption("GML_EXPOSE_GML_ID", NULL);
366 88 : if (pszExposeGMLId)
367 0 : bExposeGMLId = CSLTestBoolean(pszExposeGMLId);
368 :
369 88 : const char* pszExposeFid = CPLGetConfigOption("GML_EXPOSE_FID", NULL);
370 88 : if (pszExposeFid)
371 2 : bExposeFid = CSLTestBoolean(pszExposeFid);
372 : }
373 :
374 144 : bHintConsiderEPSGAsURN = strstr(szPtr, "xmlns:fme=\"http://www.safe.com/gml/fme\"") != NULL;
375 : }
376 :
377 : /* -------------------------------------------------------------------- */
378 : /* We assume now that it is GML. Close and instantiate a */
379 : /* GMLReader on it. */
380 : /* -------------------------------------------------------------------- */
381 144 : VSIFCloseL( fp );
382 :
383 144 : const char* pszReadMode = CPLGetConfigOption("GML_READ_MODE", NULL);
384 282 : if (pszReadMode == NULL || EQUAL(pszReadMode, "STANDARD"))
385 138 : eReadMode = STANDARD;
386 6 : else if (EQUAL(pszReadMode, "SEQUENTIAL_LAYERS"))
387 4 : eReadMode = SEQUENTIAL_LAYERS;
388 2 : else if (EQUAL(pszReadMode, "INTERLEAVED_LAYERS"))
389 2 : eReadMode = INTERLEAVED_LAYERS;
390 : else
391 : {
392 0 : CPLDebug("GML", "Unrecognized value for GML_READ_MODE configuration option.");
393 : }
394 :
395 : m_bInvertAxisOrderIfLatLong = CSLTestBoolean(
396 144 : CPLGetConfigOption("GML_INVERT_AXIS_ORDER_IF_LAT_LONG", "YES"));
397 :
398 : const char* pszConsiderEPSGAsURN =
399 144 : CPLGetConfigOption("GML_CONSIDER_EPSG_AS_URN", NULL);
400 144 : if (pszConsiderEPSGAsURN != NULL)
401 0 : m_bConsiderEPSGAsURN = CSLTestBoolean(pszConsiderEPSGAsURN);
402 144 : else if (bHintConsiderEPSGAsURN)
403 : {
404 : /* GML produced by FME (at least CanVec GML) seem to honour EPSG axis ordering */
405 10 : CPLDebug("GML", "FME-produced GML --> consider that GML_CONSIDER_EPSG_AS_URN is set to YES");
406 10 : m_bConsiderEPSGAsURN = TRUE;
407 : }
408 : else
409 134 : m_bConsiderEPSGAsURN = FALSE;
410 :
411 144 : m_bGetSecondaryGeometryOption = CSLTestBoolean(CPLGetConfigOption("GML_GET_SECONDARY_GEOM", "NO"));
412 :
413 : /* EXPAT is faster than Xerces, so when it is safe to use it, use it ! */
414 : /* The only interest of Xerces is for rare encodings that Expat doesn't handle */
415 : /* but UTF-8 is well handled by Expat */
416 144 : int bUseExpatParserPreferably = bExpatCompatibleEncoding;
417 :
418 : /* Override default choice */
419 144 : const char* pszGMLParser = CPLGetConfigOption("GML_PARSER", NULL);
420 144 : if (pszGMLParser)
421 : {
422 0 : if (EQUAL(pszGMLParser, "EXPAT"))
423 0 : bUseExpatParserPreferably = TRUE;
424 0 : else if (EQUAL(pszGMLParser, "XERCES"))
425 0 : bUseExpatParserPreferably = FALSE;
426 : }
427 :
428 : poReader = CreateGMLReader( bUseExpatParserPreferably,
429 : m_bInvertAxisOrderIfLatLong,
430 : m_bConsiderEPSGAsURN,
431 144 : m_bGetSecondaryGeometryOption );
432 144 : if( poReader == NULL )
433 : {
434 : CPLError( CE_Failure, CPLE_AppDefined,
435 : "File %s appears to be GML but the GML reader can't\n"
436 : "be instantiated, likely because Xerces or Expat support wasn't\n"
437 : "configured in.",
438 0 : pszNewName );
439 0 : return FALSE;
440 : }
441 :
442 144 : poReader->SetSourceFile( pszNewName );
443 :
444 : /* -------------------------------------------------------------------- */
445 : /* Resolve the xlinks in the source file and save it with the */
446 : /* extension ".resolved.gml". The source file will to set to that. */
447 : /* -------------------------------------------------------------------- */
448 :
449 144 : char *pszXlinkResolvedFilename = NULL;
450 144 : const char *pszOption = CPLGetConfigOption("GML_SAVE_RESOLVED_TO", NULL);
451 144 : int bResolve = TRUE;
452 144 : int bHugeFile = FALSE;
453 144 : if( pszOption != NULL && EQUALN( pszOption, "SAME", 4 ) )
454 : {
455 : // "SAME" will overwrite the existing gml file
456 0 : pszXlinkResolvedFilename = CPLStrdup( pszNewName );
457 : }
458 144 : else if( pszOption != NULL &&
459 : CPLStrnlen( pszOption, 5 ) >= 5 &&
460 : EQUALN( pszOption - 4 + strlen( pszOption ), ".gml", 4 ) )
461 : {
462 : // Any string ending with ".gml" will try and write to it
463 4 : pszXlinkResolvedFilename = CPLStrdup( pszOption );
464 : }
465 : else
466 : {
467 : // When no option is given or is not recognised,
468 : // use the same file name with the extension changed to .resolved.gml
469 : pszXlinkResolvedFilename = CPLStrdup(
470 140 : CPLResetExtension( pszNewName, "resolved.gml" ) );
471 :
472 : // Check if the file already exists.
473 : VSIStatBufL sResStatBuf, sGMLStatBuf;
474 140 : if( VSIStatL( pszXlinkResolvedFilename, &sResStatBuf ) == 0 )
475 : {
476 6 : VSIStatL( pszNewName, &sGMLStatBuf );
477 6 : if( sGMLStatBuf.st_mtime > sResStatBuf.st_mtime )
478 : {
479 : CPLDebug( "GML",
480 : "Found %s but ignoring because it appears\n"
481 : "be older than the associated GML file.",
482 0 : pszXlinkResolvedFilename );
483 : }
484 : else
485 : {
486 6 : poReader->SetSourceFile( pszXlinkResolvedFilename );
487 6 : bResolve = FALSE;
488 : }
489 : }
490 : }
491 :
492 : const char *pszSkipOption = CPLGetConfigOption( "GML_SKIP_RESOLVE_ELEMS",
493 144 : "ALL");
494 144 : char **papszSkip = NULL;
495 144 : if( EQUAL( pszSkipOption, "ALL" ) )
496 124 : bResolve = FALSE;
497 20 : else if( EQUAL( pszSkipOption, "HUGE" ) )//exactly as NONE, but intended for HUGE files
498 4 : bHugeFile = TRUE;
499 16 : else if( !EQUAL( pszSkipOption, "NONE" ) )//use this to resolve everything
500 : papszSkip = CSLTokenizeString2( pszSkipOption, ",",
501 : CSLT_STRIPLEADSPACES |
502 2 : CSLT_STRIPENDSPACES );
503 : const char *pszGFSFilename;
504 : VSIStatBufL sGFSStatBuf, sGMLStatBuf;
505 144 : int bHaveSchema = FALSE;
506 144 : int bSchemaDone = FALSE;
507 :
508 : /* -------------------------------------------------------------------- */
509 : /* Is some GML Feature Schema (.gfs) TEMPLATE required ? */
510 : /* -------------------------------------------------------------------- */
511 : const char *pszGFSTemplateName =
512 144 : CPLGetConfigOption( "GML_GFS_TEMPLATE", NULL);
513 144 : if( pszGFSTemplateName != NULL )
514 : {
515 : /* attempting to load the GFS TEMPLATE */
516 0 : bHaveSchema = poReader->LoadClasses( pszGFSTemplateName );
517 : }
518 :
519 144 : if( bResolve )
520 : {
521 20 : if ( bHugeFile )
522 : {
523 4 : bSchemaDone = TRUE;
524 : int bSqliteIsTempFile =
525 4 : CSLTestBoolean(CPLGetConfigOption( "GML_HUGE_TEMPFILE", "YES"));
526 4 : int iSqliteCacheMB = atoi(CPLGetConfigOption( "OGR_SQLITE_CACHE", "0"));
527 8 : if( poReader->HugeFileResolver( pszXlinkResolvedFilename,
528 : bSqliteIsTempFile,
529 4 : iSqliteCacheMB ) == FALSE )
530 : {
531 : // we assume an errors have been reported.
532 0 : return FALSE;
533 : }
534 : }
535 : else
536 : {
537 : poReader->ResolveXlinks( pszXlinkResolvedFilename,
538 : &bOutIsTempFile,
539 16 : papszSkip );
540 : }
541 : }
542 :
543 144 : CPLFree( pszXlinkResolvedFilename );
544 144 : pszXlinkResolvedFilename = NULL;
545 144 : CSLDestroy( papszSkip );
546 144 : papszSkip = NULL;
547 :
548 : /* Is a prescan required ? */
549 144 : if( bHaveSchema && !bSchemaDone )
550 : {
551 : /* We must detect which layers are actually present in the .gml */
552 : /* and how many features they have */
553 0 : if( !poReader->PrescanForTemplate() )
554 : {
555 : // we assume an errors have been reported.
556 0 : return FALSE;
557 : }
558 : }
559 :
560 : /* -------------------------------------------------------------------- */
561 : /* Can we find a GML Feature Schema (.gfs) for the input file? */
562 : /* -------------------------------------------------------------------- */
563 144 : if( !bHaveSchema )
564 : {
565 144 : pszGFSFilename = CPLResetExtension( pszNewName, "gfs" );
566 144 : if (strncmp(pszGFSFilename, "/vsigzip/", strlen("/vsigzip/")) == 0)
567 0 : pszGFSFilename += strlen("/vsigzip/");
568 144 : if( VSIStatL( pszGFSFilename, &sGFSStatBuf ) == 0 )
569 : {
570 32 : VSIStatL( pszNewName, &sGMLStatBuf );
571 32 : if( sGMLStatBuf.st_mtime > sGFSStatBuf.st_mtime )
572 : {
573 : CPLDebug( "GML",
574 : "Found %s but ignoring because it appears\n"
575 : "be older than the associated GML file.",
576 0 : pszGFSFilename );
577 : }
578 : else
579 : {
580 32 : bHaveSchema = poReader->LoadClasses( pszGFSFilename );
581 32 : if (bHaveSchema)
582 : {
583 : const char *pszXSDFilename;
584 32 : pszXSDFilename = CPLResetExtension( pszNewName, "xsd" );
585 32 : if( VSIStatExL( pszXSDFilename, &sGMLStatBuf,
586 : VSI_STAT_EXISTS_FLAG ) == 0 )
587 : {
588 : CPLDebug("GML", "Using %s file, ignoring %s",
589 0 : pszGFSFilename, pszXSDFilename);
590 : }
591 : }
592 : }
593 : }
594 : }
595 :
596 : /* -------------------------------------------------------------------- */
597 : /* Can we find an xsd which might conform to tbe GML3 Level 0 */
598 : /* profile? We really ought to look for it based on the rules */
599 : /* schemaLocation in the GML feature collection but for now we */
600 : /* just hopes it is in the same director with the same name. */
601 : /* -------------------------------------------------------------------- */
602 : const char *pszXSDFilename;
603 144 : int bHasFoundXSD = FALSE;
604 :
605 144 : if( !bHaveSchema )
606 : {
607 112 : pszXSDFilename = CPLResetExtension( pszNewName, "xsd" );
608 112 : if( VSIStatL( pszXSDFilename, &sGMLStatBuf ) == 0 )
609 : {
610 62 : bHasFoundXSD = TRUE;
611 :
612 62 : std::vector<GMLFeatureClass*> aosClasses;
613 62 : bHaveSchema = GMLParseXSD( pszXSDFilename, aosClasses );
614 62 : if (bHaveSchema)
615 : {
616 62 : std::vector<GMLFeatureClass*>::const_iterator iter = aosClasses.begin();
617 62 : std::vector<GMLFeatureClass*>::const_iterator eiter = aosClasses.end();
618 198 : while (iter != eiter)
619 : {
620 74 : GMLFeatureClass* poClass = *iter;
621 74 : iter ++;
622 :
623 : /* We have no way of knowing if the geometry type is 25D */
624 : /* when examining the xsd only, so if there was a hint */
625 : /* it is, we force to 25D */
626 74 : if (bHas3D)
627 : {
628 : poClass->SetGeometryType(
629 4 : poClass->GetGeometryType() | wkb25DBit);
630 : }
631 74 : poReader->AddClass( poClass );
632 : }
633 62 : poReader->SetClassListLocked( TRUE );
634 62 : }
635 : }
636 : }
637 :
638 : /* -------------------------------------------------------------------- */
639 : /* Force a first pass to establish the schema. Eventually we */
640 : /* will have mechanisms for remembering the schema and related */
641 : /* information. */
642 : /* -------------------------------------------------------------------- */
643 144 : if( !bHaveSchema )
644 : {
645 50 : if( !poReader->PrescanForSchema( TRUE ) )
646 : {
647 : // we assume an errors have been reported.
648 2 : return FALSE;
649 : }
650 :
651 48 : if( bHasFoundXSD )
652 : {
653 : CPLDebug("GML", "Generating %s file, ignoring %s",
654 0 : pszGFSFilename, pszXSDFilename);
655 : }
656 : }
657 :
658 142 : if (poReader->GetClassCount() > 1 && poReader->IsSequentialLayers() &&
659 : pszReadMode == NULL)
660 : {
661 22 : CPLDebug("GML", "Layers are monoblock. Using SEQUENTIAL_LAYERS read mode");
662 22 : eReadMode = SEQUENTIAL_LAYERS;
663 : }
664 :
665 : /* -------------------------------------------------------------------- */
666 : /* Save the schema file if possible. Don't make a fuss if we */
667 : /* can't ... could be read-only directory or something. */
668 : /* -------------------------------------------------------------------- */
669 142 : if( !bHaveSchema && !poReader->HasStoppedParsing() &&
670 : !EQUALN(pszNewName, "/vsitar/", strlen("/vsitar/")) &&
671 : !EQUALN(pszNewName, "/vsizip/", strlen("/vsizip/")) &&
672 : !EQUALN(pszNewName, "/vsigzip/vsi", strlen("/vsigzip/vsi")) &&
673 : !EQUALN(pszNewName, "/vsigzip//vsi", strlen("/vsigzip//vsi")) &&
674 : !EQUALN(pszNewName, "/vsicurl/", strlen("/vsicurl/")))
675 : {
676 48 : VSILFILE *fp = NULL;
677 :
678 48 : pszGFSFilename = CPLResetExtension( pszNewName, "gfs" );
679 48 : if (strncmp(pszGFSFilename, "/vsigzip/", strlen("/vsigzip/")) == 0)
680 0 : pszGFSFilename += strlen("/vsigzip/");
681 :
682 48 : if( VSIStatL( pszGFSFilename, &sGFSStatBuf ) != 0
683 : && (fp = VSIFOpenL( pszGFSFilename, "wt" )) != NULL )
684 : {
685 48 : VSIFCloseL( fp );
686 48 : poReader->SaveClasses( pszGFSFilename );
687 : }
688 : else
689 : {
690 : CPLDebug("GML",
691 : "Not saving %s files already exists or can't be created.",
692 0 : pszGFSFilename );
693 : }
694 : }
695 :
696 : /* -------------------------------------------------------------------- */
697 : /* Translate the GMLFeatureClasses into layers. */
698 : /* -------------------------------------------------------------------- */
699 : papoLayers = (OGRGMLLayer **)
700 142 : CPLCalloc( sizeof(OGRGMLLayer *), poReader->GetClassCount());
701 142 : nLayers = 0;
702 :
703 142 : if (poReader->GetClassCount() == 1 && nNumberOfFeatures != 0)
704 : {
705 22 : GMLFeatureClass *poClass = poReader->GetClass(0);
706 22 : int nFeatureCount = poClass->GetFeatureCount();
707 22 : if (nFeatureCount < 0)
708 : {
709 18 : poClass->SetFeatureCount(nNumberOfFeatures);
710 : }
711 4 : else if (nFeatureCount != nNumberOfFeatures)
712 : {
713 0 : CPLDebug("GML", "Feature count in header, and actual feature count don't match");
714 : }
715 : }
716 :
717 482 : while( nLayers < poReader->GetClassCount() )
718 : {
719 198 : papoLayers[nLayers] = TranslateGMLSchema(poReader->GetClass(nLayers));
720 198 : nLayers++;
721 : }
722 :
723 :
724 :
725 142 : return TRUE;
726 : }
727 :
728 : /************************************************************************/
729 : /* TranslateGMLSchema() */
730 : /************************************************************************/
731 :
732 198 : OGRGMLLayer *OGRGMLDataSource::TranslateGMLSchema( GMLFeatureClass *poClass )
733 :
734 : {
735 : OGRGMLLayer *poLayer;
736 : OGRwkbGeometryType eGType
737 198 : = (OGRwkbGeometryType) poClass->GetGeometryType();
738 :
739 198 : if( poClass->GetFeatureCount() == 0 )
740 0 : eGType = wkbUnknown;
741 :
742 : /* -------------------------------------------------------------------- */
743 : /* Create an empty layer. */
744 : /* -------------------------------------------------------------------- */
745 :
746 198 : const char* pszSRSName = poClass->GetSRSName();
747 198 : OGRSpatialReference* poSRS = NULL;
748 198 : if (pszSRSName)
749 : {
750 40 : poSRS = new OGRSpatialReference();
751 40 : if (poSRS->SetFromUserInput(pszSRSName) != OGRERR_NONE)
752 : {
753 0 : delete poSRS;
754 0 : poSRS = NULL;
755 : }
756 : }
757 :
758 : poLayer = new OGRGMLLayer( poClass->GetName(), poSRS, FALSE,
759 198 : eGType, this );
760 238 : delete poSRS;
761 :
762 : /* -------------------------------------------------------------------- */
763 : /* Added attributes (properties). */
764 : /* -------------------------------------------------------------------- */
765 198 : if (bExposeGMLId)
766 : {
767 142 : OGRFieldDefn oField( "gml_id", OFTString );
768 142 : poLayer->GetLayerDefn()->AddFieldDefn( &oField );
769 : }
770 56 : else if (bExposeFid)
771 : {
772 38 : OGRFieldDefn oField( "fid", OFTString );
773 38 : poLayer->GetLayerDefn()->AddFieldDefn( &oField );
774 : }
775 :
776 754 : for( int iField = 0; iField < poClass->GetPropertyCount(); iField++ )
777 : {
778 556 : GMLPropertyDefn *poProperty = poClass->GetProperty( iField );
779 : OGRFieldType eFType;
780 :
781 556 : if( poProperty->GetType() == GMLPT_Untyped )
782 0 : eFType = OFTString;
783 556 : else if( poProperty->GetType() == GMLPT_String )
784 220 : eFType = OFTString;
785 336 : else if( poProperty->GetType() == GMLPT_Integer )
786 222 : eFType = OFTInteger;
787 114 : else if( poProperty->GetType() == GMLPT_Real )
788 90 : eFType = OFTReal;
789 24 : else if( poProperty->GetType() == GMLPT_StringList )
790 12 : eFType = OFTStringList;
791 12 : else if( poProperty->GetType() == GMLPT_IntegerList )
792 6 : eFType = OFTIntegerList;
793 6 : else if( poProperty->GetType() == GMLPT_RealList )
794 6 : eFType = OFTRealList;
795 : else
796 0 : eFType = OFTString;
797 :
798 556 : OGRFieldDefn oField( poProperty->GetName(), eFType );
799 556 : if ( EQUALN(oField.GetNameRef(), "ogr:", 4) )
800 0 : oField.SetName(poProperty->GetName()+4);
801 556 : if( poProperty->GetWidth() > 0 )
802 186 : oField.SetWidth( poProperty->GetWidth() );
803 556 : if( poProperty->GetPrecision() > 0 )
804 14 : oField.SetPrecision( poProperty->GetPrecision() );
805 :
806 556 : poLayer->GetLayerDefn()->AddFieldDefn( &oField );
807 : }
808 :
809 198 : return poLayer;
810 : }
811 :
812 : /************************************************************************/
813 : /* GetGlobalSRSName() */
814 : /************************************************************************/
815 :
816 696 : const char *OGRGMLDataSource::GetGlobalSRSName()
817 : {
818 696 : if (poReader->CanUseGlobalSRSName() || bIsWFS)
819 546 : return poReader->GetGlobalSRSName();
820 : else
821 150 : return NULL;
822 : }
823 :
824 : /************************************************************************/
825 : /* Create() */
826 : /************************************************************************/
827 :
828 18 : int OGRGMLDataSource::Create( const char *pszFilename,
829 : char **papszOptions )
830 :
831 : {
832 18 : if( fpOutput != NULL || poReader != NULL )
833 : {
834 0 : CPLAssert( FALSE );
835 0 : return FALSE;
836 : }
837 :
838 18 : if( strcmp(pszFilename,"/dev/stdout") == 0 )
839 0 : pszFilename = "/vsistdout/";
840 :
841 : /* -------------------------------------------------------------------- */
842 : /* Read options */
843 : /* -------------------------------------------------------------------- */
844 :
845 18 : CSLDestroy(papszCreateOptions);
846 18 : papszCreateOptions = CSLDuplicate(papszOptions);
847 :
848 18 : const char* pszFormat = CSLFetchNameValue(papszCreateOptions, "FORMAT");
849 18 : bIsOutputGML3 = pszFormat && EQUAL(pszFormat, "GML3");
850 18 : bIsOutputGML3Deegree = pszFormat && EQUAL(pszFormat, "GML3Deegree");
851 18 : bIsOutputGML32 = pszFormat && EQUAL(pszFormat, "GML3.2");
852 18 : if (bIsOutputGML3Deegree || bIsOutputGML32)
853 4 : bIsOutputGML3 = TRUE;
854 :
855 : bIsLongSRSRequired =
856 18 : CSLTestBoolean(CSLFetchNameValueDef(papszCreateOptions, "GML3_LONGSRS", "YES"));
857 :
858 : bWriteSpaceIndentation =
859 18 : CSLTestBoolean(CSLFetchNameValueDef(papszCreateOptions, "SPACE_INDENTATION", "YES"));
860 :
861 : /* -------------------------------------------------------------------- */
862 : /* Create the output file. */
863 : /* -------------------------------------------------------------------- */
864 18 : pszName = CPLStrdup( pszFilename );
865 :
866 18 : if( strcmp(pszFilename,"/vsistdout/") == 0 ||
867 : strncmp(pszFilename,"/vsigzip/", 9) == 0 )
868 : {
869 0 : fpOutput = VSIFOpenL(pszFilename, "wb");
870 0 : bFpOutputIsNonSeekable = TRUE;
871 0 : bFpOutputSingleFile = TRUE;
872 : }
873 18 : else if ( strncmp(pszFilename,"/vsizip/", 8) == 0)
874 : {
875 0 : if (EQUAL(CPLGetExtension(pszFilename), "zip"))
876 : {
877 0 : CPLFree(pszName);
878 0 : pszName = CPLStrdup(CPLFormFilename(pszFilename, "out.gml", NULL));
879 : }
880 :
881 0 : fpOutput = VSIFOpenL(pszName, "wb");
882 0 : bFpOutputIsNonSeekable = TRUE;
883 : }
884 : else
885 18 : fpOutput = VSIFOpenL( pszFilename, "wb+" );
886 18 : if( fpOutput == NULL )
887 : {
888 : CPLError( CE_Failure, CPLE_OpenFailed,
889 : "Failed to create GML file %s.",
890 0 : pszFilename );
891 0 : return FALSE;
892 : }
893 :
894 : /* -------------------------------------------------------------------- */
895 : /* Write out "standard" header. */
896 : /* -------------------------------------------------------------------- */
897 : PrintLine( fpOutput, "%s",
898 18 : "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" );
899 :
900 18 : if (!bFpOutputIsNonSeekable)
901 18 : nSchemaInsertLocation = (int) VSIFTellL( fpOutput );
902 :
903 : PrintLine( fpOutput, "%s",
904 18 : "<ogr:FeatureCollection" );
905 :
906 18 : if (IsGML32Output())
907 : PrintLine( fpOutput, "%s",
908 2 : " gml:id=\"aFeatureCollection\"" );
909 :
910 : /* -------------------------------------------------------------------- */
911 : /* Write out schema info if provided in creation options. */
912 : /* -------------------------------------------------------------------- */
913 18 : const char *pszSchemaURI = CSLFetchNameValue(papszOptions,"XSISCHEMAURI");
914 18 : const char *pszSchemaOpt = CSLFetchNameValue( papszOptions, "XSISCHEMA" );
915 :
916 18 : if( pszSchemaURI != NULL )
917 : {
918 : PrintLine( fpOutput,
919 0 : " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
920 : PrintLine( fpOutput,
921 : " xsi:schemaLocation=\"%s\"",
922 0 : CSLFetchNameValue( papszOptions, "XSISCHEMAURI" ) );
923 : }
924 18 : else if( pszSchemaOpt == NULL || EQUAL(pszSchemaOpt,"EXTERNAL") )
925 : {
926 18 : char *pszBasename = CPLStrdup(CPLGetBasename( pszName ));
927 :
928 : PrintLine( fpOutput,
929 18 : " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
930 : PrintLine( fpOutput,
931 : " xsi:schemaLocation=\"http://ogr.maptools.org/ %s\"",
932 18 : CPLResetExtension( pszBasename, "xsd" ) );
933 18 : CPLFree( pszBasename );
934 : }
935 :
936 : PrintLine( fpOutput, "%s",
937 18 : " xmlns:ogr=\"http://ogr.maptools.org/\"" );
938 18 : if (IsGML32Output())
939 : PrintLine( fpOutput, "%s",
940 2 : " xmlns:gml=\"http://www.opengis.net/gml/3.2\">" );
941 : else
942 : PrintLine( fpOutput, "%s",
943 16 : " xmlns:gml=\"http://www.opengis.net/gml\">" );
944 :
945 : /* -------------------------------------------------------------------- */
946 : /* Should we initialize an area to place the boundedBy element? */
947 : /* We will need to seek back to fill it in. */
948 : /* -------------------------------------------------------------------- */
949 18 : if( CSLFetchBoolean( papszOptions, "BOUNDEDBY", TRUE ) &&
950 : !bFpOutputIsNonSeekable )
951 : {
952 18 : nBoundedByLocation = (int) VSIFTellL( fpOutput );
953 :
954 18 : if( nBoundedByLocation != -1 )
955 18 : PrintLine( fpOutput, "%350s", "" );
956 : }
957 : else
958 0 : nBoundedByLocation = -1;
959 :
960 18 : return TRUE;
961 : }
962 :
963 : /************************************************************************/
964 : /* CreateLayer() */
965 : /************************************************************************/
966 :
967 : OGRLayer *
968 18 : OGRGMLDataSource::CreateLayer( const char * pszLayerName,
969 : OGRSpatialReference *poSRS,
970 : OGRwkbGeometryType eType,
971 : char ** papszOptions )
972 :
973 : {
974 : /* -------------------------------------------------------------------- */
975 : /* Verify we are in update mode. */
976 : /* -------------------------------------------------------------------- */
977 18 : if( fpOutput == NULL )
978 : {
979 : CPLError( CE_Failure, CPLE_NoWriteAccess,
980 : "Data source %s opened for read access.\n"
981 : "New layer %s cannot be created.\n",
982 0 : pszName, pszLayerName );
983 :
984 0 : return NULL;
985 : }
986 :
987 : /* -------------------------------------------------------------------- */
988 : /* Ensure name is safe as an element name. */
989 : /* -------------------------------------------------------------------- */
990 18 : char *pszCleanLayerName = CPLStrdup( pszLayerName );
991 :
992 18 : CPLCleanXMLElementName( pszCleanLayerName );
993 18 : if( strcmp(pszCleanLayerName,pszLayerName) != 0 )
994 : {
995 : CPLError( CE_Warning, CPLE_AppDefined,
996 : "Layer name '%s' adjusted to '%s' for XML validity.",
997 0 : pszLayerName, pszCleanLayerName );
998 : }
999 :
1000 : /* -------------------------------------------------------------------- */
1001 : /* Set or check validity of global SRS. */
1002 : /* -------------------------------------------------------------------- */
1003 18 : if (nLayers == 0)
1004 : {
1005 18 : if (poSRS)
1006 10 : poGlobalSRS = poSRS->Clone();
1007 : }
1008 : else
1009 : {
1010 0 : if (poSRS == NULL ||
1011 : (poGlobalSRS != NULL && poSRS->IsSame(poGlobalSRS)))
1012 : {
1013 0 : delete poGlobalSRS;
1014 0 : poGlobalSRS = NULL;
1015 : }
1016 : }
1017 :
1018 : /* -------------------------------------------------------------------- */
1019 : /* Create the layer object. */
1020 : /* -------------------------------------------------------------------- */
1021 : OGRGMLLayer *poLayer;
1022 :
1023 18 : poLayer = new OGRGMLLayer( pszCleanLayerName, poSRS, TRUE, eType, this );
1024 :
1025 18 : CPLFree( pszCleanLayerName );
1026 :
1027 : /* -------------------------------------------------------------------- */
1028 : /* Add layer to data source layer list. */
1029 : /* -------------------------------------------------------------------- */
1030 : papoLayers = (OGRGMLLayer **)
1031 18 : CPLRealloc( papoLayers, sizeof(OGRGMLLayer *) * (nLayers+1) );
1032 :
1033 18 : papoLayers[nLayers++] = poLayer;
1034 :
1035 18 : return poLayer;
1036 : }
1037 :
1038 : /************************************************************************/
1039 : /* TestCapability() */
1040 : /************************************************************************/
1041 :
1042 6 : int OGRGMLDataSource::TestCapability( const char * pszCap )
1043 :
1044 : {
1045 6 : if( EQUAL(pszCap,ODsCCreateLayer) )
1046 6 : return TRUE;
1047 : else
1048 0 : return FALSE;
1049 : }
1050 :
1051 : /************************************************************************/
1052 : /* GetLayer() */
1053 : /************************************************************************/
1054 :
1055 248 : OGRLayer *OGRGMLDataSource::GetLayer( int iLayer )
1056 :
1057 : {
1058 248 : if( iLayer < 0 || iLayer >= nLayers )
1059 0 : return NULL;
1060 : else
1061 248 : return papoLayers[iLayer];
1062 : }
1063 :
1064 : /************************************************************************/
1065 : /* GrowExtents() */
1066 : /************************************************************************/
1067 :
1068 52 : void OGRGMLDataSource::GrowExtents( OGREnvelope3D *psGeomBounds, int nCoordDimension )
1069 :
1070 : {
1071 52 : sBoundingRect.Merge( *psGeomBounds );
1072 52 : if (nCoordDimension == 3)
1073 40 : bBBOX3D = TRUE;
1074 52 : }
1075 :
1076 : /************************************************************************/
1077 : /* InsertHeader() */
1078 : /* */
1079 : /* This method is used to update boundedby info for a */
1080 : /* dataset, and insert schema descriptions depending on */
1081 : /* selection options in effect. */
1082 : /************************************************************************/
1083 :
1084 18 : void OGRGMLDataSource::InsertHeader()
1085 :
1086 : {
1087 : VSILFILE *fpSchema;
1088 18 : int nSchemaStart = 0;
1089 :
1090 18 : if( bFpOutputSingleFile )
1091 0 : return;
1092 :
1093 : /* -------------------------------------------------------------------- */
1094 : /* Do we want to write the schema within the GML instance doc */
1095 : /* or to a separate file? For now we only support external. */
1096 : /* -------------------------------------------------------------------- */
1097 : const char *pszSchemaURI = CSLFetchNameValue(papszCreateOptions,
1098 18 : "XSISCHEMAURI");
1099 : const char *pszSchemaOpt = CSLFetchNameValue( papszCreateOptions,
1100 18 : "XSISCHEMA" );
1101 :
1102 18 : if( pszSchemaURI != NULL )
1103 0 : return;
1104 :
1105 36 : if( pszSchemaOpt == NULL || EQUAL(pszSchemaOpt,"EXTERNAL") )
1106 : {
1107 18 : const char *pszXSDFilename = CPLResetExtension( pszName, "xsd" );
1108 :
1109 18 : fpSchema = VSIFOpenL( pszXSDFilename, "wt" );
1110 18 : if( fpSchema == NULL )
1111 : {
1112 : CPLError( CE_Failure, CPLE_OpenFailed,
1113 : "Failed to open file %.500s for schema output.",
1114 0 : pszXSDFilename );
1115 0 : return;
1116 : }
1117 18 : PrintLine( fpSchema, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" );
1118 : }
1119 0 : else if( EQUAL(pszSchemaOpt,"INTERNAL") )
1120 : {
1121 0 : if (fpOutput == NULL)
1122 0 : return;
1123 0 : nSchemaStart = (int) VSIFTellL( fpOutput );
1124 0 : fpSchema = fpOutput;
1125 : }
1126 : else
1127 0 : return;
1128 :
1129 : /* ==================================================================== */
1130 : /* Write the schema section at the end of the file. Once */
1131 : /* complete, we will read it back in, and then move the whole */
1132 : /* file "down" enough to insert the schema at the beginning. */
1133 : /* ==================================================================== */
1134 :
1135 : /* -------------------------------------------------------------------- */
1136 : /* Emit the start of the schema section. */
1137 : /* -------------------------------------------------------------------- */
1138 18 : const char *pszTargetNameSpace = "http://ogr.maptools.org/";
1139 18 : const char *pszPrefix = "ogr";
1140 :
1141 18 : if (IsGML3Output())
1142 : {
1143 : PrintLine( fpSchema,
1144 8 : "<xs:schema ");
1145 : PrintLine( fpSchema,
1146 8 : " targetNamespace=\"%s\"", pszTargetNameSpace );
1147 : PrintLine( fpSchema,
1148 : " xmlns:%s=\"%s\"",
1149 8 : pszPrefix, pszTargetNameSpace );
1150 : PrintLine( fpSchema,
1151 8 : " xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"");
1152 8 : if (IsGML32Output())
1153 : {
1154 : PrintLine( fpSchema,
1155 2 : " xmlns:gml=\"http://www.opengis.net/gml/3.2\"");
1156 : PrintLine( fpSchema,
1157 2 : " xmlns:gmlsf=\"http://www.opengis.net/gmlsf/2.0\"");
1158 : }
1159 : else
1160 : {
1161 : PrintLine( fpSchema,
1162 6 : " xmlns:gml=\"http://www.opengis.net/gml\"");
1163 6 : if (!IsGML3DeegreeOutput())
1164 : {
1165 : PrintLine( fpSchema,
1166 4 : " xmlns:gmlsf=\"http://www.opengis.net/gmlsf\"");
1167 : }
1168 : }
1169 : PrintLine( fpSchema,
1170 8 : " elementFormDefault=\"qualified\"");
1171 : PrintLine( fpSchema,
1172 8 : " version=\"1.0\">");
1173 :
1174 8 : if (IsGML32Output())
1175 : {
1176 : PrintLine( fpSchema,
1177 2 : "<xs:annotation>");
1178 : PrintLine( fpSchema,
1179 2 : " <xs:appinfo source=\"http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd\">");
1180 : PrintLine( fpSchema,
1181 2 : " <gmlsf:ComplianceLevel>0</gmlsf:ComplianceLevel>");
1182 : PrintLine( fpSchema,
1183 2 : " </xs:appinfo>");
1184 : PrintLine( fpSchema,
1185 2 : "</xs:annotation>");
1186 :
1187 : PrintLine( fpSchema,
1188 2 : "<xs:import namespace=\"http://www.opengis.net/gml/3.2\" schemaLocation=\"http://schemas.opengis.net/gml/3.2.1/gml.xsd\"/>" );
1189 : PrintLine( fpSchema,
1190 2 : "<xs:import namespace=\"http://www.opengis.net/gmlsf/2.0\" schemaLocation=\"http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd\"/>" );
1191 : }
1192 : else
1193 : {
1194 6 : if (!IsGML3DeegreeOutput())
1195 : {
1196 : PrintLine( fpSchema,
1197 4 : "<xs:annotation>");
1198 : PrintLine( fpSchema,
1199 4 : " <xs:appinfo source=\"http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsfLevels.xsd\">");
1200 : PrintLine( fpSchema,
1201 4 : " <gmlsf:ComplianceLevel>0</gmlsf:ComplianceLevel>");
1202 : PrintLine( fpSchema,
1203 4 : " <gmlsf:GMLProfileSchema>http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd</gmlsf:GMLProfileSchema>");
1204 : PrintLine( fpSchema,
1205 4 : " </xs:appinfo>");
1206 : PrintLine( fpSchema,
1207 4 : "</xs:annotation>");
1208 : }
1209 :
1210 : PrintLine( fpSchema,
1211 6 : "<xs:import namespace=\"http://www.opengis.net/gml\" schemaLocation=\"http://schemas.opengis.net/gml/3.1.1/base/gml.xsd\"/>" );
1212 6 : if (!IsGML3DeegreeOutput())
1213 : {
1214 : PrintLine( fpSchema,
1215 4 : "<xs:import namespace=\"http://www.opengis.net/gmlsf\" schemaLocation=\"http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsfLevels.xsd\"/>" );
1216 : }
1217 : }
1218 : }
1219 : else
1220 : {
1221 : PrintLine( fpSchema,
1222 : "<xs:schema targetNamespace=\"%s\" xmlns:%s=\"%s\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:gml=\"http://www.opengis.net/gml\" elementFormDefault=\"qualified\" version=\"1.0\">",
1223 10 : pszTargetNameSpace, pszPrefix, pszTargetNameSpace );
1224 :
1225 : PrintLine( fpSchema,
1226 10 : "<xs:import namespace=\"http://www.opengis.net/gml\" schemaLocation=\"http://schemas.opengis.net/gml/2.1.2/feature.xsd\"/>" );
1227 : }
1228 :
1229 : /* -------------------------------------------------------------------- */
1230 : /* Define the FeatureCollection */
1231 : /* -------------------------------------------------------------------- */
1232 18 : if (IsGML3Output())
1233 : {
1234 8 : if (IsGML32Output())
1235 : {
1236 : PrintLine( fpSchema,
1237 : "<xs:element name=\"FeatureCollection\" type=\"%s:FeatureCollectionType\" substitutionGroup=\"gml:AbstractGML\"/>",
1238 2 : pszPrefix );
1239 : }
1240 6 : else if (IsGML3DeegreeOutput())
1241 : {
1242 : PrintLine( fpSchema,
1243 : "<xs:element name=\"FeatureCollection\" type=\"%s:FeatureCollectionType\" substitutionGroup=\"gml:_FeatureCollection\"/>",
1244 2 : pszPrefix );
1245 : }
1246 : else
1247 : {
1248 : PrintLine( fpSchema,
1249 : "<xs:element name=\"FeatureCollection\" type=\"%s:FeatureCollectionType\" substitutionGroup=\"gml:_GML\"/>",
1250 4 : pszPrefix );
1251 : }
1252 :
1253 8 : PrintLine( fpSchema, "<xs:complexType name=\"FeatureCollectionType\">");
1254 8 : PrintLine( fpSchema, " <xs:complexContent>" );
1255 8 : if (IsGML3DeegreeOutput())
1256 : {
1257 2 : PrintLine( fpSchema, " <xs:extension base=\"gml:AbstractFeatureCollectionType\">" );
1258 2 : PrintLine( fpSchema, " <xs:sequence>" );
1259 2 : PrintLine( fpSchema, " <xs:element name=\"featureMember\" minOccurs=\"0\" maxOccurs=\"unbounded\">" );
1260 : }
1261 : else
1262 : {
1263 6 : PrintLine( fpSchema, " <xs:extension base=\"gml:AbstractFeatureType\">" );
1264 6 : PrintLine( fpSchema, " <xs:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">" );
1265 6 : PrintLine( fpSchema, " <xs:element name=\"featureMember\">" );
1266 : }
1267 8 : PrintLine( fpSchema, " <xs:complexType>" );
1268 8 : if (IsGML32Output())
1269 : {
1270 2 : PrintLine( fpSchema, " <xs:complexContent>" );
1271 2 : PrintLine( fpSchema, " <xs:extension base=\"gml:AbstractFeatureMemberType\">" );
1272 2 : PrintLine( fpSchema, " <xs:sequence>" );
1273 2 : PrintLine( fpSchema, " <xs:element ref=\"gml:AbstractFeature\"/>" );
1274 2 : PrintLine( fpSchema, " </xs:sequence>" );
1275 2 : PrintLine( fpSchema, " </xs:extension>" );
1276 2 : PrintLine( fpSchema, " </xs:complexContent>" );
1277 : }
1278 : else
1279 : {
1280 6 : PrintLine( fpSchema, " <xs:sequence>" );
1281 6 : PrintLine( fpSchema, " <xs:element ref=\"gml:_Feature\"/>" );
1282 6 : PrintLine( fpSchema, " </xs:sequence>" );
1283 : }
1284 8 : PrintLine( fpSchema, " </xs:complexType>" );
1285 8 : PrintLine( fpSchema, " </xs:element>" );
1286 8 : PrintLine( fpSchema, " </xs:sequence>" );
1287 8 : PrintLine( fpSchema, " </xs:extension>" );
1288 8 : PrintLine( fpSchema, " </xs:complexContent>" );
1289 8 : PrintLine( fpSchema, "</xs:complexType>" );
1290 : }
1291 : else
1292 : {
1293 : PrintLine( fpSchema,
1294 : "<xs:element name=\"FeatureCollection\" type=\"%s:FeatureCollectionType\" substitutionGroup=\"gml:_FeatureCollection\"/>",
1295 10 : pszPrefix );
1296 :
1297 10 : PrintLine( fpSchema, "<xs:complexType name=\"FeatureCollectionType\">");
1298 10 : PrintLine( fpSchema, " <xs:complexContent>" );
1299 10 : PrintLine( fpSchema, " <xs:extension base=\"gml:AbstractFeatureCollectionType\">" );
1300 10 : PrintLine( fpSchema, " <xs:attribute name=\"lockId\" type=\"xs:string\" use=\"optional\"/>" );
1301 10 : PrintLine( fpSchema, " <xs:attribute name=\"scope\" type=\"xs:string\" use=\"optional\"/>" );
1302 10 : PrintLine( fpSchema, " </xs:extension>" );
1303 10 : PrintLine( fpSchema, " </xs:complexContent>" );
1304 10 : PrintLine( fpSchema, "</xs:complexType>" );
1305 : }
1306 :
1307 : /* ==================================================================== */
1308 : /* Define the schema for each layer. */
1309 : /* ==================================================================== */
1310 : int iLayer;
1311 :
1312 36 : for( iLayer = 0; iLayer < GetLayerCount(); iLayer++ )
1313 : {
1314 18 : OGRFeatureDefn *poFDefn = GetLayer(iLayer)->GetLayerDefn();
1315 :
1316 : /* -------------------------------------------------------------------- */
1317 : /* Emit initial stuff for a feature type. */
1318 : /* -------------------------------------------------------------------- */
1319 18 : if (IsGML32Output())
1320 : {
1321 : PrintLine(
1322 : fpSchema,
1323 : "<xs:element name=\"%s\" type=\"%s:%s_Type\" substitutionGroup=\"gml:AbstractFeature\"/>",
1324 2 : poFDefn->GetName(), pszPrefix, poFDefn->GetName() );
1325 : }
1326 : else
1327 : {
1328 : PrintLine(
1329 : fpSchema,
1330 : "<xs:element name=\"%s\" type=\"%s:%s_Type\" substitutionGroup=\"gml:_Feature\"/>",
1331 16 : poFDefn->GetName(), pszPrefix, poFDefn->GetName() );
1332 : }
1333 :
1334 18 : PrintLine( fpSchema, "<xs:complexType name=\"%s_Type\">", poFDefn->GetName());
1335 18 : PrintLine( fpSchema, " <xs:complexContent>");
1336 18 : PrintLine( fpSchema, " <xs:extension base=\"gml:AbstractFeatureType\">");
1337 18 : PrintLine( fpSchema, " <xs:sequence>");
1338 :
1339 : /* -------------------------------------------------------------------- */
1340 : /* Define the geometry attribute. */
1341 : /* -------------------------------------------------------------------- */
1342 18 : const char* pszGeometryTypeName = "GeometryPropertyType";
1343 18 : switch(wkbFlatten(poFDefn->GetGeomType()))
1344 : {
1345 : case wkbPoint:
1346 0 : pszGeometryTypeName = "PointPropertyType";
1347 0 : break;
1348 : case wkbLineString:
1349 0 : if (IsGML3Output())
1350 0 : pszGeometryTypeName = "CurvePropertyType";
1351 : else
1352 0 : pszGeometryTypeName = "LineStringPropertyType";
1353 0 : break;
1354 : case wkbPolygon:
1355 4 : if (IsGML3Output())
1356 2 : pszGeometryTypeName = "SurfacePropertyType";
1357 : else
1358 2 : pszGeometryTypeName = "PolygonPropertyType";
1359 4 : break;
1360 : case wkbMultiPoint:
1361 0 : pszGeometryTypeName = "MultiPointPropertyType";
1362 0 : break;
1363 : case wkbMultiLineString:
1364 0 : if (IsGML3Output())
1365 0 : pszGeometryTypeName = "MutliCurvePropertyType";
1366 : else
1367 0 : pszGeometryTypeName = "MultiLineStringPropertyType";
1368 0 : break;
1369 : case wkbMultiPolygon:
1370 0 : if (IsGML3Output())
1371 0 : pszGeometryTypeName = "MultiSurfacePropertyType";
1372 : else
1373 0 : pszGeometryTypeName = "MultiPolygonPropertyType";
1374 0 : break;
1375 : case wkbGeometryCollection:
1376 0 : pszGeometryTypeName = "MultiGeometryPropertyType";
1377 : break;
1378 : default:
1379 : break;
1380 : }
1381 :
1382 18 : if (poFDefn->GetGeomType() != wkbNone)
1383 : {
1384 : PrintLine( fpSchema,
1385 16 : " <xs:element name=\"geometryProperty\" type=\"gml:%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\"/>", pszGeometryTypeName );
1386 : }
1387 :
1388 : /* -------------------------------------------------------------------- */
1389 : /* Emit each of the attributes. */
1390 : /* -------------------------------------------------------------------- */
1391 54 : for( int iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
1392 : {
1393 36 : OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn(iField);
1394 :
1395 36 : if( poFieldDefn->GetType() == OFTInteger )
1396 : {
1397 : int nWidth;
1398 :
1399 4 : if( poFieldDefn->GetWidth() > 0 )
1400 4 : nWidth = poFieldDefn->GetWidth();
1401 : else
1402 0 : nWidth = 16;
1403 :
1404 4 : PrintLine( fpSchema, " <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">", poFieldDefn->GetNameRef());
1405 4 : PrintLine( fpSchema, " <xs:simpleType>");
1406 4 : PrintLine( fpSchema, " <xs:restriction base=\"xs:integer\">");
1407 4 : PrintLine( fpSchema, " <xs:totalDigits value=\"%d\"/>", nWidth);
1408 4 : PrintLine( fpSchema, " </xs:restriction>");
1409 4 : PrintLine( fpSchema, " </xs:simpleType>");
1410 4 : PrintLine( fpSchema, " </xs:element>");
1411 : }
1412 32 : else if( poFieldDefn->GetType() == OFTReal )
1413 : {
1414 : int nWidth, nDecimals;
1415 :
1416 12 : nWidth = poFieldDefn->GetWidth();
1417 12 : nDecimals = poFieldDefn->GetPrecision();
1418 :
1419 12 : PrintLine( fpSchema, " <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">", poFieldDefn->GetNameRef());
1420 12 : PrintLine( fpSchema, " <xs:simpleType>");
1421 12 : PrintLine( fpSchema, " <xs:restriction base=\"xs:decimal\">");
1422 12 : if (nWidth > 0)
1423 : {
1424 10 : PrintLine( fpSchema, " <xs:totalDigits value=\"%d\"/>", nWidth);
1425 10 : PrintLine( fpSchema, " <xs:fractionDigits value=\"%d\"/>", nDecimals);
1426 : }
1427 12 : PrintLine( fpSchema, " </xs:restriction>");
1428 12 : PrintLine( fpSchema, " </xs:simpleType>");
1429 12 : PrintLine( fpSchema, " </xs:element>");
1430 : }
1431 20 : else if( poFieldDefn->GetType() == OFTString )
1432 : {
1433 18 : PrintLine( fpSchema, " <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">", poFieldDefn->GetNameRef());
1434 18 : PrintLine( fpSchema, " <xs:simpleType>");
1435 18 : PrintLine( fpSchema, " <xs:restriction base=\"xs:string\">");
1436 18 : if( poFieldDefn->GetWidth() != 0 )
1437 : {
1438 8 : PrintLine( fpSchema, " <xs:maxLength value=\"%d\"/>", poFieldDefn->GetWidth());
1439 : }
1440 18 : PrintLine( fpSchema, " </xs:restriction>");
1441 18 : PrintLine( fpSchema, " </xs:simpleType>");
1442 18 : PrintLine( fpSchema, " </xs:element>");
1443 : }
1444 2 : else if( poFieldDefn->GetType() == OFTDate || poFieldDefn->GetType() == OFTDateTime )
1445 : {
1446 2 : PrintLine( fpSchema, " <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">", poFieldDefn->GetNameRef());
1447 2 : PrintLine( fpSchema, " <xs:simpleType>");
1448 2 : PrintLine( fpSchema, " <xs:restriction base=\"xs:string\">");
1449 2 : PrintLine( fpSchema, " </xs:restriction>");
1450 2 : PrintLine( fpSchema, " </xs:simpleType>");
1451 2 : PrintLine( fpSchema, " </xs:element>");
1452 : }
1453 : else
1454 : {
1455 : /* TODO */
1456 : }
1457 : } /* next field */
1458 :
1459 : /* -------------------------------------------------------------------- */
1460 : /* Finish off feature type. */
1461 : /* -------------------------------------------------------------------- */
1462 18 : PrintLine( fpSchema, " </xs:sequence>");
1463 18 : PrintLine( fpSchema, " </xs:extension>");
1464 18 : PrintLine( fpSchema, " </xs:complexContent>");
1465 18 : PrintLine( fpSchema, "</xs:complexType>" );
1466 : } /* next layer */
1467 :
1468 18 : PrintLine( fpSchema, "</xs:schema>" );
1469 :
1470 : /* ==================================================================== */
1471 : /* Move schema to the start of the file. */
1472 : /* ==================================================================== */
1473 18 : if( fpSchema == fpOutput )
1474 : {
1475 : /* -------------------------------------------------------------------- */
1476 : /* Read the schema into memory. */
1477 : /* -------------------------------------------------------------------- */
1478 0 : int nSchemaSize = (int) VSIFTellL( fpOutput ) - nSchemaStart;
1479 0 : char *pszSchema = (char *) CPLMalloc(nSchemaSize+1);
1480 :
1481 0 : VSIFSeekL( fpOutput, nSchemaStart, SEEK_SET );
1482 :
1483 0 : VSIFReadL( pszSchema, 1, nSchemaSize, fpOutput );
1484 0 : pszSchema[nSchemaSize] = '\0';
1485 :
1486 : /* -------------------------------------------------------------------- */
1487 : /* Move file data down by "schema size" bytes from after <?xml> */
1488 : /* header so we have room insert the schema. Move in pretty */
1489 : /* big chunks. */
1490 : /* -------------------------------------------------------------------- */
1491 0 : int nChunkSize = MIN(nSchemaStart-nSchemaInsertLocation,250000);
1492 0 : char *pszChunk = (char *) CPLMalloc(nChunkSize);
1493 0 : int nEndOfUnmovedData = nSchemaStart;
1494 :
1495 0 : for( nEndOfUnmovedData = nSchemaStart;
1496 : nEndOfUnmovedData > nSchemaInsertLocation; )
1497 : {
1498 : int nBytesToMove =
1499 0 : MIN(nChunkSize, nEndOfUnmovedData - nSchemaInsertLocation );
1500 :
1501 0 : VSIFSeekL( fpOutput, nEndOfUnmovedData - nBytesToMove, SEEK_SET );
1502 0 : VSIFReadL( pszChunk, 1, nBytesToMove, fpOutput );
1503 : VSIFSeekL( fpOutput, nEndOfUnmovedData - nBytesToMove + nSchemaSize,
1504 0 : SEEK_SET );
1505 0 : VSIFWriteL( pszChunk, 1, nBytesToMove, fpOutput );
1506 :
1507 0 : nEndOfUnmovedData -= nBytesToMove;
1508 : }
1509 :
1510 0 : CPLFree( pszChunk );
1511 :
1512 : /* -------------------------------------------------------------------- */
1513 : /* Write the schema in the opened slot. */
1514 : /* -------------------------------------------------------------------- */
1515 0 : VSIFSeekL( fpOutput, nSchemaInsertLocation, SEEK_SET );
1516 0 : VSIFWriteL( pszSchema, 1, nSchemaSize, fpOutput );
1517 :
1518 0 : VSIFSeekL( fpOutput, 0, SEEK_END );
1519 :
1520 0 : nBoundedByLocation += nSchemaSize;
1521 :
1522 0 : CPLFree(pszSchema);
1523 : }
1524 : /* -------------------------------------------------------------------- */
1525 : /* Close external schema files. */
1526 : /* -------------------------------------------------------------------- */
1527 : else
1528 18 : VSIFCloseL( fpSchema );
1529 : }
1530 :
1531 :
1532 : /************************************************************************/
1533 : /* PrintLine() */
1534 : /************************************************************************/
1535 :
1536 1524 : void OGRGMLDataSource::PrintLine(VSILFILE* fp, const char *fmt, ...)
1537 : {
1538 1524 : CPLString osWork;
1539 : va_list args;
1540 :
1541 1524 : va_start( args, fmt );
1542 1524 : osWork.vPrintf( fmt, args );
1543 1524 : va_end( args );
1544 :
1545 : #ifdef WIN32
1546 : const char* pszEOL = "\r\n";
1547 : #else
1548 1524 : const char* pszEOL = "\n";
1549 : #endif
1550 :
1551 1524 : VSIFPrintfL(fp, "%s%s", osWork.c_str(), pszEOL);
1552 1524 : }
1553 :
1554 :
1555 : /************************************************************************/
1556 : /* OGRGMLSingleFeatureLayer */
1557 : /************************************************************************/
1558 :
1559 : class OGRGMLSingleFeatureLayer : public OGRLayer
1560 : {
1561 : private:
1562 : int nVal;
1563 : OGRFeatureDefn *poFeatureDefn;
1564 : int iNextShapeId;
1565 :
1566 : public:
1567 : OGRGMLSingleFeatureLayer(int nVal );
1568 4 : ~OGRGMLSingleFeatureLayer() { poFeatureDefn->Release(); }
1569 :
1570 0 : virtual void ResetReading() { iNextShapeId = 0; }
1571 : virtual OGRFeature *GetNextFeature();
1572 0 : virtual OGRFeatureDefn *GetLayerDefn() { return poFeatureDefn; }
1573 0 : virtual int TestCapability( const char * ) { return FALSE; }
1574 : };
1575 :
1576 : /************************************************************************/
1577 : /* OGRGMLSingleFeatureLayer() */
1578 : /************************************************************************/
1579 :
1580 4 : OGRGMLSingleFeatureLayer::OGRGMLSingleFeatureLayer( int nVal )
1581 : {
1582 4 : poFeatureDefn = new OGRFeatureDefn( "SELECT" );
1583 4 : poFeatureDefn->Reference();
1584 4 : OGRFieldDefn oField( "Validates", OFTInteger );
1585 4 : poFeatureDefn->AddFieldDefn( &oField );
1586 :
1587 4 : this->nVal = nVal;
1588 4 : iNextShapeId = 0;
1589 4 : }
1590 :
1591 : /************************************************************************/
1592 : /* GetNextFeature() */
1593 : /************************************************************************/
1594 :
1595 4 : OGRFeature * OGRGMLSingleFeatureLayer::GetNextFeature()
1596 : {
1597 4 : if (iNextShapeId != 0)
1598 0 : return NULL;
1599 :
1600 4 : OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
1601 4 : poFeature->SetField(0, nVal);
1602 4 : poFeature->SetFID(iNextShapeId ++);
1603 4 : return poFeature;
1604 : }
1605 :
1606 : /************************************************************************/
1607 : /* ExecuteSQL() */
1608 : /************************************************************************/
1609 :
1610 6 : OGRLayer * OGRGMLDataSource::ExecuteSQL( const char *pszSQLCommand,
1611 : OGRGeometry *poSpatialFilter,
1612 : const char *pszDialect )
1613 : {
1614 6 : if (EQUAL(pszSQLCommand, "SELECT ValidateSchema()"))
1615 : {
1616 4 : CPLString osXSDFilename = CPLResetExtension( pszName, "xsd" );
1617 4 : int bIsValid = FALSE;
1618 4 : CPLErrorReset();
1619 4 : CPLXMLSchemaPtr pSchema = CPLLoadXMLSchema(osXSDFilename);
1620 4 : if (pSchema)
1621 : {
1622 4 : bIsValid = CPLValidateXML(pszName, pSchema, NULL);
1623 4 : CPLFreeXMLSchema(pSchema);
1624 : }
1625 : else
1626 : {
1627 0 : if (strstr(CPLGetLastErrorMsg(), "not implemented due to missing libxml2 support") == NULL)
1628 : {
1629 : CPLError(CE_Failure, CPLE_AppDefined,
1630 0 : "Cannot load %s", osXSDFilename.c_str());
1631 : }
1632 : }
1633 :
1634 4 : return new OGRGMLSingleFeatureLayer(bIsValid);
1635 : }
1636 :
1637 2 : return OGRDataSource::ExecuteSQL(pszSQLCommand, poSpatialFilter, pszDialect);
1638 : }
1639 :
1640 : /************************************************************************/
1641 : /* ReleaseResultSet() */
1642 : /************************************************************************/
1643 :
1644 6 : void OGRGMLDataSource::ReleaseResultSet( OGRLayer * poResultsSet )
1645 : {
1646 6 : delete poResultsSet;
1647 6 : }
|