Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OGR
4 : * Purpose: Implements OGRGMLLayer class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "ogr_gml.h"
15 : #include "gmlutils.h"
16 : #include "cpl_conv.h"
17 : #include "cpl_port.h"
18 : #include "cpl_string.h"
19 : #include "ogr_p.h"
20 : #include "ogr_api.h"
21 :
22 : /************************************************************************/
23 : /* OGRGMLLayer() */
24 : /************************************************************************/
25 :
26 655 : OGRGMLLayer::OGRGMLLayer(const char *pszName, bool bWriterIn,
27 655 : OGRGMLDataSource *poDSIn)
28 : : poFeatureDefn(new OGRFeatureDefn(
29 655 : pszName + (STARTS_WITH_CI(pszName, "ogr:") ? 4 : 0))),
30 : iNextGMLId(0), bInvalidFIDFound(false), pszFIDPrefix(nullptr),
31 : bWriter(bWriterIn), poDS(poDSIn),
32 655 : poFClass(!bWriter ? poDS->GetReader()->GetClass(pszName) : nullptr),
33 : // Reader's should get the corresponding GMLFeatureClass and cache it.
34 1310 : hCacheSRS(GML_BuildOGRGeometryFromList_CreateCache()),
35 : // Compatibility option. Not advertized, because hopefully won't be
36 : // needed. Just put here in case.
37 : bUseOldFIDFormat(
38 655 : CPLTestBool(CPLGetConfigOption("GML_USE_OLD_FID_FORMAT", "FALSE"))),
39 : // Must be in synced in OGR_G_CreateFromGML(), OGRGMLLayer::OGRGMLLayer()
40 : // and GMLReader::GMLReader().
41 : bFaceHoleNegative(
42 2620 : CPLTestBool(CPLGetConfigOption("GML_FACE_HOLE_NEGATIVE", "NO")))
43 : {
44 655 : SetDescription(poFeatureDefn->GetName());
45 655 : poFeatureDefn->Reference();
46 655 : poFeatureDefn->SetGeomType(wkbNone);
47 655 : }
48 :
49 : /************************************************************************/
50 : /* ~OGRGMLLayer() */
51 : /************************************************************************/
52 :
53 1310 : OGRGMLLayer::~OGRGMLLayer()
54 :
55 : {
56 655 : CPLFree(pszFIDPrefix);
57 :
58 655 : if (poFeatureDefn)
59 655 : poFeatureDefn->Release();
60 :
61 655 : GML_BuildOGRGeometryFromList_DestroyCache(hCacheSRS);
62 1310 : }
63 :
64 : /************************************************************************/
65 : /* ResetReading() */
66 : /************************************************************************/
67 :
68 724 : void OGRGMLLayer::ResetReading()
69 :
70 : {
71 724 : if (bWriter)
72 16 : return;
73 :
74 1416 : if (poDS->GetReadMode() == INTERLEAVED_LAYERS ||
75 708 : poDS->GetReadMode() == SEQUENTIAL_LAYERS)
76 : {
77 : // Does the last stored feature belong to our layer ? If so, no
78 : // need to reset the reader.
79 92 : if (iNextGMLId == 0 && poDS->PeekStoredGMLFeature() != nullptr &&
80 0 : poDS->PeekStoredGMLFeature()->GetClass() == poFClass)
81 0 : return;
82 :
83 92 : delete poDS->PeekStoredGMLFeature();
84 92 : poDS->SetStoredGMLFeature(nullptr);
85 : }
86 :
87 708 : iNextGMLId = 0;
88 708 : poDS->GetReader()->ResetReading();
89 708 : CPLDebug("GML", "ResetReading()");
90 708 : if (poDS->GetLayerCount() > 1 && poDS->GetReadMode() == STANDARD)
91 : {
92 78 : const char *pszElementName = poFClass->GetElementName();
93 78 : const char *pszLastPipe = strrchr(pszElementName, '|');
94 78 : if (pszLastPipe != nullptr)
95 33 : pszElementName = pszLastPipe + 1;
96 78 : poDS->GetReader()->SetFilteredClassName(pszElementName);
97 : }
98 : }
99 :
100 : /************************************************************************/
101 : /* Increment() */
102 : /************************************************************************/
103 :
104 536 : static GIntBig Increment(GIntBig nVal)
105 : {
106 536 : if (nVal <= GINTBIG_MAX - 1)
107 536 : return nVal + 1;
108 0 : return nVal;
109 : }
110 :
111 : /************************************************************************/
112 : /* GetNextFeature() */
113 : /************************************************************************/
114 :
115 797 : OGRFeature *OGRGMLLayer::GetNextFeature()
116 :
117 : {
118 797 : if (bWriter)
119 : {
120 16 : CPLError(CE_Failure, CPLE_NotSupported,
121 : "Cannot read features when writing a GML file");
122 16 : return nullptr;
123 : }
124 :
125 781 : if (poDS->GetLastReadLayer() != this)
126 : {
127 354 : if (poDS->GetReadMode() != INTERLEAVED_LAYERS)
128 345 : ResetReading();
129 354 : poDS->SetLastReadLayer(this);
130 : }
131 :
132 : /* ==================================================================== */
133 : /* Loop till we find and translate a feature meeting all our */
134 : /* requirements. */
135 : /* ==================================================================== */
136 : while (true)
137 : {
138 1438 : GMLFeature *poGMLFeature = poDS->PeekStoredGMLFeature();
139 1438 : if (poGMLFeature != nullptr)
140 : {
141 3 : poDS->SetStoredGMLFeature(nullptr);
142 : }
143 : else
144 : {
145 1435 : poGMLFeature = poDS->GetReader()->NextFeature();
146 1435 : if (poGMLFeature == nullptr)
147 781 : return nullptr;
148 :
149 : // We count reading low level GML features as a feature read for
150 : // work checking purposes, though at least we didn't necessary
151 : // have to turn it into an OGRFeature.
152 1306 : m_nFeaturesRead++;
153 : }
154 :
155 : /* --------------------------------------------------------------------
156 : */
157 : /* Is it of the proper feature class? */
158 : /* --------------------------------------------------------------------
159 : */
160 :
161 1309 : if (poGMLFeature->GetClass() != poFClass)
162 : {
163 1833 : if (poDS->GetReadMode() == INTERLEAVED_LAYERS ||
164 1220 : (poDS->GetReadMode() == SEQUENTIAL_LAYERS && iNextGMLId != 0))
165 : {
166 4 : CPLAssert(poDS->PeekStoredGMLFeature() == nullptr);
167 4 : poDS->SetStoredGMLFeature(poGMLFeature);
168 4 : return nullptr;
169 : }
170 : else
171 : {
172 609 : delete poGMLFeature;
173 609 : continue;
174 : }
175 : }
176 :
177 : /* --------------------------------------------------------------------
178 : */
179 : /* Extract the fid: */
180 : /* -Assumes the fids are non-negative integers with an optional */
181 : /* prefix */
182 : /* -If a prefix differs from the prefix of the first feature from
183 : */
184 : /* the poDS then the fids from the poDS are ignored and are */
185 : /* assigned serially thereafter */
186 : /* --------------------------------------------------------------------
187 : */
188 696 : GIntBig nFID = -1;
189 696 : const char *pszGML_FID = poGMLFeature->GetFID();
190 696 : if (bInvalidFIDFound)
191 : {
192 43 : nFID = iNextGMLId;
193 43 : iNextGMLId = Increment(iNextGMLId);
194 : }
195 653 : else if (pszGML_FID == nullptr)
196 : {
197 109 : bInvalidFIDFound = true;
198 109 : nFID = iNextGMLId;
199 109 : iNextGMLId = Increment(iNextGMLId);
200 : }
201 544 : else if (iNextGMLId == 0)
202 : {
203 267 : int j = 0;
204 267 : int i = static_cast<int>(strlen(pszGML_FID)) - 1;
205 661 : while (i >= 0 && pszGML_FID[i] >= '0' && pszGML_FID[i] <= '9' &&
206 : j < 20)
207 : {
208 394 : i--;
209 394 : j++;
210 : }
211 : // i points the last character of the fid.
212 267 : if (i >= 0 && j < 20 && pszFIDPrefix == nullptr)
213 : {
214 204 : pszFIDPrefix = static_cast<char *>(CPLMalloc(i + 2));
215 204 : pszFIDPrefix[i + 1] = '\0';
216 204 : strncpy(pszFIDPrefix, pszGML_FID, i + 1);
217 : }
218 : // pszFIDPrefix now contains the prefix or NULL if no prefix is
219 : // found.
220 267 : if (j < 20 && sscanf(pszGML_FID + i + 1, CPL_FRMT_GIB, &nFID) == 1)
221 : {
222 261 : if (iNextGMLId <= nFID)
223 261 : iNextGMLId = Increment(nFID);
224 : }
225 : else
226 : {
227 6 : bInvalidFIDFound = true;
228 6 : nFID = iNextGMLId;
229 6 : iNextGMLId = Increment(iNextGMLId);
230 : }
231 : }
232 : else // if( iNextGMLId != 0 ).
233 : {
234 277 : const char *pszFIDPrefix_notnull = pszFIDPrefix;
235 277 : if (pszFIDPrefix_notnull == nullptr)
236 6 : pszFIDPrefix_notnull = "";
237 277 : int nLenPrefix = static_cast<int>(strlen(pszFIDPrefix_notnull));
238 :
239 827 : if (strncmp(pszGML_FID, pszFIDPrefix_notnull, nLenPrefix) == 0 &&
240 550 : strlen(pszGML_FID + nLenPrefix) < 20 &&
241 273 : sscanf(pszGML_FID + nLenPrefix, CPL_FRMT_GIB, &nFID) == 1)
242 : {
243 : // fid with the prefix. Using its numerical part.
244 272 : if (iNextGMLId < nFID)
245 112 : iNextGMLId = Increment(nFID);
246 : }
247 : else
248 : {
249 : // fid without the aforementioned prefix or a valid numerical
250 : // part.
251 5 : bInvalidFIDFound = true;
252 5 : nFID = iNextGMLId;
253 5 : iNextGMLId = Increment(iNextGMLId);
254 : }
255 : }
256 :
257 : /* --------------------------------------------------------------------
258 : */
259 : /* Does it satisfy the spatial query, if there is one? */
260 : /* --------------------------------------------------------------------
261 : */
262 :
263 696 : OGRGeometry **papoGeometries = nullptr;
264 696 : const CPLXMLNode *const *papsGeometry = poGMLFeature->GetGeometryList();
265 :
266 696 : const CPLXMLNode *apsGeometries[2] = {nullptr, nullptr};
267 : const CPLXMLNode *psBoundedByGeometry =
268 696 : poGMLFeature->GetBoundedByGeometry();
269 696 : if (psBoundedByGeometry && !(papsGeometry && papsGeometry[0]))
270 : {
271 6 : apsGeometries[0] = psBoundedByGeometry;
272 6 : papsGeometry = apsGeometries;
273 : }
274 :
275 696 : OGRGeometry *poGeom = nullptr;
276 :
277 696 : if (poFeatureDefn->GetGeomFieldCount() > 1)
278 : {
279 188 : papoGeometries = static_cast<OGRGeometry **>(CPLCalloc(
280 94 : poFeatureDefn->GetGeomFieldCount(), sizeof(OGRGeometry *)));
281 94 : const char *pszSRSName = poDS->GetGlobalSRSName();
282 301 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
283 : {
284 207 : const CPLXMLNode *psGeom = poGMLFeature->GetGeometryRef(i);
285 207 : if (psGeom != nullptr)
286 : {
287 163 : const CPLXMLNode *myGeometryList[2] = {psGeom, nullptr};
288 163 : poGeom = GML_BuildOGRGeometryFromList(
289 : myGeometryList, true,
290 163 : poDS->GetInvertAxisOrderIfLatLong(), pszSRSName,
291 163 : poDS->GetConsiderEPSGAsURN(),
292 163 : poDS->GetSwapCoordinates(),
293 163 : poDS->GetSecondaryGeometryOption(), hCacheSRS,
294 163 : bFaceHoleNegative);
295 :
296 : // Do geometry type changes if needed to match layer
297 : // geometry type.
298 163 : if (poGeom != nullptr)
299 : {
300 163 : papoGeometries[i] = OGRGeometryFactory::forceTo(
301 : poGeom,
302 163 : poFeatureDefn->GetGeomFieldDefn(i)->GetType());
303 163 : poGeom = nullptr;
304 : }
305 : else
306 : {
307 : // We assume the createFromGML() function would have
308 : // already reported the error.
309 0 : for (int j = 0; j < poFeatureDefn->GetGeomFieldCount();
310 : j++)
311 : {
312 0 : delete papoGeometries[j];
313 : }
314 0 : CPLFree(papoGeometries);
315 0 : delete poGMLFeature;
316 0 : return nullptr;
317 : }
318 : }
319 : }
320 :
321 0 : if (m_poFilterGeom != nullptr && m_iGeomFieldFilter >= 0 &&
322 0 : m_iGeomFieldFilter < poFeatureDefn->GetGeomFieldCount() &&
323 94 : papoGeometries[m_iGeomFieldFilter] &&
324 0 : !FilterGeometry(papoGeometries[m_iGeomFieldFilter]))
325 : {
326 0 : for (int j = 0; j < poFeatureDefn->GetGeomFieldCount(); j++)
327 : {
328 0 : delete papoGeometries[j];
329 : }
330 0 : CPLFree(papoGeometries);
331 0 : delete poGMLFeature;
332 0 : continue;
333 : }
334 : }
335 602 : else if (papsGeometry[0] &&
336 504 : strcmp(papsGeometry[0]->pszValue, "null") == 0)
337 : {
338 : // do nothing
339 : }
340 598 : else if (papsGeometry[0] != nullptr)
341 : {
342 500 : const char *pszSRSName = poDS->GetGlobalSRSName();
343 500 : CPLPushErrorHandler(CPLQuietErrorHandler);
344 500 : poGeom = GML_BuildOGRGeometryFromList(
345 500 : papsGeometry, true, poDS->GetInvertAxisOrderIfLatLong(),
346 500 : pszSRSName, poDS->GetConsiderEPSGAsURN(),
347 500 : poDS->GetSwapCoordinates(), poDS->GetSecondaryGeometryOption(),
348 500 : hCacheSRS, bFaceHoleNegative);
349 500 : CPLPopErrorHandler();
350 :
351 : // Do geometry type changes if needed to match layer geometry type.
352 500 : if (poGeom != nullptr)
353 : {
354 500 : poGeom = OGRGeometryFactory::forceTo(poGeom, GetGeomType());
355 : }
356 : else
357 : {
358 0 : const CPLString osLastErrorMsg(CPLGetLastErrorMsg());
359 :
360 0 : const bool bGoOn = CPLTestBool(
361 : CPLGetConfigOption("GML_SKIP_CORRUPTED_FEATURES", "NO"));
362 :
363 0 : CPLError(
364 : bGoOn ? CE_Warning : CE_Failure, CPLE_AppDefined,
365 : "Geometry of feature " CPL_FRMT_GIB
366 : " %scannot be parsed: %s%s",
367 0 : nFID, pszGML_FID ? CPLSPrintf("%s ", pszGML_FID) : "",
368 : osLastErrorMsg.c_str(),
369 : bGoOn ? ". Skipping to next feature."
370 : : ". You may set the GML_SKIP_CORRUPTED_FEATURES "
371 : "configuration option to YES to skip to the next "
372 : "feature");
373 0 : delete poGMLFeature;
374 0 : if (bGoOn)
375 0 : continue;
376 0 : return nullptr;
377 : }
378 :
379 500 : if (m_poFilterGeom != nullptr && !FilterGeometry(poGeom))
380 : {
381 20 : delete poGMLFeature;
382 20 : delete poGeom;
383 20 : continue;
384 : }
385 : }
386 :
387 : /* --------------------------------------------------------------------
388 : */
389 : /* Convert the whole feature into an OGRFeature. */
390 : /* --------------------------------------------------------------------
391 : */
392 676 : int iDstField = 0;
393 676 : OGRFeature *poOGRFeature = new OGRFeature(poFeatureDefn);
394 :
395 676 : poOGRFeature->SetFID(nFID);
396 676 : if (poDS->ExposeId())
397 : {
398 568 : if (pszGML_FID)
399 531 : poOGRFeature->SetField(iDstField, pszGML_FID);
400 568 : iDstField++;
401 : }
402 :
403 676 : const int nPropertyCount = poFClass->GetPropertyCount();
404 3282 : for (int iField = 0; iField < nPropertyCount; iField++, iDstField++)
405 : {
406 : const GMLProperty *psGMLProperty =
407 2606 : poGMLFeature->GetProperty(iField);
408 2606 : if (psGMLProperty == nullptr || psGMLProperty->nSubProperties == 0)
409 611 : continue;
410 :
411 1995 : if (EQUAL(psGMLProperty->papszSubProperties[0], OGR_GML_NULL))
412 : {
413 1 : poOGRFeature->SetFieldNull(iDstField);
414 1 : continue;
415 : }
416 :
417 1994 : switch (poFClass->GetProperty(iField)->GetType())
418 : {
419 329 : case GMLPT_Real:
420 : {
421 329 : poOGRFeature->SetField(
422 : iDstField,
423 329 : CPLAtof(psGMLProperty->papszSubProperties[0]));
424 : }
425 329 : break;
426 :
427 13 : case GMLPT_IntegerList:
428 : {
429 13 : const int nCount = psGMLProperty->nSubProperties;
430 : int *panIntList =
431 13 : static_cast<int *>(CPLMalloc(sizeof(int) * nCount));
432 :
433 39 : for (int i = 0; i < nCount; i++)
434 26 : panIntList[i] =
435 26 : atoi(psGMLProperty->papszSubProperties[i]);
436 :
437 13 : poOGRFeature->SetField(iDstField, nCount, panIntList);
438 13 : CPLFree(panIntList);
439 : }
440 13 : break;
441 :
442 6 : case GMLPT_Integer64List:
443 : {
444 6 : const int nCount = psGMLProperty->nSubProperties;
445 : GIntBig *panIntList = static_cast<GIntBig *>(
446 6 : CPLMalloc(sizeof(GIntBig) * nCount));
447 :
448 15 : for (int i = 0; i < nCount; i++)
449 18 : panIntList[i] =
450 9 : CPLAtoGIntBig(psGMLProperty->papszSubProperties[i]);
451 :
452 6 : poOGRFeature->SetField(iDstField, nCount, panIntList);
453 6 : CPLFree(panIntList);
454 : }
455 6 : break;
456 :
457 25 : case GMLPT_RealList:
458 : {
459 25 : const int nCount = psGMLProperty->nSubProperties;
460 : double *padfList = static_cast<double *>(
461 25 : CPLMalloc(sizeof(double) * nCount));
462 :
463 59 : for (int i = 0; i < nCount; i++)
464 68 : padfList[i] =
465 34 : CPLAtof(psGMLProperty->papszSubProperties[i]);
466 :
467 25 : poOGRFeature->SetField(iDstField, nCount, padfList);
468 25 : CPLFree(padfList);
469 : }
470 25 : break;
471 :
472 106 : case GMLPT_StringList:
473 : case GMLPT_FeaturePropertyList:
474 : {
475 106 : poOGRFeature->SetField(iDstField,
476 106 : psGMLProperty->papszSubProperties);
477 : }
478 106 : break;
479 :
480 46 : case GMLPT_Boolean:
481 : {
482 46 : if (strcmp(psGMLProperty->papszSubProperties[0], "true") ==
483 7 : 0 ||
484 7 : strcmp(psGMLProperty->papszSubProperties[0], "1") == 0)
485 : {
486 39 : poOGRFeature->SetField(iDstField, 1);
487 : }
488 7 : else if (strcmp(psGMLProperty->papszSubProperties[0],
489 0 : "false") == 0 ||
490 0 : strcmp(psGMLProperty->papszSubProperties[0],
491 : "0") == 0)
492 : {
493 7 : poOGRFeature->SetField(iDstField, 0);
494 : }
495 : else
496 : {
497 0 : poOGRFeature->SetField(
498 0 : iDstField, psGMLProperty->papszSubProperties[0]);
499 : }
500 46 : break;
501 : }
502 :
503 3 : case GMLPT_BooleanList:
504 : {
505 3 : const int nCount = psGMLProperty->nSubProperties;
506 : int *panIntList =
507 3 : static_cast<int *>(CPLMalloc(sizeof(int) * nCount));
508 :
509 9 : for (int i = 0; i < nCount; i++)
510 : {
511 6 : panIntList[i] =
512 6 : (strcmp(psGMLProperty->papszSubProperties[i],
513 9 : "true") == 0 ||
514 3 : strcmp(psGMLProperty->papszSubProperties[i],
515 : "1") == 0);
516 : }
517 :
518 3 : poOGRFeature->SetField(iDstField, nCount, panIntList);
519 3 : CPLFree(panIntList);
520 3 : break;
521 : }
522 :
523 1466 : default:
524 1466 : poOGRFeature->SetField(
525 1466 : iDstField, psGMLProperty->papszSubProperties[0]);
526 1466 : break;
527 : }
528 : }
529 :
530 676 : delete poGMLFeature;
531 676 : poGMLFeature = nullptr;
532 :
533 : // Assign the geometry before the attribute filter because
534 : // the attribute filter may use a special field like OGR_GEOMETRY.
535 676 : if (papoGeometries != nullptr)
536 : {
537 301 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
538 : {
539 207 : poOGRFeature->SetGeomFieldDirectly(i, papoGeometries[i]);
540 : }
541 94 : CPLFree(papoGeometries);
542 94 : papoGeometries = nullptr;
543 : }
544 : else
545 : {
546 582 : poOGRFeature->SetGeometryDirectly(poGeom);
547 : }
548 :
549 : // Assign SRS.
550 1406 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
551 : {
552 730 : poGeom = poOGRFeature->GetGeomFieldRef(i);
553 730 : if (poGeom != nullptr)
554 : {
555 : const OGRSpatialReference *poSRS =
556 643 : poFeatureDefn->GetGeomFieldDefn(i)->GetSpatialRef();
557 643 : if (poSRS != nullptr)
558 133 : poGeom->assignSpatialReference(poSRS);
559 : }
560 : }
561 :
562 : /* --------------------------------------------------------------------
563 : */
564 : /* Test against the attribute query. */
565 : /* --------------------------------------------------------------------
566 : */
567 676 : if (m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poOGRFeature))
568 : {
569 28 : delete poOGRFeature;
570 28 : continue;
571 : }
572 :
573 : // Got the desired feature.
574 648 : return poOGRFeature;
575 657 : }
576 :
577 : return nullptr;
578 : }
579 :
580 : /************************************************************************/
581 : /* GetFeatureCount() */
582 : /************************************************************************/
583 :
584 62 : GIntBig OGRGMLLayer::GetFeatureCount(int bForce)
585 :
586 : {
587 62 : if (poFClass == nullptr)
588 0 : return 0;
589 :
590 62 : if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr)
591 6 : return OGRLayer::GetFeatureCount(bForce);
592 :
593 : // If the schema is read from a .xsd file, we haven't read
594 : // the feature count, so compute it now.
595 56 : GIntBig nFeatureCount = poFClass->GetFeatureCount();
596 56 : if (nFeatureCount < 0)
597 : {
598 26 : nFeatureCount = OGRLayer::GetFeatureCount(bForce);
599 26 : poFClass->SetFeatureCount(nFeatureCount);
600 : }
601 :
602 56 : return nFeatureCount;
603 : }
604 :
605 : /************************************************************************/
606 : /* GetExtent() */
607 : /************************************************************************/
608 :
609 10 : OGRErr OGRGMLLayer::GetExtent(OGREnvelope *psExtent, int bForce)
610 :
611 : {
612 10 : if (GetGeomType() == wkbNone)
613 0 : return OGRERR_FAILURE;
614 :
615 10 : double dfXMin = 0.0;
616 10 : double dfXMax = 0.0;
617 10 : double dfYMin = 0.0;
618 10 : double dfYMax = 0.0;
619 20 : if (poFClass != nullptr &&
620 10 : poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax))
621 : {
622 8 : psExtent->MinX = dfXMin;
623 8 : psExtent->MaxX = dfXMax;
624 8 : psExtent->MinY = dfYMin;
625 8 : psExtent->MaxY = dfYMax;
626 :
627 8 : return OGRERR_NONE;
628 : }
629 :
630 2 : return OGRLayer::GetExtent(psExtent, bForce);
631 : }
632 :
633 : /************************************************************************/
634 : /* GetExtent() */
635 : /************************************************************************/
636 :
637 505 : static void GMLWriteField(OGRGMLDataSource *poDS, VSILFILE *fp,
638 : bool bWriteSpaceIndentation, const char *pszPrefix,
639 : bool bRemoveAppPrefix, OGRFieldDefn *poFieldDefn,
640 : const char *pszVal)
641 :
642 : {
643 505 : const char *pszFieldName = poFieldDefn->GetNameRef();
644 :
645 505 : while (*pszVal == ' ')
646 0 : pszVal++;
647 :
648 505 : if (bWriteSpaceIndentation)
649 505 : VSIFPrintfL(fp, " ");
650 :
651 505 : if (bRemoveAppPrefix)
652 60 : poDS->PrintLine(fp, "<%s>%s</%s>", pszFieldName, pszVal, pszFieldName);
653 : else
654 445 : poDS->PrintLine(fp, "<%s:%s>%s</%s:%s>", pszPrefix, pszFieldName,
655 : pszVal, pszPrefix, pszFieldName);
656 505 : }
657 :
658 : /************************************************************************/
659 : /* ICreateFeature() */
660 : /************************************************************************/
661 :
662 265 : OGRErr OGRGMLLayer::ICreateFeature(OGRFeature *poFeature)
663 :
664 : {
665 265 : const bool bIsGML3Output = poDS->IsGML3Output();
666 265 : VSILFILE *fp = poDS->GetOutputFP();
667 265 : const bool bWriteSpaceIndentation = poDS->WriteSpaceIndentation();
668 265 : const char *pszPrefix = poDS->GetAppPrefix();
669 265 : const bool bRemoveAppPrefix = poDS->RemoveAppPrefix();
670 265 : const bool bGMLFeatureCollection = poDS->GMLFeatureCollection();
671 :
672 265 : if (!bWriter)
673 0 : return OGRERR_FAILURE;
674 :
675 265 : poFeature->FillUnsetWithDefault(TRUE, nullptr);
676 265 : if (!poFeature->Validate(OGR_F_VAL_ALL & ~OGR_F_VAL_GEOM_TYPE &
677 : ~OGR_F_VAL_ALLOW_NULL_WHEN_DEFAULT,
678 : TRUE))
679 2 : return OGRERR_FAILURE;
680 :
681 263 : if (bWriteSpaceIndentation)
682 263 : VSIFPrintfL(fp, " ");
683 263 : if (bIsGML3Output && !bGMLFeatureCollection)
684 : {
685 219 : if (bRemoveAppPrefix)
686 10 : poDS->PrintLine(fp, "<featureMember>");
687 : else
688 209 : poDS->PrintLine(fp, "<%s:featureMember>", pszPrefix);
689 : }
690 : else
691 : {
692 44 : poDS->PrintLine(fp, "<gml:featureMember>");
693 : }
694 :
695 263 : if (poFeature->GetFID() == OGRNullFID)
696 250 : poFeature->SetFID(iNextGMLId++);
697 :
698 263 : if (bWriteSpaceIndentation)
699 263 : VSIFPrintfL(fp, " ");
700 263 : VSIFPrintfL(fp, "<");
701 263 : if (!bRemoveAppPrefix)
702 243 : VSIFPrintfL(fp, "%s:", pszPrefix);
703 :
704 263 : int nGMLIdIndex = -1;
705 263 : if (bIsGML3Output)
706 : {
707 229 : nGMLIdIndex = poFeatureDefn->GetFieldIndex("gml_id");
708 229 : if (nGMLIdIndex >= 0 && poFeature->IsFieldSetAndNotNull(nGMLIdIndex))
709 3 : poDS->PrintLine(fp, "%s gml:id=\"%s\">", poFeatureDefn->GetName(),
710 : poFeature->GetFieldAsString(nGMLIdIndex));
711 : else
712 452 : poDS->PrintLine(fp, "%s gml:id=\"%s." CPL_FRMT_GIB "\">",
713 226 : poFeatureDefn->GetName(), poFeatureDefn->GetName(),
714 : poFeature->GetFID());
715 : }
716 : else
717 : {
718 34 : nGMLIdIndex = poFeatureDefn->GetFieldIndex("fid");
719 34 : if (bUseOldFIDFormat)
720 : {
721 0 : poDS->PrintLine(fp, "%s fid=\"F" CPL_FRMT_GIB "\">",
722 0 : poFeatureDefn->GetName(), poFeature->GetFID());
723 : }
724 44 : else if (nGMLIdIndex >= 0 &&
725 10 : poFeature->IsFieldSetAndNotNull(nGMLIdIndex))
726 : {
727 10 : poDS->PrintLine(fp, "%s fid=\"%s\">", poFeatureDefn->GetName(),
728 : poFeature->GetFieldAsString(nGMLIdIndex));
729 : }
730 : else
731 : {
732 48 : poDS->PrintLine(fp, "%s fid=\"%s." CPL_FRMT_GIB "\">",
733 24 : poFeatureDefn->GetName(), poFeatureDefn->GetName(),
734 : poFeature->GetFID());
735 : }
736 : }
737 :
738 515 : for (int iGeomField = 0; iGeomField < poFeatureDefn->GetGeomFieldCount();
739 : iGeomField++)
740 : {
741 : const OGRGeomFieldDefn *poFieldDefn =
742 252 : poFeatureDefn->GetGeomFieldDefn(iGeomField);
743 :
744 : // Write out Geometry - for now it isn't indented properly.
745 : // GML geometries don't like very much the concept of empty geometry.
746 252 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
747 252 : if (poGeom != nullptr && !poGeom->IsEmpty())
748 : {
749 215 : OGREnvelope3D sGeomBounds;
750 :
751 215 : const int nCoordDimension = poGeom->getCoordinateDimension();
752 :
753 215 : poGeom->getEnvelope(&sGeomBounds);
754 215 : if (poDS->HasWriteGlobalSRS())
755 211 : poDS->GrowExtents(&sGeomBounds, nCoordDimension);
756 :
757 356 : if (poGeom->getSpatialReference() == nullptr &&
758 141 : poFieldDefn->GetSpatialRef() != nullptr)
759 18 : poGeom->assignSpatialReference(poFieldDefn->GetSpatialRef());
760 :
761 215 : const auto &oCoordPrec = poFieldDefn->GetCoordinatePrecision();
762 :
763 215 : if (bIsGML3Output && poDS->WriteFeatureBoundedBy())
764 : {
765 171 : bool bCoordSwap = false;
766 :
767 : char *pszSRSName =
768 171 : GML_GetSRSName(poGeom->getSpatialReference(),
769 171 : poDS->GetSRSNameFormat(), &bCoordSwap);
770 171 : char szLowerCorner[75] = {};
771 171 : char szUpperCorner[75] = {};
772 :
773 171 : OGRWktOptions coordOpts;
774 :
775 171 : if (oCoordPrec.dfXYResolution !=
776 : OGRGeomCoordinatePrecision::UNKNOWN)
777 : {
778 3 : coordOpts.format = OGRWktFormat::F;
779 3 : coordOpts.xyPrecision =
780 3 : OGRGeomCoordinatePrecision::ResolutionToPrecision(
781 3 : oCoordPrec.dfXYResolution);
782 : }
783 171 : if (oCoordPrec.dfZResolution !=
784 : OGRGeomCoordinatePrecision::UNKNOWN)
785 : {
786 3 : coordOpts.format = OGRWktFormat::F;
787 3 : coordOpts.zPrecision =
788 3 : OGRGeomCoordinatePrecision::ResolutionToPrecision(
789 3 : oCoordPrec.dfZResolution);
790 : }
791 :
792 342 : std::string wkt;
793 171 : if (bCoordSwap)
794 : {
795 36 : wkt = OGRMakeWktCoordinate(
796 : sGeomBounds.MinY, sGeomBounds.MinX, sGeomBounds.MinZ,
797 18 : nCoordDimension, coordOpts);
798 18 : memcpy(szLowerCorner, wkt.data(), wkt.size() + 1);
799 :
800 36 : wkt = OGRMakeWktCoordinate(
801 : sGeomBounds.MaxY, sGeomBounds.MaxX, sGeomBounds.MaxZ,
802 18 : nCoordDimension, coordOpts);
803 18 : memcpy(szUpperCorner, wkt.data(), wkt.size() + 1);
804 : }
805 : else
806 : {
807 306 : wkt = OGRMakeWktCoordinate(
808 : sGeomBounds.MinX, sGeomBounds.MinY, sGeomBounds.MinZ,
809 153 : nCoordDimension, coordOpts);
810 153 : memcpy(szLowerCorner, wkt.data(), wkt.size() + 1);
811 :
812 306 : wkt = OGRMakeWktCoordinate(
813 : sGeomBounds.MaxX, sGeomBounds.MaxY, sGeomBounds.MaxZ,
814 153 : nCoordDimension, coordOpts);
815 153 : memcpy(szUpperCorner, wkt.data(), wkt.size() + 1);
816 : }
817 171 : if (bWriteSpaceIndentation)
818 171 : VSIFPrintfL(fp, " ");
819 171 : poDS->PrintLine(
820 : fp,
821 : "<gml:boundedBy><gml:Envelope%s%s><gml:lowerCorner>%s"
822 : "</gml:lowerCorner><gml:upperCorner>%s</gml:upperCorner>"
823 : "</gml:Envelope></gml:boundedBy>",
824 : (nCoordDimension == 3) ? " srsDimension=\"3\"" : "",
825 : pszSRSName, szLowerCorner, szUpperCorner);
826 171 : CPLFree(pszSRSName);
827 : }
828 :
829 215 : char **papszOptions = nullptr;
830 215 : if (bIsGML3Output)
831 : {
832 181 : papszOptions = CSLAddString(papszOptions, "FORMAT=GML3");
833 181 : if (poDS->GetSRSNameFormat() == SRSNAME_SHORT)
834 : papszOptions =
835 1 : CSLAddString(papszOptions, "SRSNAME_FORMAT=SHORT");
836 180 : else if (poDS->GetSRSNameFormat() == SRSNAME_OGC_URN)
837 : papszOptions =
838 167 : CSLAddString(papszOptions, "SRSNAME_FORMAT=OGC_URN");
839 13 : else if (poDS->GetSRSNameFormat() == SRSNAME_OGC_URL)
840 : papszOptions =
841 13 : CSLAddString(papszOptions, "SRSNAME_FORMAT=OGC_URL");
842 : }
843 215 : const char *pszSRSDimensionLoc = poDS->GetSRSDimensionLoc();
844 215 : if (pszSRSDimensionLoc != nullptr)
845 3 : papszOptions = CSLSetNameValue(papszOptions, "SRSDIMENSION_LOC",
846 : pszSRSDimensionLoc);
847 215 : if (poDS->IsGML32Output())
848 : {
849 115 : if (poFeatureDefn->GetGeomFieldCount() > 1)
850 18 : papszOptions = CSLAddString(
851 : papszOptions, CPLSPrintf("GMLID=%s.%s." CPL_FRMT_GIB,
852 9 : poFeatureDefn->GetName(),
853 : poFieldDefn->GetNameRef(),
854 : poFeature->GetFID()));
855 : else
856 212 : papszOptions = CSLAddString(
857 : papszOptions, CPLSPrintf("GMLID=%s.geom." CPL_FRMT_GIB,
858 106 : poFeatureDefn->GetName(),
859 : poFeature->GetFID()));
860 : }
861 :
862 215 : if (oCoordPrec.dfXYResolution !=
863 : OGRGeomCoordinatePrecision::UNKNOWN)
864 : {
865 3 : papszOptions = CSLAddString(
866 : papszOptions, CPLSPrintf("XY_COORD_RESOLUTION=%g",
867 3 : oCoordPrec.dfXYResolution));
868 : }
869 215 : if (oCoordPrec.dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
870 : {
871 3 : papszOptions = CSLAddString(
872 : papszOptions, CPLSPrintf("Z_COORD_RESOLUTION=%g",
873 3 : oCoordPrec.dfZResolution));
874 : }
875 :
876 215 : char *pszGeometry = nullptr;
877 215 : if (!bIsGML3Output && OGR_GT_IsNonLinear(poGeom->getGeometryType()))
878 : {
879 0 : OGRGeometry *poGeomTmp = OGRGeometryFactory::forceTo(
880 0 : poGeom->clone(),
881 0 : OGR_GT_GetLinear(poGeom->getGeometryType()));
882 0 : pszGeometry = poGeomTmp->exportToGML(papszOptions);
883 0 : delete poGeomTmp;
884 : }
885 : else
886 : {
887 215 : if (wkbFlatten(poGeom->getGeometryType()) == wkbTriangle)
888 : {
889 0 : pszGeometry = poGeom->exportToGML(papszOptions);
890 :
891 : const char *pszGMLID =
892 0 : poDS->IsGML32Output()
893 0 : ? CPLSPrintf(
894 : " gml:id=\"%s\"",
895 : CSLFetchNameValue(papszOptions, "GMLID"))
896 0 : : "";
897 0 : char *pszNewGeom = CPLStrdup(
898 : CPLSPrintf("<gml:TriangulatedSurface%s><gml:patches>%s<"
899 : "/gml:patches></gml:TriangulatedSurface>",
900 : pszGMLID, pszGeometry));
901 0 : CPLFree(pszGeometry);
902 0 : pszGeometry = pszNewGeom;
903 : }
904 : else
905 : {
906 215 : pszGeometry = poGeom->exportToGML(papszOptions);
907 : }
908 : }
909 215 : CSLDestroy(papszOptions);
910 215 : if (pszGeometry)
911 : {
912 214 : if (bWriteSpaceIndentation)
913 214 : VSIFPrintfL(fp, " ");
914 214 : if (bRemoveAppPrefix)
915 20 : poDS->PrintLine(fp, "<%s>%s</%s>",
916 : poFieldDefn->GetNameRef(), pszGeometry,
917 : poFieldDefn->GetNameRef());
918 : else
919 194 : poDS->PrintLine(fp, "<%s:%s>%s</%s:%s>", pszPrefix,
920 : poFieldDefn->GetNameRef(), pszGeometry,
921 : pszPrefix, poFieldDefn->GetNameRef());
922 : }
923 : else
924 : {
925 1 : CPLError(CE_Failure, CPLE_AppDefined,
926 : "Export of geometry to GML failed");
927 : }
928 215 : CPLFree(pszGeometry);
929 : }
930 : }
931 :
932 : // Write all "set" fields.
933 884 : for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++)
934 : {
935 621 : if (iField == nGMLIdIndex)
936 13 : continue;
937 608 : OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
938 :
939 608 : if (poFeature->IsFieldNull(iField))
940 : {
941 1 : const char *pszFieldName = poFieldDefn->GetNameRef();
942 :
943 1 : if (bWriteSpaceIndentation)
944 1 : VSIFPrintfL(fp, " ");
945 :
946 1 : if (bRemoveAppPrefix)
947 0 : poDS->PrintLine(fp, "<%s xsi:nil=\"true\"/>", pszFieldName);
948 : else
949 1 : poDS->PrintLine(fp, "<%s:%s xsi:nil=\"true\"/>", pszPrefix,
950 : pszFieldName);
951 : }
952 607 : else if (poFeature->IsFieldSet(iField))
953 : {
954 500 : OGRFieldType eType = poFieldDefn->GetType();
955 500 : if (eType == OFTStringList)
956 : {
957 1 : char **papszIter = poFeature->GetFieldAsStringList(iField);
958 3 : while (papszIter != nullptr && *papszIter != nullptr)
959 : {
960 2 : char *pszEscaped = OGRGetXML_UTF8_EscapedString(*papszIter);
961 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
962 : bRemoveAppPrefix, poFieldDefn, pszEscaped);
963 2 : CPLFree(pszEscaped);
964 :
965 2 : papszIter++;
966 : }
967 : }
968 499 : else if (eType == OFTIntegerList)
969 : {
970 2 : int nCount = 0;
971 : const int *panVals =
972 2 : poFeature->GetFieldAsIntegerList(iField, &nCount);
973 2 : if (poFieldDefn->GetSubType() == OFSTBoolean)
974 : {
975 3 : for (int i = 0; i < nCount; i++)
976 : {
977 : // 0 and 1 are OK, but the canonical representation is
978 : // false and true.
979 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation,
980 : pszPrefix, bRemoveAppPrefix, poFieldDefn,
981 2 : panVals[i] ? "true" : "false");
982 : }
983 : }
984 : else
985 : {
986 3 : for (int i = 0; i < nCount; i++)
987 : {
988 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation,
989 : pszPrefix, bRemoveAppPrefix, poFieldDefn,
990 2 : CPLSPrintf("%d", panVals[i]));
991 : }
992 : }
993 : }
994 497 : else if (eType == OFTInteger64List)
995 : {
996 2 : int nCount = 0;
997 : const GIntBig *panVals =
998 2 : poFeature->GetFieldAsInteger64List(iField, &nCount);
999 2 : if (poFieldDefn->GetSubType() == OFSTBoolean)
1000 : {
1001 0 : for (int i = 0; i < nCount; i++)
1002 : {
1003 : // 0 and 1 are OK, but the canonical representation is
1004 : // false and true.
1005 0 : GMLWriteField(poDS, fp, bWriteSpaceIndentation,
1006 : pszPrefix, bRemoveAppPrefix, poFieldDefn,
1007 0 : panVals[i] ? "true" : "false");
1008 : }
1009 : }
1010 : else
1011 : {
1012 5 : for (int i = 0; i < nCount; i++)
1013 : {
1014 3 : GMLWriteField(poDS, fp, bWriteSpaceIndentation,
1015 : pszPrefix, bRemoveAppPrefix, poFieldDefn,
1016 3 : CPLSPrintf(CPL_FRMT_GIB, panVals[i]));
1017 : }
1018 : }
1019 : }
1020 495 : else if (eType == OFTRealList)
1021 : {
1022 1 : int nCount = 0;
1023 : const double *padfVals =
1024 1 : poFeature->GetFieldAsDoubleList(iField, &nCount);
1025 3 : for (int i = 0; i < nCount; i++)
1026 : {
1027 2 : char szBuffer[80] = {};
1028 2 : CPLsnprintf(szBuffer, sizeof(szBuffer), "%.15g",
1029 2 : padfVals[i]);
1030 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1031 : bRemoveAppPrefix, poFieldDefn, szBuffer);
1032 : }
1033 : }
1034 625 : else if ((eType == OFTInteger || eType == OFTInteger64) &&
1035 131 : poFieldDefn->GetSubType() == OFSTBoolean)
1036 : {
1037 : // 0 and 1 are OK, but the canonical representation is false and
1038 : // true.
1039 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1040 : bRemoveAppPrefix, poFieldDefn,
1041 2 : (poFeature->GetFieldAsInteger(iField)) ? "true"
1042 : : "false");
1043 : }
1044 492 : else if (eType == OFTDate)
1045 : {
1046 49 : const OGRField *poField = poFeature->GetRawFieldRef(iField);
1047 : const char *pszXML =
1048 98 : CPLSPrintf("%04d-%02d-%02d", poField->Date.Year,
1049 49 : poField->Date.Month, poField->Date.Day);
1050 49 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1051 : bRemoveAppPrefix, poFieldDefn, pszXML);
1052 : }
1053 443 : else if (eType == OFTDateTime)
1054 : {
1055 : char *pszXML =
1056 49 : OGRGetXMLDateTime(poFeature->GetRawFieldRef(iField));
1057 49 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1058 : bRemoveAppPrefix, poFieldDefn, pszXML);
1059 49 : CPLFree(pszXML);
1060 : }
1061 : else
1062 : {
1063 394 : const char *pszRaw = poFeature->GetFieldAsString(iField);
1064 :
1065 394 : char *pszEscaped = OGRGetXML_UTF8_EscapedString(pszRaw);
1066 :
1067 394 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1068 : bRemoveAppPrefix, poFieldDefn, pszEscaped);
1069 394 : CPLFree(pszEscaped);
1070 : }
1071 : }
1072 : }
1073 :
1074 263 : if (bWriteSpaceIndentation)
1075 263 : VSIFPrintfL(fp, " ");
1076 263 : if (bRemoveAppPrefix)
1077 20 : poDS->PrintLine(fp, "</%s>", poFeatureDefn->GetName());
1078 : else
1079 243 : poDS->PrintLine(fp, "</%s:%s>", pszPrefix, poFeatureDefn->GetName());
1080 263 : if (bWriteSpaceIndentation)
1081 263 : VSIFPrintfL(fp, " ");
1082 263 : if (bIsGML3Output && !bGMLFeatureCollection)
1083 : {
1084 219 : if (bRemoveAppPrefix)
1085 10 : poDS->PrintLine(fp, "</featureMember>");
1086 : else
1087 209 : poDS->PrintLine(fp, "</%s:featureMember>", pszPrefix);
1088 : }
1089 : else
1090 : {
1091 44 : poDS->PrintLine(fp, "</gml:featureMember>");
1092 : }
1093 :
1094 263 : return OGRERR_NONE;
1095 : }
1096 :
1097 : /************************************************************************/
1098 : /* TestCapability() */
1099 : /************************************************************************/
1100 :
1101 338 : int OGRGMLLayer::TestCapability(const char *pszCap)
1102 :
1103 : {
1104 338 : if (EQUAL(pszCap, OLCSequentialWrite))
1105 19 : return bWriter;
1106 :
1107 319 : else if (EQUAL(pszCap, OLCCreateField))
1108 18 : return bWriter && iNextGMLId == 0;
1109 :
1110 301 : else if (EQUAL(pszCap, OLCCreateGeomField))
1111 4 : return bWriter && iNextGMLId == 0;
1112 :
1113 297 : else if (EQUAL(pszCap, OLCFastGetExtent))
1114 : {
1115 4 : if (poFClass == nullptr)
1116 0 : return FALSE;
1117 :
1118 4 : double dfXMin = 0.0;
1119 4 : double dfXMax = 0.0;
1120 4 : double dfYMin = 0.0;
1121 4 : double dfYMax = 0.0;
1122 :
1123 4 : return poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax);
1124 : }
1125 :
1126 293 : else if (EQUAL(pszCap, OLCFastFeatureCount))
1127 : {
1128 1 : if (poFClass == nullptr || m_poFilterGeom != nullptr ||
1129 1 : m_poAttrQuery != nullptr)
1130 0 : return FALSE;
1131 :
1132 1 : return poFClass->GetFeatureCount() != -1;
1133 : }
1134 :
1135 292 : else if (EQUAL(pszCap, OLCStringsAsUTF8))
1136 14 : return TRUE;
1137 :
1138 278 : else if (EQUAL(pszCap, OLCCurveGeometries))
1139 145 : return poDS->IsGML3Output();
1140 :
1141 133 : else if (EQUAL(pszCap, OLCZGeometries))
1142 3 : return TRUE;
1143 :
1144 : else
1145 130 : return FALSE;
1146 : }
1147 :
1148 : /************************************************************************/
1149 : /* CreateField() */
1150 : /************************************************************************/
1151 :
1152 181 : OGRErr OGRGMLLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
1153 :
1154 : {
1155 181 : if (!bWriter || iNextGMLId != 0)
1156 0 : return OGRERR_FAILURE;
1157 :
1158 : /* -------------------------------------------------------------------- */
1159 : /* Enforce XML naming semantics on element name. */
1160 : /* -------------------------------------------------------------------- */
1161 362 : OGRFieldDefn oCleanCopy(poField);
1162 181 : char *pszName = CPLStrdup(poField->GetNameRef());
1163 181 : CPLCleanXMLElementName(pszName);
1164 :
1165 181 : if (strcmp(pszName, poField->GetNameRef()) != 0)
1166 : {
1167 0 : if (!bApproxOK)
1168 : {
1169 0 : CPLFree(pszName);
1170 0 : CPLError(CE_Failure, CPLE_AppDefined,
1171 : "Unable to create field with name '%s', it would not\n"
1172 : "be valid as an XML element name.",
1173 : poField->GetNameRef());
1174 0 : return OGRERR_FAILURE;
1175 : }
1176 :
1177 0 : oCleanCopy.SetName(pszName);
1178 0 : CPLError(CE_Warning, CPLE_AppDefined,
1179 : "Field name '%s' adjusted to '%s' to be a valid\n"
1180 : "XML element name.",
1181 : poField->GetNameRef(), pszName);
1182 : }
1183 :
1184 181 : CPLFree(pszName);
1185 :
1186 181 : poFeatureDefn->AddFieldDefn(&oCleanCopy);
1187 :
1188 181 : return OGRERR_NONE;
1189 : }
1190 :
1191 : /************************************************************************/
1192 : /* CreateGeomField() */
1193 : /************************************************************************/
1194 :
1195 19 : OGRErr OGRGMLLayer::CreateGeomField(const OGRGeomFieldDefn *poField,
1196 : int bApproxOK)
1197 :
1198 : {
1199 19 : if (!bWriter || iNextGMLId != 0)
1200 0 : return OGRERR_FAILURE;
1201 :
1202 : /* -------------------------------------------------------------------- */
1203 : /* Enforce XML naming semantics on element name. */
1204 : /* -------------------------------------------------------------------- */
1205 38 : OGRGeomFieldDefn oCleanCopy(poField);
1206 19 : const auto poSRSOri = poField->GetSpatialRef();
1207 19 : poDS->DeclareNewWriteSRS(poSRSOri);
1208 19 : if (poSRSOri)
1209 : {
1210 6 : auto poSRS = poSRSOri->Clone();
1211 6 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1212 6 : oCleanCopy.SetSpatialRef(poSRS);
1213 6 : poSRS->Release();
1214 : }
1215 19 : char *pszName = CPLStrdup(poField->GetNameRef());
1216 19 : CPLCleanXMLElementName(pszName);
1217 :
1218 19 : if (strcmp(pszName, poField->GetNameRef()) != 0)
1219 : {
1220 0 : if (!bApproxOK)
1221 : {
1222 0 : CPLFree(pszName);
1223 0 : CPLError(CE_Failure, CPLE_AppDefined,
1224 : "Unable to create field with name '%s', it would not\n"
1225 : "be valid as an XML element name.",
1226 : poField->GetNameRef());
1227 0 : return OGRERR_FAILURE;
1228 : }
1229 :
1230 0 : oCleanCopy.SetName(pszName);
1231 0 : CPLError(CE_Warning, CPLE_AppDefined,
1232 : "Field name '%s' adjusted to '%s' to be a valid\n"
1233 : "XML element name.",
1234 : poField->GetNameRef(), pszName);
1235 : }
1236 :
1237 19 : CPLFree(pszName);
1238 :
1239 19 : poFeatureDefn->AddGeomFieldDefn(&oCleanCopy);
1240 :
1241 19 : return OGRERR_NONE;
1242 : }
1243 :
1244 : /************************************************************************/
1245 : /* GetDataset() */
1246 : /************************************************************************/
1247 :
1248 18 : GDALDataset *OGRGMLLayer::GetDataset()
1249 : {
1250 18 : return poDS;
1251 : }
|