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