1 : /******************************************************************************
2 : * $Id: ogrgmllayer.cpp 23705 2012-01-06 15:47:31Z rouault $
3 : *
4 : * Project: OGR
5 : * Purpose: Implements OGRGMLLayer 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 : #include "ogr_gml.h"
31 : #include "gmlutils.h"
32 : #include "cpl_conv.h"
33 : #include "cpl_port.h"
34 : #include "cpl_string.h"
35 : #include "ogr_p.h"
36 : #include "ogr_api.h"
37 :
38 : CPL_CVSID("$Id: ogrgmllayer.cpp 23705 2012-01-06 15:47:31Z rouault $");
39 :
40 : /************************************************************************/
41 : /* OGRGMLLayer() */
42 : /************************************************************************/
43 :
44 216 : OGRGMLLayer::OGRGMLLayer( const char * pszName,
45 : OGRSpatialReference *poSRSIn, int bWriterIn,
46 : OGRwkbGeometryType eReqType,
47 216 : OGRGMLDataSource *poDSIn )
48 :
49 : {
50 216 : if( poSRSIn == NULL )
51 166 : poSRS = NULL;
52 : else
53 50 : poSRS = poSRSIn->Clone();
54 :
55 216 : iNextGMLId = 0;
56 216 : nTotalGMLCount = -1;
57 216 : bInvalidFIDFound = FALSE;
58 216 : pszFIDPrefix = NULL;
59 216 : bFaceHoleNegative = FALSE;
60 :
61 216 : poDS = poDSIn;
62 :
63 216 : if ( EQUALN(pszName, "ogr:", 4) )
64 0 : poFeatureDefn = new OGRFeatureDefn( pszName+4 );
65 : else
66 216 : poFeatureDefn = new OGRFeatureDefn( pszName );
67 216 : poFeatureDefn->Reference();
68 216 : poFeatureDefn->SetGeomType( eReqType );
69 :
70 216 : bWriter = bWriterIn;
71 :
72 : /* -------------------------------------------------------------------- */
73 : /* Reader's should get the corresponding GMLFeatureClass and */
74 : /* cache it. */
75 : /* -------------------------------------------------------------------- */
76 216 : if( !bWriter )
77 198 : poFClass = poDS->GetReader()->GetClass( pszName );
78 : else
79 18 : poFClass = NULL;
80 :
81 216 : hCacheSRS = GML_BuildOGRGeometryFromList_CreateCache();
82 :
83 : /* Compatibility option. Not advertized, because hopefully won't be needed */
84 : /* Just put here in provision... */
85 216 : bUseOldFIDFormat = CSLTestBoolean(CPLGetConfigOption("GML_USE_OLD_FID_FORMAT", "FALSE"));
86 :
87 : /* Must be in synced in OGR_G_CreateFromGML(), OGRGMLLayer::OGRGMLLayer() and GMLReader::GMLReader() */
88 216 : bFaceHoleNegative = CSLTestBoolean(CPLGetConfigOption("GML_FACE_HOLE_NEGATIVE", "NO"));
89 :
90 216 : }
91 :
92 : /************************************************************************/
93 : /* ~OGRGMLLayer() */
94 : /************************************************************************/
95 :
96 216 : OGRGMLLayer::~OGRGMLLayer()
97 :
98 : {
99 216 : CPLFree(pszFIDPrefix);
100 :
101 216 : if( poFeatureDefn )
102 216 : poFeatureDefn->Release();
103 :
104 216 : if( poSRS != NULL )
105 50 : poSRS->Release();
106 :
107 216 : GML_BuildOGRGeometryFromList_DestroyCache(hCacheSRS);
108 216 : }
109 :
110 : /************************************************************************/
111 : /* ResetReading() */
112 : /************************************************************************/
113 :
114 316 : void OGRGMLLayer::ResetReading()
115 :
116 : {
117 316 : if (bWriter)
118 0 : return;
119 :
120 316 : if (poDS->GetReadMode() == INTERLEAVED_LAYERS ||
121 : poDS->GetReadMode() == SEQUENTIAL_LAYERS)
122 : {
123 : /* Does the last stored feature belong to our layer ? If so, no */
124 : /* need to reset the reader */
125 32 : if (iNextGMLId == 0 && poDS->PeekStoredGMLFeature() != NULL &&
126 : poDS->PeekStoredGMLFeature()->GetClass() == poFClass)
127 0 : return;
128 :
129 32 : delete poDS->PeekStoredGMLFeature();
130 32 : poDS->SetStoredGMLFeature(NULL);
131 : }
132 :
133 316 : iNextGMLId = 0;
134 316 : poDS->GetReader()->ResetReading();
135 316 : CPLDebug("GML", "ResetReading()");
136 316 : if (poDS->GetLayerCount() > 1 && poDS->GetReadMode() == STANDARD)
137 6 : poDS->GetReader()->SetFilteredClassName(poFClass->GetName());
138 : }
139 :
140 : /************************************************************************/
141 : /* GetNextFeature() */
142 : /************************************************************************/
143 :
144 778 : OGRFeature *OGRGMLLayer::GetNextFeature()
145 :
146 : {
147 778 : GMLFeature *poGMLFeature = NULL;
148 778 : OGRGeometry *poGeom = NULL;
149 :
150 778 : if (bWriter)
151 : {
152 : CPLError(CE_Failure, CPLE_NotSupported,
153 0 : "Cannot read features when writing a GML file");
154 0 : return NULL;
155 : }
156 :
157 778 : if( poDS->GetLastReadLayer() != this )
158 : {
159 138 : if( poDS->GetReadMode() != INTERLEAVED_LAYERS )
160 120 : ResetReading();
161 138 : poDS->SetLastReadLayer(this);
162 : }
163 :
164 : /* ==================================================================== */
165 : /* Loop till we find and translate a feature meeting all our */
166 : /* requirements. */
167 : /* ==================================================================== */
168 702 : while( TRUE )
169 : {
170 : /* -------------------------------------------------------------------- */
171 : /* Cleanup last feature, and get a new raw gml feature. */
172 : /* -------------------------------------------------------------------- */
173 1480 : if( poGMLFeature != NULL )
174 702 : delete poGMLFeature;
175 :
176 1480 : if( poGeom != NULL )
177 : {
178 20 : delete poGeom;
179 20 : poGeom = NULL;
180 : }
181 :
182 1480 : poGMLFeature = poDS->PeekStoredGMLFeature();
183 1480 : if (poGMLFeature != NULL)
184 6 : poDS->SetStoredGMLFeature(NULL);
185 : else
186 : {
187 1474 : poGMLFeature = poDS->GetReader()->NextFeature();
188 1474 : if( poGMLFeature == NULL )
189 92 : return NULL;
190 :
191 : // We count reading low level GML features as a feature read for
192 : // work checking purposes, though at least we didn't necessary
193 : // have to turn it into an OGRFeature.
194 1382 : m_nFeaturesRead++;
195 : }
196 :
197 : /* -------------------------------------------------------------------- */
198 : /* Is it of the proper feature class? */
199 : /* -------------------------------------------------------------------- */
200 :
201 1388 : if( poGMLFeature->GetClass() != poFClass )
202 : {
203 676 : if( poDS->GetReadMode() == INTERLEAVED_LAYERS ||
204 : (poDS->GetReadMode() == SEQUENTIAL_LAYERS && iNextGMLId != 0) )
205 : {
206 8 : CPLAssert(poDS->PeekStoredGMLFeature() == NULL);
207 8 : poDS->SetStoredGMLFeature(poGMLFeature);
208 8 : return NULL;
209 : }
210 : else
211 668 : continue;
212 : }
213 :
214 : /* -------------------------------------------------------------------- */
215 : /* Extract the fid: */
216 : /* -Assumes the fids are non-negative integers with an optional */
217 : /* prefix */
218 : /* -If a prefix differs from the prefix of the first feature from */
219 : /* the poDS then the fids from the poDS are ignored and are */
220 : /* assigned serially thereafter */
221 : /* -------------------------------------------------------------------- */
222 712 : int nFID = -1;
223 712 : const char * pszGML_FID = poGMLFeature->GetFID();
224 712 : if( bInvalidFIDFound )
225 : {
226 128 : nFID = iNextGMLId++;
227 : }
228 584 : else if( pszGML_FID == NULL )
229 : {
230 60 : bInvalidFIDFound = TRUE;
231 60 : nFID = iNextGMLId++;
232 : }
233 524 : else if( iNextGMLId == 0 )
234 : {
235 126 : int i = strlen( pszGML_FID )-1, j = 0;
236 782 : while( i >= 0 && pszGML_FID[i] >= '0'
237 314 : && pszGML_FID[i] <= '9' && j<8)
238 216 : i--, j++;
239 : /* i points the last character of the fid */
240 126 : if( i >= 0 && j < 8 && pszFIDPrefix == NULL)
241 : {
242 54 : pszFIDPrefix = (char *) CPLMalloc(i+2);
243 54 : pszFIDPrefix[i+1] = '\0';
244 54 : strncpy(pszFIDPrefix, pszGML_FID, i+1);
245 : }
246 : /* pszFIDPrefix now contains the prefix or NULL if no prefix is found */
247 126 : if( j < 8 && sscanf(pszGML_FID+i+1, "%d", &nFID)==1)
248 : {
249 122 : if( iNextGMLId <= nFID )
250 122 : iNextGMLId = nFID + 1;
251 : }
252 : else
253 : {
254 4 : bInvalidFIDFound = TRUE;
255 4 : nFID = iNextGMLId++;
256 : }
257 : }
258 398 : else if( iNextGMLId != 0 )
259 : {
260 398 : const char* pszFIDPrefix_notnull = pszFIDPrefix;
261 398 : if (pszFIDPrefix_notnull == NULL) pszFIDPrefix_notnull = "";
262 398 : int nLenPrefix = strlen(pszFIDPrefix_notnull);
263 :
264 398 : if( strncmp(pszGML_FID, pszFIDPrefix_notnull, nLenPrefix) == 0 &&
265 : strlen(pszGML_FID+nLenPrefix) <= 9 &&
266 : sscanf(pszGML_FID+nLenPrefix, "%d", &nFID) == 1 )
267 : { /* fid with the prefix. Using its numerical part */
268 394 : if( iNextGMLId < nFID )
269 174 : iNextGMLId = nFID + 1;
270 : }
271 : else
272 : { /* fid without the aforementioned prefix or a valid numerical part */
273 4 : bInvalidFIDFound = TRUE;
274 4 : nFID = iNextGMLId++;
275 : }
276 : }
277 :
278 : /* -------------------------------------------------------------------- */
279 : /* Does it satisfy the spatial query, if there is one? */
280 : /* -------------------------------------------------------------------- */
281 :
282 712 : const CPLXMLNode* const * papsGeometry = poGMLFeature->GetGeometryList();
283 712 : if (papsGeometry[0] != NULL)
284 : {
285 696 : const char* pszSRSName = poDS->GetGlobalSRSName();
286 : poGeom = GML_BuildOGRGeometryFromList(papsGeometry, TRUE,
287 : poDS->GetInvertAxisOrderIfLatLong(),
288 : pszSRSName,
289 : poDS->GetConsiderEPSGAsURN(),
290 : poDS->GetSecondaryGeometryOption(),
291 : hCacheSRS,
292 696 : bFaceHoleNegative );
293 :
294 : /* Force single geometry to multigeometry if needed to match layer geometry type */
295 696 : if (poGeom != NULL)
296 : {
297 696 : OGRwkbGeometryType eType = poGeom->getGeometryType();
298 696 : OGRwkbGeometryType eLayerType = GetGeomType();
299 702 : if (eType == wkbPoint && eLayerType == wkbMultiPoint)
300 : {
301 6 : OGRMultiPoint* poNewGeom = new OGRMultiPoint();
302 6 : poNewGeom->addGeometryDirectly(poGeom);
303 6 : poGeom = poNewGeom;
304 : }
305 694 : else if (eType == wkbLineString && eLayerType == wkbMultiLineString)
306 : {
307 4 : OGRMultiLineString* poNewGeom = new OGRMultiLineString();
308 4 : poNewGeom->addGeometryDirectly(poGeom);
309 4 : poGeom = poNewGeom;
310 : }
311 686 : else if (eType == wkbPolygon && eLayerType == wkbMultiPolygon)
312 : {
313 6 : OGRMultiPolygon* poNewGeom = new OGRMultiPolygon();
314 6 : poNewGeom->addGeometryDirectly(poGeom);
315 6 : poGeom = poNewGeom;
316 : }
317 : }
318 :
319 696 : if (poGeom != NULL && poSRS != NULL)
320 56 : poGeom->assignSpatialReference(poSRS);
321 :
322 : // We assume the createFromGML() function would have already
323 : // reported the error.
324 696 : if( poGeom == NULL )
325 : {
326 0 : delete poGMLFeature;
327 0 : return NULL;
328 : }
329 :
330 696 : if( m_poFilterGeom != NULL && !FilterGeometry( poGeom ) )
331 20 : continue;
332 : }
333 :
334 :
335 : /* -------------------------------------------------------------------- */
336 : /* Convert the whole feature into an OGRFeature. */
337 : /* -------------------------------------------------------------------- */
338 : int iField;
339 692 : int iDstField = 0;
340 692 : OGRFeature *poOGRFeature = new OGRFeature( GetLayerDefn() );
341 :
342 692 : poOGRFeature->SetFID( nFID );
343 692 : if (poDS->ExposeId())
344 : {
345 674 : if (pszGML_FID)
346 506 : poOGRFeature->SetField( iDstField, pszGML_FID );
347 674 : iDstField ++;
348 : }
349 :
350 692 : int nPropertyCount = poFClass->GetPropertyCount();
351 2974 : for( iField = 0; iField < nPropertyCount; iField++, iDstField ++ )
352 : {
353 2282 : const GMLProperty *psGMLProperty = poGMLFeature->GetProperty( iField );
354 2282 : if( psGMLProperty == NULL || psGMLProperty->nSubProperties == 0 )
355 16 : continue;
356 :
357 2266 : switch( poFClass->GetProperty(iField)->GetType() )
358 : {
359 : case GMLPT_Real:
360 : {
361 322 : poOGRFeature->SetField( iDstField, CPLAtof(psGMLProperty->papszSubProperties[0]) );
362 : }
363 322 : break;
364 :
365 : case GMLPT_IntegerList:
366 : {
367 6 : int nCount = psGMLProperty->nSubProperties;
368 6 : int *panIntList = (int *) CPLMalloc(sizeof(int) * nCount );
369 : int i;
370 :
371 18 : for( i = 0; i < nCount; i++ )
372 12 : panIntList[i] = atoi(psGMLProperty->papszSubProperties[i]);
373 :
374 6 : poOGRFeature->SetField( iDstField, nCount, panIntList );
375 6 : CPLFree( panIntList );
376 : }
377 6 : break;
378 :
379 : case GMLPT_RealList:
380 : {
381 6 : int nCount = psGMLProperty->nSubProperties;
382 6 : double *padfList = (double *)CPLMalloc(sizeof(double)*nCount);
383 : int i;
384 :
385 18 : for( i = 0; i < nCount; i++ )
386 12 : padfList[i] = CPLAtof(psGMLProperty->papszSubProperties[i]);
387 :
388 6 : poOGRFeature->SetField( iDstField, nCount, padfList );
389 6 : CPLFree( padfList );
390 : }
391 6 : break;
392 :
393 : case GMLPT_StringList:
394 : {
395 10 : poOGRFeature->SetField( iDstField, psGMLProperty->papszSubProperties );
396 : }
397 10 : break;
398 :
399 : default:
400 1922 : poOGRFeature->SetField( iDstField, psGMLProperty->papszSubProperties[0] );
401 : break;
402 : }
403 : }
404 :
405 : /* Assign the geometry before the attribute filter because */
406 : /* the attribute filter may use a special field like OGR_GEOMETRY */
407 692 : poOGRFeature->SetGeometryDirectly( poGeom );
408 692 : poGeom = NULL;
409 :
410 : /* -------------------------------------------------------------------- */
411 : /* Test against the attribute query. */
412 : /* -------------------------------------------------------------------- */
413 692 : if( m_poAttrQuery != NULL
414 : && !m_poAttrQuery->Evaluate( poOGRFeature ) )
415 : {
416 14 : delete poOGRFeature;
417 14 : continue;
418 : }
419 :
420 : /* -------------------------------------------------------------------- */
421 : /* Wow, we got our desired feature. Return it. */
422 : /* -------------------------------------------------------------------- */
423 678 : delete poGMLFeature;
424 :
425 678 : return poOGRFeature;
426 : }
427 :
428 : return NULL;
429 : }
430 :
431 : /************************************************************************/
432 : /* GetFeatureCount() */
433 : /************************************************************************/
434 :
435 28 : int OGRGMLLayer::GetFeatureCount( int bForce )
436 :
437 : {
438 28 : if( poFClass == NULL )
439 0 : return 0;
440 :
441 28 : if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
442 8 : return OGRLayer::GetFeatureCount( bForce );
443 : else
444 : {
445 : /* If the schema is read from a .xsd file, we haven't read */
446 : /* the feature count, so compute it now */
447 20 : int nFeatureCount = poFClass->GetFeatureCount();
448 20 : if (nFeatureCount < 0)
449 : {
450 4 : nFeatureCount = OGRLayer::GetFeatureCount(bForce);
451 4 : poFClass->SetFeatureCount(nFeatureCount);
452 : }
453 20 : return nFeatureCount;
454 : }
455 : }
456 :
457 : /************************************************************************/
458 : /* GetExtent() */
459 : /************************************************************************/
460 :
461 6 : OGRErr OGRGMLLayer::GetExtent(OGREnvelope *psExtent, int bForce )
462 :
463 : {
464 : double dfXMin, dfXMax, dfYMin, dfYMax;
465 :
466 6 : if( poFClass != NULL &&
467 : poFClass->GetExtents( &dfXMin, &dfXMax, &dfYMin, &dfYMax ) )
468 : {
469 2 : psExtent->MinX = dfXMin;
470 2 : psExtent->MaxX = dfXMax;
471 2 : psExtent->MinY = dfYMin;
472 2 : psExtent->MaxY = dfYMax;
473 :
474 2 : return OGRERR_NONE;
475 : }
476 : else
477 4 : return OGRLayer::GetExtent( psExtent, bForce );
478 : }
479 :
480 : /************************************************************************/
481 : /* CreateFeature() */
482 : /************************************************************************/
483 :
484 72 : OGRErr OGRGMLLayer::CreateFeature( OGRFeature *poFeature )
485 :
486 : {
487 72 : int bIsGML3Output = poDS->IsGML3Output();
488 72 : VSILFILE *fp = poDS->GetOutputFP();
489 72 : int bWriteSpaceIndentation = poDS->WriteSpaceIndentation();
490 :
491 72 : if( !bWriter )
492 0 : return OGRERR_FAILURE;
493 :
494 72 : if (bWriteSpaceIndentation)
495 72 : VSIFPrintfL(fp, " ");
496 72 : if (bIsGML3Output)
497 32 : poDS->PrintLine( fp, "<ogr:featureMember>" );
498 : else
499 40 : poDS->PrintLine( fp, "<gml:featureMember>" );
500 :
501 72 : if( poFeature->GetFID() == OGRNullFID )
502 72 : poFeature->SetFID( iNextGMLId++ );
503 :
504 72 : int nGMLIdIndex = -1;
505 72 : if (bWriteSpaceIndentation)
506 72 : VSIFPrintfL(fp, " ");
507 72 : if (bIsGML3Output)
508 : {
509 32 : nGMLIdIndex = poFeatureDefn->GetFieldIndex("gml_id");
510 32 : if (nGMLIdIndex >= 0 && poFeature->IsFieldSet( nGMLIdIndex ) )
511 : poDS->PrintLine( fp, "<ogr:%s gml:id=\"%s\">",
512 : poFeatureDefn->GetName(),
513 0 : poFeature->GetFieldAsString(nGMLIdIndex) );
514 : else
515 : poDS->PrintLine( fp, "<ogr:%s gml:id=\"%s.%ld\">",
516 : poFeatureDefn->GetName(),
517 : poFeatureDefn->GetName(),
518 32 : poFeature->GetFID() );
519 : }
520 : else
521 : {
522 40 : nGMLIdIndex = poFeatureDefn->GetFieldIndex("fid");
523 40 : if (bUseOldFIDFormat)
524 : {
525 : poDS->PrintLine( fp, "<ogr:%s fid=\"F%ld\">",
526 : poFeatureDefn->GetName(),
527 0 : poFeature->GetFID() );
528 : }
529 40 : else if (nGMLIdIndex >= 0 && poFeature->IsFieldSet( nGMLIdIndex ) )
530 : {
531 : poDS->PrintLine( fp, "<ogr:%s fid=\"%s\">",
532 : poFeatureDefn->GetName(),
533 0 : poFeature->GetFieldAsString(nGMLIdIndex) );
534 : }
535 : else
536 : {
537 : poDS->PrintLine( fp, "<ogr:%s fid=\"%s.%ld\">",
538 : poFeatureDefn->GetName(),
539 : poFeatureDefn->GetName(),
540 40 : poFeature->GetFID() );
541 : }
542 : }
543 :
544 : // Write out Geometry - for now it isn't indented properly.
545 : /* GML geometries don't like very much the concept of empty geometry */
546 72 : OGRGeometry* poGeom = poFeature->GetGeometryRef();
547 72 : if( poGeom != NULL && !poGeom->IsEmpty())
548 : {
549 : char *pszGeometry;
550 52 : OGREnvelope3D sGeomBounds;
551 :
552 52 : int nCoordDimension = poGeom->getCoordinateDimension();
553 :
554 52 : poGeom->getEnvelope( &sGeomBounds );
555 52 : poDS->GrowExtents( &sGeomBounds, nCoordDimension );
556 :
557 52 : if (bIsGML3Output)
558 : {
559 : int bCoordSwap;
560 :
561 32 : if (poGeom->getSpatialReference() == NULL && poSRS != NULL)
562 12 : poGeom->assignSpatialReference(poSRS);
563 :
564 32 : char* pszSRSName = GML_GetSRSName(poGeom->getSpatialReference(), poDS->IsLongSRSRequired(), &bCoordSwap);
565 : char szLowerCorner[75], szUpperCorner[75];
566 32 : if (bCoordSwap)
567 : {
568 12 : OGRMakeWktCoordinate(szLowerCorner, sGeomBounds.MinY, sGeomBounds.MinX, sGeomBounds.MinZ, nCoordDimension);
569 12 : OGRMakeWktCoordinate(szUpperCorner, sGeomBounds.MaxY, sGeomBounds.MaxX, sGeomBounds.MaxZ, nCoordDimension);
570 : }
571 : else
572 : {
573 20 : OGRMakeWktCoordinate(szLowerCorner, sGeomBounds.MinX, sGeomBounds.MinY, sGeomBounds.MinZ, nCoordDimension);
574 20 : OGRMakeWktCoordinate(szUpperCorner, sGeomBounds.MaxX, sGeomBounds.MaxY, sGeomBounds.MaxZ, nCoordDimension);
575 : }
576 32 : if (bWriteSpaceIndentation)
577 32 : VSIFPrintfL(fp, " ");
578 : poDS->PrintLine( fp, "<gml:boundedBy><gml:Envelope%s%s><gml:lowerCorner>%s</gml:lowerCorner><gml:upperCorner>%s</gml:upperCorner></gml:Envelope></gml:boundedBy>",
579 32 : (nCoordDimension == 3) ? " srsDimension=\"3\"" : "",pszSRSName, szLowerCorner, szUpperCorner);
580 32 : CPLFree(pszSRSName);
581 : }
582 :
583 52 : char** papszOptions = (bIsGML3Output) ? CSLAddString(NULL, "FORMAT=GML3") : NULL;
584 52 : if (bIsGML3Output && !poDS->IsLongSRSRequired())
585 0 : papszOptions = CSLAddString(papszOptions, "GML3_LONGSRS=NO");
586 52 : if (poDS->IsGML32Output())
587 4 : papszOptions = CSLAddString(papszOptions, CPLSPrintf("GMLID=%s.geom.%ld", poFeatureDefn->GetName(), poFeature->GetFID()));
588 52 : pszGeometry = poGeom->exportToGML(papszOptions);
589 52 : CSLDestroy(papszOptions);
590 52 : if (bWriteSpaceIndentation)
591 52 : VSIFPrintfL(fp, " ");
592 : poDS->PrintLine( fp, "<ogr:geometryProperty>%s</ogr:geometryProperty>",
593 52 : pszGeometry );
594 52 : CPLFree( pszGeometry );
595 : }
596 :
597 : // Write all "set" fields.
598 246 : for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
599 : {
600 :
601 174 : OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( iField );
602 :
603 174 : if( poFeature->IsFieldSet( iField ) && iField != nGMLIdIndex )
604 : {
605 168 : const char *pszRaw = poFeature->GetFieldAsString( iField );
606 :
607 744 : while( *pszRaw == ' ' )
608 408 : pszRaw++;
609 :
610 168 : char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
611 :
612 168 : if (poFieldDefn->GetType() == OFTReal)
613 : {
614 : /* Use point as decimal separator */
615 84 : char* pszComma = strchr(pszEscaped, ',');
616 84 : if (pszComma)
617 0 : *pszComma = '.';
618 : }
619 :
620 168 : if (bWriteSpaceIndentation)
621 168 : VSIFPrintfL(fp, " ");
622 : poDS->PrintLine( fp, "<ogr:%s>%s</ogr:%s>",
623 : poFieldDefn->GetNameRef(), pszEscaped,
624 168 : poFieldDefn->GetNameRef() );
625 168 : CPLFree( pszEscaped );
626 : }
627 : }
628 :
629 72 : if (bWriteSpaceIndentation)
630 72 : VSIFPrintfL(fp, " ");
631 72 : poDS->PrintLine( fp, "</ogr:%s>", poFeatureDefn->GetName() );
632 72 : if (bWriteSpaceIndentation)
633 72 : VSIFPrintfL(fp, " ");
634 72 : if (bIsGML3Output)
635 32 : poDS->PrintLine( fp, "</ogr:featureMember>" );
636 : else
637 40 : poDS->PrintLine( fp, "</gml:featureMember>" );
638 :
639 72 : return OGRERR_NONE;
640 : }
641 :
642 : /************************************************************************/
643 : /* TestCapability() */
644 : /************************************************************************/
645 :
646 22 : int OGRGMLLayer::TestCapability( const char * pszCap )
647 :
648 : {
649 22 : if( EQUAL(pszCap,OLCSequentialWrite) )
650 2 : return bWriter;
651 :
652 20 : else if( EQUAL(pszCap,OLCCreateField) )
653 0 : return bWriter && iNextGMLId == 0;
654 :
655 20 : else if( EQUAL(pszCap,OLCFastGetExtent) )
656 : {
657 : double dfXMin, dfXMax, dfYMin, dfYMax;
658 :
659 2 : if( poFClass == NULL )
660 0 : return FALSE;
661 :
662 2 : return poFClass->GetExtents( &dfXMin, &dfXMax, &dfYMin, &dfYMax );
663 : }
664 :
665 18 : else if( EQUAL(pszCap,OLCFastFeatureCount) )
666 : {
667 6 : if( poFClass == NULL
668 : || m_poFilterGeom != NULL
669 : || m_poAttrQuery != NULL )
670 0 : return FALSE;
671 :
672 6 : return poFClass->GetFeatureCount() != -1;
673 : }
674 :
675 12 : else if( EQUAL(pszCap,OLCStringsAsUTF8) )
676 4 : return TRUE;
677 :
678 : else
679 8 : return FALSE;
680 : }
681 :
682 : /************************************************************************/
683 : /* CreateField() */
684 : /************************************************************************/
685 :
686 36 : OGRErr OGRGMLLayer::CreateField( OGRFieldDefn *poField, int bApproxOK )
687 :
688 : {
689 36 : if( !bWriter || iNextGMLId != 0 )
690 0 : return OGRERR_FAILURE;
691 :
692 : /* -------------------------------------------------------------------- */
693 : /* Enforce XML naming semantics on element name. */
694 : /* -------------------------------------------------------------------- */
695 36 : OGRFieldDefn oCleanCopy( poField );
696 36 : char *pszName = CPLStrdup( poField->GetNameRef() );
697 36 : CPLCleanXMLElementName( pszName );
698 :
699 36 : if( strcmp(pszName,poField->GetNameRef()) != 0 )
700 : {
701 0 : if( !bApproxOK )
702 : {
703 0 : CPLFree( pszName );
704 : CPLError( CE_Failure, CPLE_AppDefined,
705 : "Unable to create field with name '%s', it would not\n"
706 : "be valid as an XML element name.",
707 0 : poField->GetNameRef() );
708 0 : return OGRERR_FAILURE;
709 : }
710 :
711 0 : oCleanCopy.SetName( pszName );
712 : CPLError( CE_Warning, CPLE_AppDefined,
713 : "Field name '%s' adjusted to '%s' to be a valid\n"
714 : "XML element name.",
715 0 : poField->GetNameRef(), pszName );
716 : }
717 :
718 36 : CPLFree( pszName );
719 :
720 :
721 36 : poFeatureDefn->AddFieldDefn( &oCleanCopy );
722 :
723 36 : return OGRERR_NONE;
724 : }
725 :
726 : /************************************************************************/
727 : /* GetSpatialRef() */
728 : /************************************************************************/
729 :
730 16 : OGRSpatialReference *OGRGMLLayer::GetSpatialRef()
731 :
732 : {
733 16 : return poSRS;
734 : }
735 :
736 : /************************************************************************/
737 : /* GetGeometryColumn() */
738 : /************************************************************************/
739 :
740 6 : const char* OGRGMLLayer::GetGeometryColumn()
741 : {
742 6 : if( poFClass == NULL || poFClass->GetGeometryElement() == NULL )
743 0 : return "";
744 :
745 6 : return poFClass->GetGeometryElement();
746 : }
|