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 704 : OGRGMLLayer::OGRGMLLayer(const char *pszName, bool bWriterIn,
27 704 : OGRGMLDataSource *poDSIn)
28 : : poFeatureDefn(new OGRFeatureDefn(
29 704 : pszName + (STARTS_WITH_CI(pszName, "ogr:") ? 4 : 0))),
30 : iNextGMLId(0), bInvalidFIDFound(false), pszFIDPrefix(nullptr),
31 : bWriter(bWriterIn), poDS(poDSIn),
32 704 : poFClass(!bWriter ? poDS->GetReader()->GetClass(pszName) : nullptr),
33 : // Reader's should get the corresponding GMLFeatureClass and cache it.
34 1408 : hCacheSRS(GML_BuildOGRGeometryFromList_CreateCache()),
35 : // Compatibility option. Not advertized, because hopefully won't be
36 : // needed. Just put here in case.
37 : bUseOldFIDFormat(
38 704 : 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 2816 : CPLTestBool(CPLGetConfigOption("GML_FACE_HOLE_NEGATIVE", "NO")))
43 : {
44 704 : SetDescription(poFeatureDefn->GetName());
45 704 : poFeatureDefn->Reference();
46 704 : poFeatureDefn->SetGeomType(wkbNone);
47 704 : }
48 :
49 : /************************************************************************/
50 : /* ~OGRGMLLayer() */
51 : /************************************************************************/
52 :
53 1408 : OGRGMLLayer::~OGRGMLLayer()
54 :
55 : {
56 704 : CPLFree(pszFIDPrefix);
57 :
58 704 : if (poFeatureDefn)
59 704 : poFeatureDefn->Release();
60 :
61 704 : GML_BuildOGRGeometryFromList_DestroyCache(hCacheSRS);
62 1408 : }
63 :
64 : /************************************************************************/
65 : /* ResetReading() */
66 : /************************************************************************/
67 :
68 771 : void OGRGMLLayer::ResetReading()
69 :
70 : {
71 771 : if (bWriter)
72 16 : return;
73 :
74 1510 : if (poDS->GetReadMode() == INTERLEAVED_LAYERS ||
75 755 : 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 100 : if (iNextGMLId == 0 && poDS->PeekStoredGMLFeature() != nullptr &&
80 0 : poDS->PeekStoredGMLFeature()->GetClass() == poFClass)
81 0 : return;
82 :
83 100 : delete poDS->PeekStoredGMLFeature();
84 100 : poDS->SetStoredGMLFeature(nullptr);
85 : }
86 :
87 755 : iNextGMLId = 0;
88 755 : poDS->GetReader()->ResetReading();
89 755 : CPLDebug("GML", "ResetReading()");
90 755 : 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 579 : static GIntBig Increment(GIntBig nVal)
105 : {
106 579 : if (nVal <= GINTBIG_MAX - 1)
107 579 : return nVal + 1;
108 0 : return nVal;
109 : }
110 :
111 : /************************************************************************/
112 : /* GetNextFeature() */
113 : /************************************************************************/
114 :
115 842 : OGRFeature *OGRGMLLayer::GetNextFeature()
116 :
117 : {
118 842 : 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 826 : if (poDS->GetLastReadLayer() != this)
126 : {
127 395 : if (poDS->GetReadMode() != INTERLEAVED_LAYERS)
128 386 : ResetReading();
129 395 : poDS->SetLastReadLayer(this);
130 : }
131 :
132 826 : const bool bSkipCorruptedFeatures = CPLFetchBool(
133 826 : poDS->GetOpenOptions(), "SKIP_CORRUPTED_FEATURES",
134 826 : CPLTestBool(CPLGetConfigOption("GML_SKIP_CORRUPTED_FEATURES", "NO")));
135 :
136 : /* ==================================================================== */
137 : /* Loop till we find and translate a feature meeting all our */
138 : /* requirements. */
139 : /* ==================================================================== */
140 : while (true)
141 : {
142 1700 : GMLFeature *poGMLFeature = poDS->PeekStoredGMLFeature();
143 1700 : if (poGMLFeature != nullptr)
144 : {
145 3 : poDS->SetStoredGMLFeature(nullptr);
146 : }
147 : else
148 : {
149 1697 : poGMLFeature = poDS->GetReader()->NextFeature();
150 1697 : if (poGMLFeature == nullptr)
151 826 : return nullptr;
152 :
153 : // We count reading low level GML features as a feature read for
154 : // work checking purposes, though at least we didn't necessary
155 : // have to turn it into an OGRFeature.
156 1564 : m_nFeaturesRead++;
157 : }
158 :
159 : /* --------------------------------------------------------------------
160 : */
161 : /* Is it of the proper feature class? */
162 : /* --------------------------------------------------------------------
163 : */
164 :
165 1567 : if (poGMLFeature->GetClass() != poFClass)
166 : {
167 2478 : if (poDS->GetReadMode() == INTERLEAVED_LAYERS ||
168 1650 : (poDS->GetReadMode() == SEQUENTIAL_LAYERS && iNextGMLId != 0))
169 : {
170 4 : CPLAssert(poDS->PeekStoredGMLFeature() == nullptr);
171 4 : poDS->SetStoredGMLFeature(poGMLFeature);
172 4 : return nullptr;
173 : }
174 : else
175 : {
176 824 : delete poGMLFeature;
177 824 : continue;
178 : }
179 : }
180 :
181 : /* --------------------------------------------------------------------
182 : */
183 : /* Extract the fid: */
184 : /* -Assumes the fids are non-negative integers with an optional */
185 : /* prefix */
186 : /* -If a prefix differs from the prefix of the first feature from
187 : */
188 : /* the poDS then the fids from the poDS are ignored and are */
189 : /* assigned serially thereafter */
190 : /* --------------------------------------------------------------------
191 : */
192 739 : GIntBig nFID = -1;
193 739 : const char *pszGML_FID = poGMLFeature->GetFID();
194 739 : if (bInvalidFIDFound)
195 : {
196 44 : nFID = iNextGMLId;
197 44 : iNextGMLId = Increment(iNextGMLId);
198 : }
199 695 : else if (pszGML_FID == nullptr)
200 : {
201 115 : bInvalidFIDFound = true;
202 115 : nFID = iNextGMLId;
203 115 : iNextGMLId = Increment(iNextGMLId);
204 : }
205 580 : else if (iNextGMLId == 0)
206 : {
207 303 : int j = 0;
208 303 : int i = static_cast<int>(strlen(pszGML_FID)) - 1;
209 734 : while (i >= 0 && pszGML_FID[i] >= '0' && pszGML_FID[i] <= '9' &&
210 : j < 20)
211 : {
212 431 : i--;
213 431 : j++;
214 : }
215 : // i points the last character of the fid.
216 303 : if (i >= 0 && j < 20 && pszFIDPrefix == nullptr)
217 : {
218 239 : pszFIDPrefix = static_cast<char *>(CPLMalloc(i + 2));
219 239 : pszFIDPrefix[i + 1] = '\0';
220 239 : strncpy(pszFIDPrefix, pszGML_FID, i + 1);
221 : }
222 : // pszFIDPrefix now contains the prefix or NULL if no prefix is
223 : // found.
224 303 : if (j < 20 && sscanf(pszGML_FID + i + 1, CPL_FRMT_GIB, &nFID) == 1)
225 : {
226 294 : if (iNextGMLId <= nFID)
227 294 : iNextGMLId = Increment(nFID);
228 : }
229 : else
230 : {
231 9 : bInvalidFIDFound = true;
232 9 : nFID = iNextGMLId;
233 9 : iNextGMLId = Increment(iNextGMLId);
234 : }
235 : }
236 : else // if( iNextGMLId != 0 ).
237 : {
238 277 : const char *pszFIDPrefix_notnull = pszFIDPrefix;
239 277 : if (pszFIDPrefix_notnull == nullptr)
240 6 : pszFIDPrefix_notnull = "";
241 277 : int nLenPrefix = static_cast<int>(strlen(pszFIDPrefix_notnull));
242 :
243 827 : if (strncmp(pszGML_FID, pszFIDPrefix_notnull, nLenPrefix) == 0 &&
244 550 : strlen(pszGML_FID + nLenPrefix) < 20 &&
245 273 : sscanf(pszGML_FID + nLenPrefix, CPL_FRMT_GIB, &nFID) == 1)
246 : {
247 : // fid with the prefix. Using its numerical part.
248 272 : if (iNextGMLId < nFID)
249 112 : iNextGMLId = Increment(nFID);
250 : }
251 : else
252 : {
253 : // fid without the aforementioned prefix or a valid numerical
254 : // part.
255 5 : bInvalidFIDFound = true;
256 5 : nFID = iNextGMLId;
257 5 : iNextGMLId = Increment(iNextGMLId);
258 : }
259 : }
260 :
261 : /* --------------------------------------------------------------------
262 : */
263 : /* Does it satisfy the spatial query, if there is one? */
264 : /* --------------------------------------------------------------------
265 : */
266 :
267 739 : OGRGeometry **papoGeometries = nullptr;
268 739 : const CPLXMLNode *const *papsGeometry = poGMLFeature->GetGeometryList();
269 :
270 739 : const CPLXMLNode *apsGeometries[2] = {nullptr, nullptr};
271 : const CPLXMLNode *psBoundedByGeometry =
272 739 : poGMLFeature->GetBoundedByGeometry();
273 739 : if (psBoundedByGeometry && !(papsGeometry && papsGeometry[0]))
274 : {
275 6 : apsGeometries[0] = psBoundedByGeometry;
276 6 : papsGeometry = apsGeometries;
277 : }
278 :
279 739 : OGRGeometry *poGeom = nullptr;
280 :
281 739 : if (poFeatureDefn->GetGeomFieldCount() > 1)
282 : {
283 188 : papoGeometries = static_cast<OGRGeometry **>(CPLCalloc(
284 94 : poFeatureDefn->GetGeomFieldCount(), sizeof(OGRGeometry *)));
285 94 : const char *pszSRSName = poDS->GetGlobalSRSName();
286 301 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
287 : {
288 207 : const CPLXMLNode *psGeom = poGMLFeature->GetGeometryRef(i);
289 207 : if (psGeom != nullptr)
290 : {
291 163 : const CPLXMLNode *myGeometryList[2] = {psGeom, nullptr};
292 163 : poGeom = GML_BuildOGRGeometryFromList(
293 : myGeometryList, true,
294 163 : poDS->GetInvertAxisOrderIfLatLong(), pszSRSName,
295 163 : poDS->GetConsiderEPSGAsURN(),
296 163 : poDS->GetSwapCoordinates(),
297 163 : poDS->GetSecondaryGeometryOption(), hCacheSRS,
298 163 : bFaceHoleNegative);
299 :
300 : // Do geometry type changes if needed to match layer
301 : // geometry type.
302 163 : if (poGeom != nullptr)
303 : {
304 163 : papoGeometries[i] = OGRGeometryFactory::forceTo(
305 : poGeom,
306 163 : poFeatureDefn->GetGeomFieldDefn(i)->GetType());
307 163 : poGeom = nullptr;
308 : }
309 : else
310 : {
311 : // We assume the createFromGML() function would have
312 : // already reported the error.
313 0 : for (int j = 0; j < poFeatureDefn->GetGeomFieldCount();
314 : j++)
315 : {
316 0 : delete papoGeometries[j];
317 : }
318 0 : CPLFree(papoGeometries);
319 0 : delete poGMLFeature;
320 0 : return nullptr;
321 : }
322 : }
323 : }
324 :
325 0 : if (m_poFilterGeom != nullptr && m_iGeomFieldFilter >= 0 &&
326 0 : m_iGeomFieldFilter < poFeatureDefn->GetGeomFieldCount() &&
327 94 : papoGeometries[m_iGeomFieldFilter] &&
328 0 : !FilterGeometry(papoGeometries[m_iGeomFieldFilter]))
329 : {
330 0 : for (int j = 0; j < poFeatureDefn->GetGeomFieldCount(); j++)
331 : {
332 0 : delete papoGeometries[j];
333 : }
334 0 : CPLFree(papoGeometries);
335 0 : delete poGMLFeature;
336 0 : continue;
337 : }
338 : }
339 645 : else if (papsGeometry[0] &&
340 547 : strcmp(papsGeometry[0]->pszValue, "null") == 0)
341 : {
342 : // do nothing
343 : }
344 641 : else if (papsGeometry[0] != nullptr)
345 : {
346 543 : const char *pszSRSName = poDS->GetGlobalSRSName();
347 543 : CPLPushErrorHandler(CPLQuietErrorHandler);
348 543 : poGeom = GML_BuildOGRGeometryFromList(
349 543 : papsGeometry, true, poDS->GetInvertAxisOrderIfLatLong(),
350 543 : pszSRSName, poDS->GetConsiderEPSGAsURN(),
351 543 : poDS->GetSwapCoordinates(), poDS->GetSecondaryGeometryOption(),
352 543 : hCacheSRS, bFaceHoleNegative);
353 543 : CPLPopErrorHandler();
354 :
355 : // Do geometry type changes if needed to match layer geometry type.
356 543 : if (poGeom != nullptr)
357 : {
358 539 : poGeom = OGRGeometryFactory::forceTo(poGeom, GetGeomType());
359 : }
360 : else
361 : {
362 4 : const CPLString osLastErrorMsg(CPLGetLastErrorMsg());
363 :
364 8 : CPLError(
365 : bSkipCorruptedFeatures ? CE_Warning : CE_Failure,
366 : CPLE_AppDefined,
367 : "Geometry of feature " CPL_FRMT_GIB
368 : " %scannot be parsed: %s%s",
369 4 : nFID, pszGML_FID ? CPLSPrintf("%s ", pszGML_FID) : "",
370 : osLastErrorMsg.c_str(),
371 : bSkipCorruptedFeatures
372 : ? ". Skipping to next feature."
373 : : ". You may set the GML_SKIP_CORRUPTED_FEATURES "
374 : "configuration option to YES to skip to the next "
375 : "feature");
376 4 : delete poGMLFeature;
377 4 : if (bSkipCorruptedFeatures)
378 2 : continue;
379 2 : return nullptr;
380 : }
381 :
382 539 : if (m_poFilterGeom != nullptr && !FilterGeometry(poGeom))
383 : {
384 20 : delete poGMLFeature;
385 20 : delete poGeom;
386 20 : continue;
387 : }
388 : }
389 :
390 : /* --------------------------------------------------------------------
391 : */
392 : /* Convert the whole feature into an OGRFeature. */
393 : /* --------------------------------------------------------------------
394 : */
395 715 : int iDstField = 0;
396 715 : OGRFeature *poOGRFeature = new OGRFeature(poFeatureDefn);
397 :
398 715 : poOGRFeature->SetFID(nFID);
399 715 : if (poDS->ExposeId())
400 : {
401 607 : if (pszGML_FID)
402 564 : poOGRFeature->SetField(iDstField, pszGML_FID);
403 607 : iDstField++;
404 : }
405 :
406 715 : const int nPropertyCount = poFClass->GetPropertyCount();
407 3462 : for (int iField = 0; iField < nPropertyCount; iField++, iDstField++)
408 : {
409 : const GMLProperty *psGMLProperty =
410 2747 : poGMLFeature->GetProperty(iField);
411 2747 : if (psGMLProperty == nullptr || psGMLProperty->nSubProperties == 0)
412 614 : continue;
413 :
414 2133 : if (EQUAL(psGMLProperty->papszSubProperties[0], OGR_GML_NULL))
415 : {
416 8 : poOGRFeature->SetFieldNull(iDstField);
417 8 : continue;
418 : }
419 :
420 2125 : switch (poFClass->GetProperty(iField)->GetType())
421 : {
422 354 : case GMLPT_Real:
423 : {
424 354 : poOGRFeature->SetField(
425 : iDstField,
426 354 : CPLAtof(psGMLProperty->papszSubProperties[0]));
427 : }
428 354 : break;
429 :
430 13 : case GMLPT_IntegerList:
431 : {
432 13 : const int nCount = psGMLProperty->nSubProperties;
433 : int *panIntList =
434 13 : static_cast<int *>(CPLMalloc(sizeof(int) * nCount));
435 :
436 39 : for (int i = 0; i < nCount; i++)
437 26 : panIntList[i] =
438 26 : atoi(psGMLProperty->papszSubProperties[i]);
439 :
440 13 : poOGRFeature->SetField(iDstField, nCount, panIntList);
441 13 : CPLFree(panIntList);
442 : }
443 13 : break;
444 :
445 6 : case GMLPT_Integer64List:
446 : {
447 6 : const int nCount = psGMLProperty->nSubProperties;
448 : GIntBig *panIntList = static_cast<GIntBig *>(
449 6 : CPLMalloc(sizeof(GIntBig) * nCount));
450 :
451 15 : for (int i = 0; i < nCount; i++)
452 18 : panIntList[i] =
453 9 : CPLAtoGIntBig(psGMLProperty->papszSubProperties[i]);
454 :
455 6 : poOGRFeature->SetField(iDstField, nCount, panIntList);
456 6 : CPLFree(panIntList);
457 : }
458 6 : break;
459 :
460 25 : case GMLPT_RealList:
461 : {
462 25 : const int nCount = psGMLProperty->nSubProperties;
463 : double *padfList = static_cast<double *>(
464 25 : CPLMalloc(sizeof(double) * nCount));
465 :
466 59 : for (int i = 0; i < nCount; i++)
467 68 : padfList[i] =
468 34 : CPLAtof(psGMLProperty->papszSubProperties[i]);
469 :
470 25 : poOGRFeature->SetField(iDstField, nCount, padfList);
471 25 : CPLFree(padfList);
472 : }
473 25 : break;
474 :
475 106 : case GMLPT_StringList:
476 : case GMLPT_FeaturePropertyList:
477 : {
478 106 : poOGRFeature->SetField(iDstField,
479 106 : psGMLProperty->papszSubProperties);
480 : }
481 106 : break;
482 :
483 46 : case GMLPT_Boolean:
484 : {
485 46 : if (strcmp(psGMLProperty->papszSubProperties[0], "true") ==
486 7 : 0 ||
487 7 : strcmp(psGMLProperty->papszSubProperties[0], "1") == 0)
488 : {
489 39 : poOGRFeature->SetField(iDstField, 1);
490 : }
491 7 : else if (strcmp(psGMLProperty->papszSubProperties[0],
492 0 : "false") == 0 ||
493 0 : strcmp(psGMLProperty->papszSubProperties[0],
494 : "0") == 0)
495 : {
496 7 : poOGRFeature->SetField(iDstField, 0);
497 : }
498 : else
499 : {
500 0 : poOGRFeature->SetField(
501 0 : iDstField, psGMLProperty->papszSubProperties[0]);
502 : }
503 46 : break;
504 : }
505 :
506 3 : case GMLPT_BooleanList:
507 : {
508 3 : const int nCount = psGMLProperty->nSubProperties;
509 : int *panIntList =
510 3 : static_cast<int *>(CPLMalloc(sizeof(int) * nCount));
511 :
512 9 : for (int i = 0; i < nCount; i++)
513 : {
514 6 : panIntList[i] =
515 6 : (strcmp(psGMLProperty->papszSubProperties[i],
516 9 : "true") == 0 ||
517 3 : strcmp(psGMLProperty->papszSubProperties[i],
518 : "1") == 0);
519 : }
520 :
521 3 : poOGRFeature->SetField(iDstField, nCount, panIntList);
522 3 : CPLFree(panIntList);
523 3 : break;
524 : }
525 :
526 1572 : default:
527 1572 : poOGRFeature->SetField(
528 1572 : iDstField, psGMLProperty->papszSubProperties[0]);
529 1572 : break;
530 : }
531 : }
532 :
533 715 : delete poGMLFeature;
534 715 : poGMLFeature = nullptr;
535 :
536 : // Assign the geometry before the attribute filter because
537 : // the attribute filter may use a special field like OGR_GEOMETRY.
538 715 : if (papoGeometries != nullptr)
539 : {
540 301 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
541 : {
542 207 : poOGRFeature->SetGeomFieldDirectly(i, papoGeometries[i]);
543 : }
544 94 : CPLFree(papoGeometries);
545 94 : papoGeometries = nullptr;
546 : }
547 : else
548 : {
549 621 : poOGRFeature->SetGeometryDirectly(poGeom);
550 : }
551 :
552 : // Assign SRS.
553 1484 : for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
554 : {
555 769 : poGeom = poOGRFeature->GetGeomFieldRef(i);
556 769 : if (poGeom != nullptr)
557 : {
558 : const OGRSpatialReference *poSRS =
559 682 : poFeatureDefn->GetGeomFieldDefn(i)->GetSpatialRef();
560 682 : if (poSRS != nullptr)
561 145 : poGeom->assignSpatialReference(poSRS);
562 : }
563 : }
564 :
565 : /* --------------------------------------------------------------------
566 : */
567 : /* Test against the attribute query. */
568 : /* --------------------------------------------------------------------
569 : */
570 715 : if (m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poOGRFeature))
571 : {
572 28 : delete poOGRFeature;
573 28 : continue;
574 : }
575 :
576 : // Got the desired feature.
577 687 : return poOGRFeature;
578 874 : }
579 :
580 : return nullptr;
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(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 0 : OGRGeometry *poGeomTmp = OGRGeometryFactory::forceTo(
884 0 : poGeom->clone(),
885 0 : OGR_GT_GetLinear(poGeom->getGeometryType()));
886 0 : pszGeometry = poGeomTmp->exportToGML(papszOptions);
887 0 : delete poGeomTmp;
888 : }
889 : else
890 : {
891 215 : if (wkbFlatten(poGeom->getGeometryType()) == wkbTriangle)
892 : {
893 0 : pszGeometry = poGeom->exportToGML(papszOptions);
894 :
895 : const char *pszGMLID =
896 0 : poDS->IsGML32Output()
897 0 : ? CPLSPrintf(
898 : " gml:id=\"%s\"",
899 : CSLFetchNameValue(papszOptions, "GMLID"))
900 0 : : "";
901 0 : char *pszNewGeom = CPLStrdup(
902 : CPLSPrintf("<gml:TriangulatedSurface%s><gml:patches>%s<"
903 : "/gml:patches></gml:TriangulatedSurface>",
904 : pszGMLID, pszGeometry));
905 0 : CPLFree(pszGeometry);
906 0 : pszGeometry = pszNewGeom;
907 : }
908 : else
909 : {
910 215 : pszGeometry = poGeom->exportToGML(papszOptions);
911 : }
912 : }
913 215 : CSLDestroy(papszOptions);
914 215 : if (pszGeometry)
915 : {
916 214 : if (bWriteSpaceIndentation)
917 214 : VSIFPrintfL(fp, " ");
918 214 : if (bRemoveAppPrefix)
919 20 : poDS->PrintLine(fp, "<%s>%s</%s>",
920 : poFieldDefn->GetNameRef(), pszGeometry,
921 : poFieldDefn->GetNameRef());
922 : else
923 194 : poDS->PrintLine(fp, "<%s:%s>%s</%s:%s>", pszPrefix,
924 : poFieldDefn->GetNameRef(), pszGeometry,
925 : pszPrefix, poFieldDefn->GetNameRef());
926 : }
927 : else
928 : {
929 1 : CPLError(CE_Failure, CPLE_AppDefined,
930 : "Export of geometry to GML failed");
931 : }
932 215 : CPLFree(pszGeometry);
933 : }
934 : }
935 :
936 : // Write all "set" fields.
937 885 : for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++)
938 : {
939 621 : if (iField == nGMLIdIndex)
940 13 : continue;
941 608 : OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
942 :
943 608 : if (poFeature->IsFieldNull(iField))
944 : {
945 1 : const char *pszFieldName = poFieldDefn->GetNameRef();
946 :
947 1 : if (bWriteSpaceIndentation)
948 1 : VSIFPrintfL(fp, " ");
949 :
950 1 : if (bRemoveAppPrefix)
951 0 : poDS->PrintLine(fp, "<%s xsi:nil=\"true\"/>", pszFieldName);
952 : else
953 1 : poDS->PrintLine(fp, "<%s:%s xsi:nil=\"true\"/>", pszPrefix,
954 : pszFieldName);
955 : }
956 607 : else if (poFeature->IsFieldSet(iField))
957 : {
958 500 : OGRFieldType eType = poFieldDefn->GetType();
959 500 : if (eType == OFTStringList)
960 : {
961 1 : char **papszIter = poFeature->GetFieldAsStringList(iField);
962 3 : while (papszIter != nullptr && *papszIter != nullptr)
963 : {
964 2 : char *pszEscaped = OGRGetXML_UTF8_EscapedString(*papszIter);
965 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
966 : bRemoveAppPrefix, poFieldDefn, pszEscaped);
967 2 : CPLFree(pszEscaped);
968 :
969 2 : papszIter++;
970 : }
971 : }
972 499 : else if (eType == OFTIntegerList)
973 : {
974 2 : int nCount = 0;
975 : const int *panVals =
976 2 : poFeature->GetFieldAsIntegerList(iField, &nCount);
977 2 : if (poFieldDefn->GetSubType() == OFSTBoolean)
978 : {
979 3 : for (int i = 0; i < nCount; i++)
980 : {
981 : // 0 and 1 are OK, but the canonical representation is
982 : // false and true.
983 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation,
984 : pszPrefix, bRemoveAppPrefix, poFieldDefn,
985 2 : panVals[i] ? "true" : "false");
986 : }
987 : }
988 : else
989 : {
990 3 : for (int i = 0; i < nCount; i++)
991 : {
992 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation,
993 : pszPrefix, bRemoveAppPrefix, poFieldDefn,
994 2 : CPLSPrintf("%d", panVals[i]));
995 : }
996 : }
997 : }
998 497 : else if (eType == OFTInteger64List)
999 : {
1000 2 : int nCount = 0;
1001 : const GIntBig *panVals =
1002 2 : poFeature->GetFieldAsInteger64List(iField, &nCount);
1003 2 : if (poFieldDefn->GetSubType() == OFSTBoolean)
1004 : {
1005 0 : for (int i = 0; i < nCount; i++)
1006 : {
1007 : // 0 and 1 are OK, but the canonical representation is
1008 : // false and true.
1009 0 : GMLWriteField(poDS, fp, bWriteSpaceIndentation,
1010 : pszPrefix, bRemoveAppPrefix, poFieldDefn,
1011 0 : panVals[i] ? "true" : "false");
1012 : }
1013 : }
1014 : else
1015 : {
1016 5 : for (int i = 0; i < nCount; i++)
1017 : {
1018 3 : GMLWriteField(poDS, fp, bWriteSpaceIndentation,
1019 : pszPrefix, bRemoveAppPrefix, poFieldDefn,
1020 3 : CPLSPrintf(CPL_FRMT_GIB, panVals[i]));
1021 : }
1022 : }
1023 : }
1024 495 : else if (eType == OFTRealList)
1025 : {
1026 1 : int nCount = 0;
1027 : const double *padfVals =
1028 1 : poFeature->GetFieldAsDoubleList(iField, &nCount);
1029 3 : for (int i = 0; i < nCount; i++)
1030 : {
1031 2 : char szBuffer[80] = {};
1032 2 : CPLsnprintf(szBuffer, sizeof(szBuffer), "%.15g",
1033 2 : padfVals[i]);
1034 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1035 : bRemoveAppPrefix, poFieldDefn, szBuffer);
1036 : }
1037 : }
1038 625 : else if ((eType == OFTInteger || eType == OFTInteger64) &&
1039 131 : poFieldDefn->GetSubType() == OFSTBoolean)
1040 : {
1041 : // 0 and 1 are OK, but the canonical representation is false and
1042 : // true.
1043 2 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1044 : bRemoveAppPrefix, poFieldDefn,
1045 2 : (poFeature->GetFieldAsInteger(iField)) ? "true"
1046 : : "false");
1047 : }
1048 492 : else if (eType == OFTDate)
1049 : {
1050 49 : const OGRField *poField = poFeature->GetRawFieldRef(iField);
1051 : const char *pszXML =
1052 98 : CPLSPrintf("%04d-%02d-%02d", poField->Date.Year,
1053 49 : poField->Date.Month, poField->Date.Day);
1054 49 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1055 : bRemoveAppPrefix, poFieldDefn, pszXML);
1056 : }
1057 443 : else if (eType == OFTDateTime)
1058 : {
1059 : char *pszXML =
1060 49 : OGRGetXMLDateTime(poFeature->GetRawFieldRef(iField));
1061 49 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1062 : bRemoveAppPrefix, poFieldDefn, pszXML);
1063 49 : CPLFree(pszXML);
1064 : }
1065 : else
1066 : {
1067 394 : const char *pszRaw = poFeature->GetFieldAsString(iField);
1068 :
1069 394 : char *pszEscaped = OGRGetXML_UTF8_EscapedString(pszRaw);
1070 :
1071 394 : GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
1072 : bRemoveAppPrefix, poFieldDefn, pszEscaped);
1073 394 : CPLFree(pszEscaped);
1074 : }
1075 : }
1076 : }
1077 :
1078 264 : if (bWriteSpaceIndentation)
1079 264 : VSIFPrintfL(fp, " ");
1080 264 : if (bRemoveAppPrefix)
1081 20 : poDS->PrintLine(fp, "</%s>", poFeatureDefn->GetName());
1082 : else
1083 244 : poDS->PrintLine(fp, "</%s:%s>", pszPrefix, poFeatureDefn->GetName());
1084 264 : if (bWriteSpaceIndentation)
1085 264 : VSIFPrintfL(fp, " ");
1086 264 : if (bIsGML3Output && !bGMLFeatureCollection)
1087 : {
1088 220 : if (bRemoveAppPrefix)
1089 10 : poDS->PrintLine(fp, "</featureMember>");
1090 : else
1091 210 : poDS->PrintLine(fp, "</%s:featureMember>", pszPrefix);
1092 : }
1093 : else
1094 : {
1095 44 : poDS->PrintLine(fp, "</gml:featureMember>");
1096 : }
1097 :
1098 264 : return !poDS->HasWriteError() ? OGRERR_NONE : OGRERR_FAILURE;
1099 : }
1100 :
1101 : /************************************************************************/
1102 : /* TestCapability() */
1103 : /************************************************************************/
1104 :
1105 341 : int OGRGMLLayer::TestCapability(const char *pszCap)
1106 :
1107 : {
1108 341 : if (EQUAL(pszCap, OLCSequentialWrite))
1109 19 : return bWriter;
1110 :
1111 322 : else if (EQUAL(pszCap, OLCCreateField))
1112 18 : return bWriter && iNextGMLId == 0;
1113 :
1114 304 : else if (EQUAL(pszCap, OLCCreateGeomField))
1115 4 : return bWriter && iNextGMLId == 0;
1116 :
1117 300 : else if (EQUAL(pszCap, OLCFastGetExtent))
1118 : {
1119 4 : if (poFClass == nullptr)
1120 0 : return FALSE;
1121 :
1122 4 : double dfXMin = 0.0;
1123 4 : double dfXMax = 0.0;
1124 4 : double dfYMin = 0.0;
1125 4 : double dfYMax = 0.0;
1126 :
1127 4 : return poFClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax);
1128 : }
1129 :
1130 296 : else if (EQUAL(pszCap, OLCFastFeatureCount))
1131 : {
1132 1 : if (poFClass == nullptr || m_poFilterGeom != nullptr ||
1133 1 : m_poAttrQuery != nullptr)
1134 0 : return FALSE;
1135 :
1136 1 : return poFClass->GetFeatureCount() != -1;
1137 : }
1138 :
1139 295 : else if (EQUAL(pszCap, OLCStringsAsUTF8))
1140 15 : return TRUE;
1141 :
1142 280 : else if (EQUAL(pszCap, OLCCurveGeometries))
1143 146 : return poDS->IsGML3Output();
1144 :
1145 134 : else if (EQUAL(pszCap, OLCZGeometries))
1146 3 : return TRUE;
1147 :
1148 : else
1149 131 : return FALSE;
1150 : }
1151 :
1152 : /************************************************************************/
1153 : /* CreateField() */
1154 : /************************************************************************/
1155 :
1156 181 : OGRErr OGRGMLLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
1157 :
1158 : {
1159 181 : if (!bWriter || iNextGMLId != 0)
1160 0 : return OGRERR_FAILURE;
1161 :
1162 : /* -------------------------------------------------------------------- */
1163 : /* Enforce XML naming semantics on element name. */
1164 : /* -------------------------------------------------------------------- */
1165 362 : OGRFieldDefn oCleanCopy(poField);
1166 181 : char *pszName = CPLStrdup(poField->GetNameRef());
1167 181 : CPLCleanXMLElementName(pszName);
1168 :
1169 181 : if (strcmp(pszName, poField->GetNameRef()) != 0)
1170 : {
1171 0 : if (!bApproxOK)
1172 : {
1173 0 : CPLFree(pszName);
1174 0 : CPLError(CE_Failure, CPLE_AppDefined,
1175 : "Unable to create field with name '%s', it would not\n"
1176 : "be valid as an XML element name.",
1177 : poField->GetNameRef());
1178 0 : return OGRERR_FAILURE;
1179 : }
1180 :
1181 0 : oCleanCopy.SetName(pszName);
1182 0 : CPLError(CE_Warning, CPLE_AppDefined,
1183 : "Field name '%s' adjusted to '%s' to be a valid\n"
1184 : "XML element name.",
1185 : poField->GetNameRef(), pszName);
1186 : }
1187 :
1188 181 : CPLFree(pszName);
1189 :
1190 181 : poFeatureDefn->AddFieldDefn(&oCleanCopy);
1191 :
1192 181 : return OGRERR_NONE;
1193 : }
1194 :
1195 : /************************************************************************/
1196 : /* CreateGeomField() */
1197 : /************************************************************************/
1198 :
1199 19 : OGRErr OGRGMLLayer::CreateGeomField(const OGRGeomFieldDefn *poField,
1200 : int bApproxOK)
1201 :
1202 : {
1203 19 : if (!bWriter || iNextGMLId != 0)
1204 0 : return OGRERR_FAILURE;
1205 :
1206 : /* -------------------------------------------------------------------- */
1207 : /* Enforce XML naming semantics on element name. */
1208 : /* -------------------------------------------------------------------- */
1209 38 : OGRGeomFieldDefn oCleanCopy(poField);
1210 19 : const auto poSRSOri = poField->GetSpatialRef();
1211 19 : poDS->DeclareNewWriteSRS(poSRSOri);
1212 19 : if (poSRSOri)
1213 : {
1214 6 : auto poSRS = poSRSOri->Clone();
1215 6 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1216 6 : oCleanCopy.SetSpatialRef(poSRS);
1217 6 : poSRS->Release();
1218 : }
1219 19 : char *pszName = CPLStrdup(poField->GetNameRef());
1220 19 : CPLCleanXMLElementName(pszName);
1221 :
1222 19 : if (strcmp(pszName, poField->GetNameRef()) != 0)
1223 : {
1224 0 : if (!bApproxOK)
1225 : {
1226 0 : CPLFree(pszName);
1227 0 : CPLError(CE_Failure, CPLE_AppDefined,
1228 : "Unable to create field with name '%s', it would not\n"
1229 : "be valid as an XML element name.",
1230 : poField->GetNameRef());
1231 0 : return OGRERR_FAILURE;
1232 : }
1233 :
1234 0 : oCleanCopy.SetName(pszName);
1235 0 : CPLError(CE_Warning, CPLE_AppDefined,
1236 : "Field name '%s' adjusted to '%s' to be a valid\n"
1237 : "XML element name.",
1238 : poField->GetNameRef(), pszName);
1239 : }
1240 :
1241 19 : CPLFree(pszName);
1242 :
1243 19 : poFeatureDefn->AddGeomFieldDefn(&oCleanCopy);
1244 :
1245 19 : return OGRERR_NONE;
1246 : }
1247 :
1248 : /************************************************************************/
1249 : /* GetDataset() */
1250 : /************************************************************************/
1251 :
1252 18 : GDALDataset *OGRGMLLayer::GetDataset()
1253 : {
1254 18 : return poDS;
1255 : }
|