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