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