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