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