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 681 : OGRGMLLayer::OGRGMLLayer(const char *pszName, bool bWriterIn,
27 681 : OGRGMLDataSource *poDSIn)
28 : : poFeatureDefn(new OGRFeatureDefn(
29 681 : pszName + (STARTS_WITH_CI(pszName, "ogr:") ? 4 : 0))),
30 : iNextGMLId(0), bInvalidFIDFound(false), pszFIDPrefix(nullptr),
31 : bWriter(bWriterIn), poDS(poDSIn),
32 681 : poFClass(!bWriter ? poDS->GetReader()->GetClass(pszName) : nullptr),
33 : // Reader's should get the corresponding GMLFeatureClass and cache it.
34 1362 : hCacheSRS(GML_BuildOGRGeometryFromList_CreateCache()),
35 : // Compatibility option. Not advertized, because hopefully won't be
36 : // needed. Just put here in case.
37 : bUseOldFIDFormat(
38 681 : 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 2724 : CPLTestBool(CPLGetConfigOption("GML_FACE_HOLE_NEGATIVE", "NO")))
43 : {
44 681 : SetDescription(poFeatureDefn->GetName());
45 681 : poFeatureDefn->Reference();
46 681 : poFeatureDefn->SetGeomType(wkbNone);
47 681 : }
48 :
49 : /************************************************************************/
50 : /* ~OGRGMLLayer() */
51 : /************************************************************************/
52 :
53 1362 : OGRGMLLayer::~OGRGMLLayer()
54 :
55 : {
56 681 : CPLFree(pszFIDPrefix);
57 :
58 681 : if (poFeatureDefn)
59 681 : poFeatureDefn->Release();
60 :
61 681 : GML_BuildOGRGeometryFromList_DestroyCache(hCacheSRS);
62 1362 : }
63 :
64 : /************************************************************************/
65 : /* ResetReading() */
66 : /************************************************************************/
67 :
68 750 : void OGRGMLLayer::ResetReading()
69 :
70 : {
71 750 : if (bWriter)
72 16 : return;
73 :
74 1468 : if (poDS->GetReadMode() == INTERLEAVED_LAYERS ||
75 734 : 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 94 : if (iNextGMLId == 0 && poDS->PeekStoredGMLFeature() != nullptr &&
80 0 : poDS->PeekStoredGMLFeature()->GetClass() == poFClass)
81 0 : return;
82 :
83 94 : delete poDS->PeekStoredGMLFeature();
84 94 : poDS->SetStoredGMLFeature(nullptr);
85 : }
86 :
87 734 : iNextGMLId = 0;
88 734 : poDS->GetReader()->ResetReading();
89 734 : CPLDebug("GML", "ResetReading()");
90 734 : 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 563 : static GIntBig Increment(GIntBig nVal)
105 : {
106 563 : if (nVal <= GINTBIG_MAX - 1)
107 563 : return nVal + 1;
108 0 : return nVal;
109 : }
110 :
111 : /************************************************************************/
112 : /* GetNextFeature() */
113 : /************************************************************************/
114 :
115 824 : OGRFeature *OGRGMLLayer::GetNextFeature()
116 :
117 : {
118 824 : 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 808 : if (poDS->GetLastReadLayer() != this)
126 : {
127 380 : if (poDS->GetReadMode() != INTERLEAVED_LAYERS)
128 371 : ResetReading();
129 380 : 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 1466 : GMLFeature *poGMLFeature = poDS->PeekStoredGMLFeature();
139 1466 : if (poGMLFeature != nullptr)
140 : {
141 3 : poDS->SetStoredGMLFeature(nullptr);
142 : }
143 : else
144 : {
145 1463 : poGMLFeature = poDS->GetReader()->NextFeature();
146 1463 : if (poGMLFeature == nullptr)
147 808 : 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 1334 : m_nFeaturesRead++;
153 : }
154 :
155 : /* --------------------------------------------------------------------
156 : */
157 : /* Is it of the proper feature class? */
158 : /* --------------------------------------------------------------------
159 : */
160 :
161 1337 : if (poGMLFeature->GetClass() != poFClass)
162 : {
163 1836 : if (poDS->GetReadMode() == INTERLEAVED_LAYERS ||
164 1222 : (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 610 : delete poGMLFeature;
173 610 : 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 723 : GIntBig nFID = -1;
189 723 : const char *pszGML_FID = poGMLFeature->GetFID();
190 723 : if (bInvalidFIDFound)
191 : {
192 44 : nFID = iNextGMLId;
193 44 : iNextGMLId = Increment(iNextGMLId);
194 : }
195 679 : else if (pszGML_FID == nullptr)
196 : {
197 109 : bInvalidFIDFound = true;
198 109 : nFID = iNextGMLId;
199 109 : iNextGMLId = Increment(iNextGMLId);
200 : }
201 570 : else if (iNextGMLId == 0)
202 : {
203 293 : int j = 0;
204 293 : int i = static_cast<int>(strlen(pszGML_FID)) - 1;
205 710 : while (i >= 0 && pszGML_FID[i] >= '0' && pszGML_FID[i] <= '9' &&
206 : j < 20)
207 : {
208 417 : i--;
209 417 : j++;
210 : }
211 : // i points the last character of the fid.
212 293 : if (i >= 0 && j < 20 && pszFIDPrefix == nullptr)
213 : {
214 230 : pszFIDPrefix = static_cast<char *>(CPLMalloc(i + 2));
215 230 : pszFIDPrefix[i + 1] = '\0';
216 230 : strncpy(pszFIDPrefix, pszGML_FID, i + 1);
217 : }
218 : // pszFIDPrefix now contains the prefix or NULL if no prefix is
219 : // found.
220 293 : if (j < 20 && sscanf(pszGML_FID + i + 1, CPL_FRMT_GIB, &nFID) == 1)
221 : {
222 284 : if (iNextGMLId <= nFID)
223 284 : iNextGMLId = Increment(nFID);
224 : }
225 : else
226 : {
227 9 : bInvalidFIDFound = true;
228 9 : nFID = iNextGMLId;
229 9 : 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 723 : OGRGeometry **papoGeometries = nullptr;
264 723 : const CPLXMLNode *const *papsGeometry = poGMLFeature->GetGeometryList();
265 :
266 723 : const CPLXMLNode *apsGeometries[2] = {nullptr, nullptr};
267 : const CPLXMLNode *psBoundedByGeometry =
268 723 : poGMLFeature->GetBoundedByGeometry();
269 723 : if (psBoundedByGeometry && !(papsGeometry && papsGeometry[0]))
270 : {
271 6 : apsGeometries[0] = psBoundedByGeometry;
272 6 : papsGeometry = apsGeometries;
273 : }
274 :
275 723 : OGRGeometry *poGeom = nullptr;
276 :
277 723 : 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 629 : else if (papsGeometry[0] &&
336 531 : strcmp(papsGeometry[0]->pszValue, "null") == 0)
337 : {
338 : // do nothing
339 : }
340 625 : else if (papsGeometry[0] != nullptr)
341 : {
342 527 : const char *pszSRSName = poDS->GetGlobalSRSName();
343 527 : CPLPushErrorHandler(CPLQuietErrorHandler);
344 527 : poGeom = GML_BuildOGRGeometryFromList(
345 527 : papsGeometry, true, poDS->GetInvertAxisOrderIfLatLong(),
346 527 : pszSRSName, poDS->GetConsiderEPSGAsURN(),
347 527 : poDS->GetSwapCoordinates(), poDS->GetSecondaryGeometryOption(),
348 527 : hCacheSRS, bFaceHoleNegative);
349 527 : CPLPopErrorHandler();
350 :
351 : // Do geometry type changes if needed to match layer geometry type.
352 527 : if (poGeom != nullptr)
353 : {
354 527 : 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 527 : 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 703 : int iDstField = 0;
393 703 : OGRFeature *poOGRFeature = new OGRFeature(poFeatureDefn);
394 :
395 703 : poOGRFeature->SetFID(nFID);
396 703 : if (poDS->ExposeId())
397 : {
398 595 : if (pszGML_FID)
399 558 : poOGRFeature->SetField(iDstField, pszGML_FID);
400 595 : iDstField++;
401 : }
402 :
403 703 : const int nPropertyCount = poFClass->GetPropertyCount();
404 3430 : for (int iField = 0; iField < nPropertyCount; iField++, iDstField++)
405 : {
406 : const GMLProperty *psGMLProperty =
407 2727 : poGMLFeature->GetProperty(iField);
408 2727 : if (psGMLProperty == nullptr || psGMLProperty->nSubProperties == 0)
409 614 : continue;
410 :
411 2113 : if (EQUAL(psGMLProperty->papszSubProperties[0], OGR_GML_NULL))
412 : {
413 8 : poOGRFeature->SetFieldNull(iDstField);
414 8 : continue;
415 : }
416 :
417 2105 : switch (poFClass->GetProperty(iField)->GetType())
418 : {
419 354 : case GMLPT_Real:
420 : {
421 354 : poOGRFeature->SetField(
422 : iDstField,
423 354 : CPLAtof(psGMLProperty->papszSubProperties[0]));
424 : }
425 354 : 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 1552 : default:
524 1552 : poOGRFeature->SetField(
525 1552 : iDstField, psGMLProperty->papszSubProperties[0]);
526 1552 : break;
527 : }
528 : }
529 :
530 703 : delete poGMLFeature;
531 703 : 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 703 : 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 609 : poOGRFeature->SetGeometryDirectly(poGeom);
547 : }
548 :
549 : // Assign SRS.
550 1460 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
551 : {
552 757 : poGeom = poOGRFeature->GetGeomFieldRef(i);
553 757 : if (poGeom != nullptr)
554 : {
555 : const OGRSpatialReference *poSRS =
556 670 : poFeatureDefn->GetGeomFieldDefn(i)->GetSpatialRef();
557 670 : if (poSRS != nullptr)
558 137 : poGeom->assignSpatialReference(poSRS);
559 : }
560 : }
561 :
562 : /* --------------------------------------------------------------------
563 : */
564 : /* Test against the attribute query. */
565 : /* --------------------------------------------------------------------
566 : */
567 703 : if (m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poOGRFeature))
568 : {
569 28 : delete poOGRFeature;
570 28 : continue;
571 : }
572 :
573 : // Got the desired feature.
574 675 : return poOGRFeature;
575 658 : }
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 : /* IGetExtent() */
607 : /************************************************************************/
608 :
609 10 : OGRErr OGRGMLLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
610 : bool bForce)
611 :
612 : {
613 10 : if (GetGeomType() == wkbNone)
614 0 : return OGRERR_FAILURE;
615 :
616 10 : double dfXMin = 0.0;
617 10 : double dfXMax = 0.0;
618 10 : double dfYMin = 0.0;
619 10 : double dfYMax = 0.0;
620 20 : if (poFClass != nullptr &&
621 10 : poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax))
622 : {
623 8 : psExtent->MinX = dfXMin;
624 8 : psExtent->MaxX = dfXMax;
625 8 : psExtent->MinY = dfYMin;
626 8 : psExtent->MaxY = dfYMax;
627 :
628 8 : return OGRERR_NONE;
629 : }
630 :
631 2 : return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
632 : }
633 :
634 : /************************************************************************/
635 : /* GetExtent() */
636 : /************************************************************************/
637 :
638 505 : static void GMLWriteField(OGRGMLDataSource *poDS, VSILFILE *fp,
639 : bool bWriteSpaceIndentation, const char *pszPrefix,
640 : bool bRemoveAppPrefix, OGRFieldDefn *poFieldDefn,
641 : const char *pszVal)
642 :
643 : {
644 505 : const char *pszFieldName = poFieldDefn->GetNameRef();
645 :
646 505 : while (*pszVal == ' ')
647 0 : pszVal++;
648 :
649 505 : if (bWriteSpaceIndentation)
650 505 : VSIFPrintfL(fp, " ");
651 :
652 505 : if (bRemoveAppPrefix)
653 60 : poDS->PrintLine(fp, "<%s>%s</%s>", pszFieldName, pszVal, pszFieldName);
654 : else
655 445 : poDS->PrintLine(fp, "<%s:%s>%s</%s:%s>", pszPrefix, pszFieldName,
656 : pszVal, pszPrefix, pszFieldName);
657 505 : }
658 :
659 : /************************************************************************/
660 : /* ICreateFeature() */
661 : /************************************************************************/
662 :
663 266 : OGRErr OGRGMLLayer::ICreateFeature(OGRFeature *poFeature)
664 :
665 : {
666 266 : const bool bIsGML3Output = poDS->IsGML3Output();
667 266 : VSILFILE *fp = poDS->GetOutputFP();
668 266 : const bool bWriteSpaceIndentation = poDS->WriteSpaceIndentation();
669 266 : const char *pszPrefix = poDS->GetAppPrefix();
670 266 : const bool bRemoveAppPrefix = poDS->RemoveAppPrefix();
671 266 : const bool bGMLFeatureCollection = poDS->GMLFeatureCollection();
672 :
673 266 : if (!bWriter || poDS->HasWriteError())
674 0 : return OGRERR_FAILURE;
675 :
676 266 : poFeature->FillUnsetWithDefault(TRUE, nullptr);
677 266 : if (!poFeature->Validate(OGR_F_VAL_ALL & ~OGR_F_VAL_GEOM_TYPE &
678 : ~OGR_F_VAL_ALLOW_NULL_WHEN_DEFAULT,
679 : TRUE))
680 2 : return OGRERR_FAILURE;
681 :
682 264 : if (bWriteSpaceIndentation)
683 264 : VSIFPrintfL(fp, " ");
684 264 : if (bIsGML3Output && !bGMLFeatureCollection)
685 : {
686 220 : if (bRemoveAppPrefix)
687 10 : poDS->PrintLine(fp, "<featureMember>");
688 : else
689 210 : poDS->PrintLine(fp, "<%s:featureMember>", pszPrefix);
690 : }
691 : else
692 : {
693 44 : poDS->PrintLine(fp, "<gml:featureMember>");
694 : }
695 :
696 264 : if (poFeature->GetFID() == OGRNullFID)
697 251 : poFeature->SetFID(iNextGMLId++);
698 :
699 264 : if (bWriteSpaceIndentation)
700 264 : VSIFPrintfL(fp, " ");
701 264 : VSIFPrintfL(fp, "<");
702 264 : if (!bRemoveAppPrefix)
703 244 : VSIFPrintfL(fp, "%s:", pszPrefix);
704 :
705 264 : int nGMLIdIndex = -1;
706 264 : if (bIsGML3Output)
707 : {
708 230 : nGMLIdIndex = poFeatureDefn->GetFieldIndex("gml_id");
709 230 : if (nGMLIdIndex >= 0 && poFeature->IsFieldSetAndNotNull(nGMLIdIndex))
710 3 : poDS->PrintLine(fp, "%s gml:id=\"%s\">", poFeatureDefn->GetName(),
711 : poFeature->GetFieldAsString(nGMLIdIndex));
712 : else
713 454 : poDS->PrintLine(fp, "%s gml:id=\"%s." CPL_FRMT_GIB "\">",
714 227 : poFeatureDefn->GetName(), poFeatureDefn->GetName(),
715 : poFeature->GetFID());
716 : }
717 : else
718 : {
719 34 : nGMLIdIndex = poFeatureDefn->GetFieldIndex("fid");
720 34 : if (bUseOldFIDFormat)
721 : {
722 0 : poDS->PrintLine(fp, "%s fid=\"F" CPL_FRMT_GIB "\">",
723 0 : poFeatureDefn->GetName(), poFeature->GetFID());
724 : }
725 44 : else if (nGMLIdIndex >= 0 &&
726 10 : poFeature->IsFieldSetAndNotNull(nGMLIdIndex))
727 : {
728 10 : poDS->PrintLine(fp, "%s fid=\"%s\">", poFeatureDefn->GetName(),
729 : poFeature->GetFieldAsString(nGMLIdIndex));
730 : }
731 : else
732 : {
733 48 : poDS->PrintLine(fp, "%s fid=\"%s." CPL_FRMT_GIB "\">",
734 24 : poFeatureDefn->GetName(), poFeatureDefn->GetName(),
735 : poFeature->GetFID());
736 : }
737 : }
738 :
739 517 : for (int iGeomField = 0; iGeomField < poFeatureDefn->GetGeomFieldCount();
740 : iGeomField++)
741 : {
742 : const OGRGeomFieldDefn *poFieldDefn =
743 253 : poFeatureDefn->GetGeomFieldDefn(iGeomField);
744 :
745 : // Write out Geometry - for now it isn't indented properly.
746 : // GML geometries don't like very much the concept of empty geometry.
747 253 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
748 253 : if (poGeom != nullptr && !poGeom->IsEmpty())
749 : {
750 215 : OGREnvelope3D sGeomBounds;
751 :
752 215 : const int nCoordDimension = poGeom->getCoordinateDimension();
753 :
754 215 : poGeom->getEnvelope(&sGeomBounds);
755 215 : if (poDS->HasWriteGlobalSRS())
756 211 : poDS->GrowExtents(&sGeomBounds, nCoordDimension);
757 :
758 356 : if (poGeom->getSpatialReference() == nullptr &&
759 141 : poFieldDefn->GetSpatialRef() != nullptr)
760 18 : poGeom->assignSpatialReference(poFieldDefn->GetSpatialRef());
761 :
762 215 : const auto &oCoordPrec = poFieldDefn->GetCoordinatePrecision();
763 :
764 215 : if (bIsGML3Output && poDS->WriteFeatureBoundedBy())
765 : {
766 171 : bool bCoordSwap = false;
767 :
768 : char *pszSRSName =
769 171 : GML_GetSRSName(poGeom->getSpatialReference(),
770 171 : poDS->GetSRSNameFormat(), &bCoordSwap);
771 171 : char szLowerCorner[75] = {};
772 171 : char szUpperCorner[75] = {};
773 :
774 171 : OGRWktOptions coordOpts;
775 :
776 171 : if (oCoordPrec.dfXYResolution !=
777 : OGRGeomCoordinatePrecision::UNKNOWN)
778 : {
779 3 : coordOpts.format = OGRWktFormat::F;
780 3 : coordOpts.xyPrecision =
781 3 : OGRGeomCoordinatePrecision::ResolutionToPrecision(
782 3 : oCoordPrec.dfXYResolution);
783 : }
784 171 : if (oCoordPrec.dfZResolution !=
785 : OGRGeomCoordinatePrecision::UNKNOWN)
786 : {
787 3 : coordOpts.format = OGRWktFormat::F;
788 3 : coordOpts.zPrecision =
789 3 : OGRGeomCoordinatePrecision::ResolutionToPrecision(
790 3 : oCoordPrec.dfZResolution);
791 : }
792 :
793 342 : std::string wkt;
794 171 : if (bCoordSwap)
795 : {
796 36 : wkt = OGRMakeWktCoordinate(
797 : sGeomBounds.MinY, sGeomBounds.MinX, sGeomBounds.MinZ,
798 18 : nCoordDimension, coordOpts);
799 18 : memcpy(szLowerCorner, wkt.data(), wkt.size() + 1);
800 :
801 36 : wkt = OGRMakeWktCoordinate(
802 : sGeomBounds.MaxY, sGeomBounds.MaxX, sGeomBounds.MaxZ,
803 18 : nCoordDimension, coordOpts);
804 18 : memcpy(szUpperCorner, wkt.data(), wkt.size() + 1);
805 : }
806 : else
807 : {
808 306 : wkt = OGRMakeWktCoordinate(
809 : sGeomBounds.MinX, sGeomBounds.MinY, sGeomBounds.MinZ,
810 153 : nCoordDimension, coordOpts);
811 153 : memcpy(szLowerCorner, wkt.data(), wkt.size() + 1);
812 :
813 306 : wkt = OGRMakeWktCoordinate(
814 : sGeomBounds.MaxX, sGeomBounds.MaxY, sGeomBounds.MaxZ,
815 153 : nCoordDimension, coordOpts);
816 153 : memcpy(szUpperCorner, wkt.data(), wkt.size() + 1);
817 : }
818 171 : if (bWriteSpaceIndentation)
819 171 : VSIFPrintfL(fp, " ");
820 171 : poDS->PrintLine(
821 : fp,
822 : "<gml:boundedBy><gml:Envelope%s%s><gml:lowerCorner>%s"
823 : "</gml:lowerCorner><gml:upperCorner>%s</gml:upperCorner>"
824 : "</gml:Envelope></gml:boundedBy>",
825 : (nCoordDimension == 3) ? " srsDimension=\"3\"" : "",
826 : pszSRSName, szLowerCorner, szUpperCorner);
827 171 : CPLFree(pszSRSName);
828 : }
829 :
830 215 : char **papszOptions = nullptr;
831 215 : if (bIsGML3Output)
832 : {
833 181 : papszOptions = CSLAddString(papszOptions, "FORMAT=GML3");
834 181 : if (poDS->GetSRSNameFormat() == SRSNAME_SHORT)
835 : papszOptions =
836 1 : CSLAddString(papszOptions, "SRSNAME_FORMAT=SHORT");
837 180 : else if (poDS->GetSRSNameFormat() == SRSNAME_OGC_URN)
838 : papszOptions =
839 167 : CSLAddString(papszOptions, "SRSNAME_FORMAT=OGC_URN");
840 13 : else if (poDS->GetSRSNameFormat() == SRSNAME_OGC_URL)
841 : papszOptions =
842 13 : CSLAddString(papszOptions, "SRSNAME_FORMAT=OGC_URL");
843 : }
844 215 : const char *pszSRSDimensionLoc = poDS->GetSRSDimensionLoc();
845 215 : if (pszSRSDimensionLoc != nullptr)
846 3 : papszOptions = CSLSetNameValue(papszOptions, "SRSDIMENSION_LOC",
847 : pszSRSDimensionLoc);
848 215 : if (poDS->IsGML32Output())
849 : {
850 115 : if (poFeatureDefn->GetGeomFieldCount() > 1)
851 18 : papszOptions = CSLAddString(
852 : papszOptions, CPLSPrintf("GMLID=%s.%s." CPL_FRMT_GIB,
853 9 : poFeatureDefn->GetName(),
854 : poFieldDefn->GetNameRef(),
855 : poFeature->GetFID()));
856 : else
857 212 : papszOptions = CSLAddString(
858 : papszOptions, CPLSPrintf("GMLID=%s.geom." CPL_FRMT_GIB,
859 106 : poFeatureDefn->GetName(),
860 : poFeature->GetFID()));
861 : }
862 :
863 215 : if (oCoordPrec.dfXYResolution !=
864 : OGRGeomCoordinatePrecision::UNKNOWN)
865 : {
866 3 : papszOptions = CSLAddString(
867 : papszOptions, CPLSPrintf("XY_COORD_RESOLUTION=%g",
868 3 : oCoordPrec.dfXYResolution));
869 : }
870 215 : if (oCoordPrec.dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
871 : {
872 3 : papszOptions = CSLAddString(
873 : papszOptions, CPLSPrintf("Z_COORD_RESOLUTION=%g",
874 3 : oCoordPrec.dfZResolution));
875 : }
876 :
877 215 : char *pszGeometry = nullptr;
878 215 : if (!bIsGML3Output && OGR_GT_IsNonLinear(poGeom->getGeometryType()))
879 : {
880 0 : OGRGeometry *poGeomTmp = OGRGeometryFactory::forceTo(
881 0 : poGeom->clone(),
882 0 : OGR_GT_GetLinear(poGeom->getGeometryType()));
883 0 : pszGeometry = poGeomTmp->exportToGML(papszOptions);
884 0 : delete poGeomTmp;
885 : }
886 : else
887 : {
888 215 : if (wkbFlatten(poGeom->getGeometryType()) == wkbTriangle)
889 : {
890 0 : pszGeometry = poGeom->exportToGML(papszOptions);
891 :
892 : const char *pszGMLID =
893 0 : poDS->IsGML32Output()
894 0 : ? CPLSPrintf(
895 : " gml:id=\"%s\"",
896 : CSLFetchNameValue(papszOptions, "GMLID"))
897 0 : : "";
898 0 : char *pszNewGeom = CPLStrdup(
899 : CPLSPrintf("<gml:TriangulatedSurface%s><gml:patches>%s<"
900 : "/gml:patches></gml:TriangulatedSurface>",
901 : pszGMLID, pszGeometry));
902 0 : CPLFree(pszGeometry);
903 0 : pszGeometry = pszNewGeom;
904 : }
905 : else
906 : {
907 215 : pszGeometry = poGeom->exportToGML(papszOptions);
908 : }
909 : }
910 215 : CSLDestroy(papszOptions);
911 215 : if (pszGeometry)
912 : {
913 214 : if (bWriteSpaceIndentation)
914 214 : VSIFPrintfL(fp, " ");
915 214 : if (bRemoveAppPrefix)
916 20 : poDS->PrintLine(fp, "<%s>%s</%s>",
917 : poFieldDefn->GetNameRef(), pszGeometry,
918 : poFieldDefn->GetNameRef());
919 : else
920 194 : poDS->PrintLine(fp, "<%s:%s>%s</%s:%s>", pszPrefix,
921 : poFieldDefn->GetNameRef(), pszGeometry,
922 : pszPrefix, poFieldDefn->GetNameRef());
923 : }
924 : else
925 : {
926 1 : CPLError(CE_Failure, CPLE_AppDefined,
927 : "Export of geometry to GML failed");
928 : }
929 215 : CPLFree(pszGeometry);
930 : }
931 : }
932 :
933 : // Write all "set" fields.
934 885 : for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++)
935 : {
936 621 : if (iField == nGMLIdIndex)
937 13 : continue;
938 608 : OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
939 :
940 608 : if (poFeature->IsFieldNull(iField))
941 : {
942 1 : const char *pszFieldName = poFieldDefn->GetNameRef();
943 :
944 1 : if (bWriteSpaceIndentation)
945 1 : VSIFPrintfL(fp, " ");
946 :
947 1 : if (bRemoveAppPrefix)
948 0 : poDS->PrintLine(fp, "<%s xsi:nil=\"true\"/>", pszFieldName);
949 : else
950 1 : poDS->PrintLine(fp, "<%s:%s xsi:nil=\"true\"/>", pszPrefix,
951 : pszFieldName);
952 : }
953 607 : else if (poFeature->IsFieldSet(iField))
954 : {
955 500 : OGRFieldType eType = poFieldDefn->GetType();
956 500 : if (eType == OFTStringList)
957 : {
958 1 : char **papszIter = poFeature->GetFieldAsStringList(iField);
959 3 : while (papszIter != nullptr && *papszIter != nullptr)
960 : {
961 2 : char *pszEscaped = OGRGetXML_UTF8_EscapedString(*papszIter);
962 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
963 : bRemoveAppPrefix, poFieldDefn, pszEscaped);
964 2 : CPLFree(pszEscaped);
965 :
966 2 : papszIter++;
967 : }
968 : }
969 499 : else if (eType == OFTIntegerList)
970 : {
971 2 : int nCount = 0;
972 : const int *panVals =
973 2 : poFeature->GetFieldAsIntegerList(iField, &nCount);
974 2 : if (poFieldDefn->GetSubType() == OFSTBoolean)
975 : {
976 3 : for (int i = 0; i < nCount; i++)
977 : {
978 : // 0 and 1 are OK, but the canonical representation is
979 : // false and true.
980 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation,
981 : pszPrefix, bRemoveAppPrefix, poFieldDefn,
982 2 : panVals[i] ? "true" : "false");
983 : }
984 : }
985 : else
986 : {
987 3 : for (int i = 0; i < nCount; i++)
988 : {
989 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation,
990 : pszPrefix, bRemoveAppPrefix, poFieldDefn,
991 2 : CPLSPrintf("%d", panVals[i]));
992 : }
993 : }
994 : }
995 497 : else if (eType == OFTInteger64List)
996 : {
997 2 : int nCount = 0;
998 : const GIntBig *panVals =
999 2 : poFeature->GetFieldAsInteger64List(iField, &nCount);
1000 2 : if (poFieldDefn->GetSubType() == OFSTBoolean)
1001 : {
1002 0 : for (int i = 0; i < nCount; i++)
1003 : {
1004 : // 0 and 1 are OK, but the canonical representation is
1005 : // false and true.
1006 0 : GMLWriteField(poDS, fp, bWriteSpaceIndentation,
1007 : pszPrefix, bRemoveAppPrefix, poFieldDefn,
1008 0 : panVals[i] ? "true" : "false");
1009 : }
1010 : }
1011 : else
1012 : {
1013 5 : for (int i = 0; i < nCount; i++)
1014 : {
1015 3 : GMLWriteField(poDS, fp, bWriteSpaceIndentation,
1016 : pszPrefix, bRemoveAppPrefix, poFieldDefn,
1017 3 : CPLSPrintf(CPL_FRMT_GIB, panVals[i]));
1018 : }
1019 : }
1020 : }
1021 495 : else if (eType == OFTRealList)
1022 : {
1023 1 : int nCount = 0;
1024 : const double *padfVals =
1025 1 : poFeature->GetFieldAsDoubleList(iField, &nCount);
1026 3 : for (int i = 0; i < nCount; i++)
1027 : {
1028 2 : char szBuffer[80] = {};
1029 2 : CPLsnprintf(szBuffer, sizeof(szBuffer), "%.15g",
1030 2 : padfVals[i]);
1031 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1032 : bRemoveAppPrefix, poFieldDefn, szBuffer);
1033 : }
1034 : }
1035 625 : else if ((eType == OFTInteger || eType == OFTInteger64) &&
1036 131 : poFieldDefn->GetSubType() == OFSTBoolean)
1037 : {
1038 : // 0 and 1 are OK, but the canonical representation is false and
1039 : // true.
1040 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1041 : bRemoveAppPrefix, poFieldDefn,
1042 2 : (poFeature->GetFieldAsInteger(iField)) ? "true"
1043 : : "false");
1044 : }
1045 492 : else if (eType == OFTDate)
1046 : {
1047 49 : const OGRField *poField = poFeature->GetRawFieldRef(iField);
1048 : const char *pszXML =
1049 98 : CPLSPrintf("%04d-%02d-%02d", poField->Date.Year,
1050 49 : poField->Date.Month, poField->Date.Day);
1051 49 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1052 : bRemoveAppPrefix, poFieldDefn, pszXML);
1053 : }
1054 443 : else if (eType == OFTDateTime)
1055 : {
1056 : char *pszXML =
1057 49 : OGRGetXMLDateTime(poFeature->GetRawFieldRef(iField));
1058 49 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1059 : bRemoveAppPrefix, poFieldDefn, pszXML);
1060 49 : CPLFree(pszXML);
1061 : }
1062 : else
1063 : {
1064 394 : const char *pszRaw = poFeature->GetFieldAsString(iField);
1065 :
1066 394 : char *pszEscaped = OGRGetXML_UTF8_EscapedString(pszRaw);
1067 :
1068 394 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1069 : bRemoveAppPrefix, poFieldDefn, pszEscaped);
1070 394 : CPLFree(pszEscaped);
1071 : }
1072 : }
1073 : }
1074 :
1075 264 : if (bWriteSpaceIndentation)
1076 264 : VSIFPrintfL(fp, " ");
1077 264 : if (bRemoveAppPrefix)
1078 20 : poDS->PrintLine(fp, "</%s>", poFeatureDefn->GetName());
1079 : else
1080 244 : poDS->PrintLine(fp, "</%s:%s>", pszPrefix, poFeatureDefn->GetName());
1081 264 : if (bWriteSpaceIndentation)
1082 264 : VSIFPrintfL(fp, " ");
1083 264 : if (bIsGML3Output && !bGMLFeatureCollection)
1084 : {
1085 220 : if (bRemoveAppPrefix)
1086 10 : poDS->PrintLine(fp, "</featureMember>");
1087 : else
1088 210 : poDS->PrintLine(fp, "</%s:featureMember>", pszPrefix);
1089 : }
1090 : else
1091 : {
1092 44 : poDS->PrintLine(fp, "</gml:featureMember>");
1093 : }
1094 :
1095 264 : return !poDS->HasWriteError() ? OGRERR_NONE : OGRERR_FAILURE;
1096 : }
1097 :
1098 : /************************************************************************/
1099 : /* TestCapability() */
1100 : /************************************************************************/
1101 :
1102 340 : int OGRGMLLayer::TestCapability(const char *pszCap)
1103 :
1104 : {
1105 340 : if (EQUAL(pszCap, OLCSequentialWrite))
1106 19 : return bWriter;
1107 :
1108 321 : else if (EQUAL(pszCap, OLCCreateField))
1109 18 : return bWriter && iNextGMLId == 0;
1110 :
1111 303 : else if (EQUAL(pszCap, OLCCreateGeomField))
1112 4 : return bWriter && iNextGMLId == 0;
1113 :
1114 299 : else if (EQUAL(pszCap, OLCFastGetExtent))
1115 : {
1116 4 : if (poFClass == nullptr)
1117 0 : return FALSE;
1118 :
1119 4 : double dfXMin = 0.0;
1120 4 : double dfXMax = 0.0;
1121 4 : double dfYMin = 0.0;
1122 4 : double dfYMax = 0.0;
1123 :
1124 4 : return poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax);
1125 : }
1126 :
1127 295 : else if (EQUAL(pszCap, OLCFastFeatureCount))
1128 : {
1129 1 : if (poFClass == nullptr || m_poFilterGeom != nullptr ||
1130 1 : m_poAttrQuery != nullptr)
1131 0 : return FALSE;
1132 :
1133 1 : return poFClass->GetFeatureCount() != -1;
1134 : }
1135 :
1136 294 : else if (EQUAL(pszCap, OLCStringsAsUTF8))
1137 14 : return TRUE;
1138 :
1139 280 : else if (EQUAL(pszCap, OLCCurveGeometries))
1140 146 : return poDS->IsGML3Output();
1141 :
1142 134 : else if (EQUAL(pszCap, OLCZGeometries))
1143 3 : return TRUE;
1144 :
1145 : else
1146 131 : return FALSE;
1147 : }
1148 :
1149 : /************************************************************************/
1150 : /* CreateField() */
1151 : /************************************************************************/
1152 :
1153 181 : OGRErr OGRGMLLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
1154 :
1155 : {
1156 181 : if (!bWriter || iNextGMLId != 0)
1157 0 : return OGRERR_FAILURE;
1158 :
1159 : /* -------------------------------------------------------------------- */
1160 : /* Enforce XML naming semantics on element name. */
1161 : /* -------------------------------------------------------------------- */
1162 362 : OGRFieldDefn oCleanCopy(poField);
1163 181 : char *pszName = CPLStrdup(poField->GetNameRef());
1164 181 : CPLCleanXMLElementName(pszName);
1165 :
1166 181 : if (strcmp(pszName, poField->GetNameRef()) != 0)
1167 : {
1168 0 : if (!bApproxOK)
1169 : {
1170 0 : CPLFree(pszName);
1171 0 : CPLError(CE_Failure, CPLE_AppDefined,
1172 : "Unable to create field with name '%s', it would not\n"
1173 : "be valid as an XML element name.",
1174 : poField->GetNameRef());
1175 0 : return OGRERR_FAILURE;
1176 : }
1177 :
1178 0 : oCleanCopy.SetName(pszName);
1179 0 : CPLError(CE_Warning, CPLE_AppDefined,
1180 : "Field name '%s' adjusted to '%s' to be a valid\n"
1181 : "XML element name.",
1182 : poField->GetNameRef(), pszName);
1183 : }
1184 :
1185 181 : CPLFree(pszName);
1186 :
1187 181 : poFeatureDefn->AddFieldDefn(&oCleanCopy);
1188 :
1189 181 : return OGRERR_NONE;
1190 : }
1191 :
1192 : /************************************************************************/
1193 : /* CreateGeomField() */
1194 : /************************************************************************/
1195 :
1196 19 : OGRErr OGRGMLLayer::CreateGeomField(const OGRGeomFieldDefn *poField,
1197 : int bApproxOK)
1198 :
1199 : {
1200 19 : if (!bWriter || iNextGMLId != 0)
1201 0 : return OGRERR_FAILURE;
1202 :
1203 : /* -------------------------------------------------------------------- */
1204 : /* Enforce XML naming semantics on element name. */
1205 : /* -------------------------------------------------------------------- */
1206 38 : OGRGeomFieldDefn oCleanCopy(poField);
1207 19 : const auto poSRSOri = poField->GetSpatialRef();
1208 19 : poDS->DeclareNewWriteSRS(poSRSOri);
1209 19 : if (poSRSOri)
1210 : {
1211 6 : auto poSRS = poSRSOri->Clone();
1212 6 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1213 6 : oCleanCopy.SetSpatialRef(poSRS);
1214 6 : poSRS->Release();
1215 : }
1216 19 : char *pszName = CPLStrdup(poField->GetNameRef());
1217 19 : CPLCleanXMLElementName(pszName);
1218 :
1219 19 : if (strcmp(pszName, poField->GetNameRef()) != 0)
1220 : {
1221 0 : if (!bApproxOK)
1222 : {
1223 0 : CPLFree(pszName);
1224 0 : CPLError(CE_Failure, CPLE_AppDefined,
1225 : "Unable to create field with name '%s', it would not\n"
1226 : "be valid as an XML element name.",
1227 : poField->GetNameRef());
1228 0 : return OGRERR_FAILURE;
1229 : }
1230 :
1231 0 : oCleanCopy.SetName(pszName);
1232 0 : CPLError(CE_Warning, CPLE_AppDefined,
1233 : "Field name '%s' adjusted to '%s' to be a valid\n"
1234 : "XML element name.",
1235 : poField->GetNameRef(), pszName);
1236 : }
1237 :
1238 19 : CPLFree(pszName);
1239 :
1240 19 : poFeatureDefn->AddGeomFieldDefn(&oCleanCopy);
1241 :
1242 19 : return OGRERR_NONE;
1243 : }
1244 :
1245 : /************************************************************************/
1246 : /* GetDataset() */
1247 : /************************************************************************/
1248 :
1249 18 : GDALDataset *OGRGMLLayer::GetDataset()
1250 : {
1251 18 : return poDS;
1252 : }
|