LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gmlutils - gmlfeatureclass.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 464 584 79.5 %
Date: 2025-01-18 12:42:00 Functions: 28 30 93.3 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Project:  GML Reader
       4             :  * Purpose:  Implementation of GMLFeatureClass.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  **********************************************************************
       8             :  * Copyright (c) 2002, Frank Warmerdam
       9             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "gmlfeature.h"
      16             : 
      17             : #include <cmath>
      18             : #include <cstddef>
      19             : #include <cstdio>
      20             : #include <cstdlib>
      21             : #include <cstring>
      22             : #include <string>
      23             : 
      24             : #include "cpl_conv.h"
      25             : #include "cpl_error.h"
      26             : #include "cpl_minixml.h"
      27             : #include "cpl_string.h"
      28             : #include "ogr_core.h"
      29             : #include "ogr_p.h"
      30             : #include "ogr_geometry.h"
      31             : 
      32             : /************************************************************************/
      33             : /*                          GMLFeatureClass()                           */
      34             : /************************************************************************/
      35             : 
      36         876 : GMLFeatureClass::GMLFeatureClass(const char *pszName)
      37         876 :     : m_pszName(CPLStrdup(pszName)), m_pszElementName(nullptr),
      38         876 :       n_nNameLen(static_cast<int>(strlen(pszName))), n_nElementNameLen(0),
      39             :       m_nPropertyCount(0), m_papoProperty(nullptr), m_nGeometryPropertyCount(0),
      40             :       m_papoGeometryProperty(nullptr), m_bSchemaLocked(false),
      41             :       m_nFeatureCount(-1),  // Unknown.
      42             :       m_pszExtraInfo(nullptr), m_bHaveExtents(false), m_dfXMin(0.0),
      43             :       m_dfXMax(0.0), m_dfYMin(0.0), m_dfYMax(0.0), m_pszSRSName(nullptr),
      44         876 :       m_bSRSNameConsistent(true)
      45             : {
      46         876 : }
      47             : 
      48             : /************************************************************************/
      49             : /*                          ~GMLFeatureClass()                          */
      50             : /************************************************************************/
      51             : 
      52         876 : GMLFeatureClass::~GMLFeatureClass()
      53             : 
      54             : {
      55         876 :     CPLFree(m_pszName);
      56         876 :     CPLFree(m_pszElementName);
      57             : 
      58        3869 :     for (int i = 0; i < m_nPropertyCount; i++)
      59        2993 :         delete m_papoProperty[i];
      60         876 :     CPLFree(m_papoProperty);
      61             : 
      62         876 :     ClearGeometryProperties();
      63             : 
      64         876 :     CPLFree(m_pszSRSName);
      65         876 : }
      66             : 
      67             : /************************************************************************/
      68             : /*                         StealProperties()                            */
      69             : /************************************************************************/
      70             : 
      71           4 : void GMLFeatureClass::StealProperties()
      72             : {
      73           4 :     m_nPropertyCount = 0;
      74           4 :     CPLFree(m_papoProperty);
      75           4 :     m_papoProperty = nullptr;
      76           4 :     m_oMapPropertyNameToIndex.clear();
      77           4 :     m_oMapPropertySrcElementToIndex.clear();
      78           4 : }
      79             : 
      80             : /************************************************************************/
      81             : /*                       StealGeometryProperties()                      */
      82             : /************************************************************************/
      83             : 
      84           2 : void GMLFeatureClass::StealGeometryProperties()
      85             : {
      86           2 :     m_nGeometryPropertyCount = 0;
      87           2 :     CPLFree(m_papoGeometryProperty);
      88           2 :     m_papoGeometryProperty = nullptr;
      89           2 : }
      90             : 
      91             : /************************************************************************/
      92             : /*                            SetName()                                 */
      93             : /************************************************************************/
      94             : 
      95           3 : void GMLFeatureClass::SetName(const char *pszNewName)
      96             : {
      97           3 :     CPLFree(m_pszName);
      98           3 :     m_pszName = CPLStrdup(pszNewName);
      99           3 : }
     100             : 
     101             : /************************************************************************/
     102             : /*                           GetProperty(int)                           */
     103             : /************************************************************************/
     104             : 
     105       33444 : GMLPropertyDefn *GMLFeatureClass::GetProperty(int iIndex) const
     106             : 
     107             : {
     108       33444 :     if (iIndex < 0 || iIndex >= m_nPropertyCount)
     109        3479 :         return nullptr;
     110             : 
     111       29965 :     return m_papoProperty[iIndex];
     112             : }
     113             : 
     114             : /************************************************************************/
     115             : /*                          GetPropertyIndex()                          */
     116             : /************************************************************************/
     117             : 
     118        3632 : int GMLFeatureClass::GetPropertyIndex(const char *pszName) const
     119             : 
     120             : {
     121        3632 :     auto oIter = m_oMapPropertyNameToIndex.find(CPLString(pszName).toupper());
     122        3632 :     if (oIter != m_oMapPropertyNameToIndex.end())
     123          42 :         return oIter->second;
     124             : 
     125        3590 :     return -1;
     126             : }
     127             : 
     128             : /************************************************************************/
     129             : /*                        GetPropertyIndexBySrcElement()                */
     130             : /************************************************************************/
     131             : 
     132        5617 : int GMLFeatureClass::GetPropertyIndexBySrcElement(const char *pszElement,
     133             :                                                   int nLen) const
     134             : 
     135             : {
     136             :     auto oIter =
     137        5617 :         m_oMapPropertySrcElementToIndex.find(CPLString(pszElement, nLen));
     138        5617 :     if (oIter != m_oMapPropertySrcElementToIndex.end())
     139        2989 :         return oIter->second;
     140             : 
     141        2628 :     return -1;
     142             : }
     143             : 
     144             : /************************************************************************/
     145             : /*                            AddProperty()                             */
     146             : /************************************************************************/
     147             : 
     148        3013 : int GMLFeatureClass::AddProperty(GMLPropertyDefn *poDefn, int iPos)
     149             : 
     150             : {
     151        3013 :     if (GetProperty(poDefn->GetName()) != nullptr)
     152             :     {
     153           2 :         CPLError(CE_Warning, CPLE_AppDefined,
     154             :                  "Field with same name (%s) already exists in (%s). "
     155             :                  "Skipping newer ones",
     156             :                  poDefn->GetName(), m_pszName);
     157           2 :         return -1;
     158             :     }
     159             : 
     160        3011 :     m_nPropertyCount++;
     161        3011 :     m_papoProperty = static_cast<GMLPropertyDefn **>(
     162        3011 :         CPLRealloc(m_papoProperty, sizeof(void *) * m_nPropertyCount));
     163             : 
     164        3011 :     if (iPos < 0)
     165             :     {
     166        3008 :         iPos = m_nPropertyCount - 1;
     167             :     }
     168           3 :     else if (iPos < m_nPropertyCount - 1)
     169             :     {
     170           3 :         memmove(m_papoProperty + iPos + 1, m_papoProperty + iPos,
     171           3 :                 (m_nPropertyCount - 1 - iPos) * sizeof(GMLPropertyDefn *));
     172          12 :         for (auto &iter : m_oMapPropertyNameToIndex)
     173             :         {
     174           9 :             if (iter.second >= iPos)
     175           6 :                 iter.second++;
     176             :         }
     177          12 :         for (auto &iter : m_oMapPropertySrcElementToIndex)
     178             :         {
     179           9 :             if (iter.second >= iPos)
     180           6 :                 iter.second++;
     181             :         }
     182             :     }
     183             : 
     184        3011 :     m_papoProperty[iPos] = poDefn;
     185        3011 :     m_oMapPropertyNameToIndex[CPLString(poDefn->GetName()).toupper()] = iPos;
     186        3011 :     if (m_oMapPropertySrcElementToIndex.find(poDefn->GetSrcElement()) ==
     187        6022 :         m_oMapPropertySrcElementToIndex.end())
     188             :     {
     189        3009 :         m_oMapPropertySrcElementToIndex[poDefn->GetSrcElement()] = iPos;
     190             :     }
     191             : 
     192        3011 :     return iPos;
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                         GetGeometryProperty(int)                      */
     197             : /************************************************************************/
     198             : 
     199        3005 : GMLGeometryPropertyDefn *GMLFeatureClass::GetGeometryProperty(int iIndex) const
     200             : {
     201        3005 :     if (iIndex < 0 || iIndex >= m_nGeometryPropertyCount)
     202           0 :         return nullptr;
     203             : 
     204        3005 :     return m_papoGeometryProperty[iIndex];
     205             : }
     206             : 
     207             : /************************************************************************/
     208             : /*                   GetGeometryPropertyIndexBySrcElement()             */
     209             : /************************************************************************/
     210             : 
     211        2185 : int GMLFeatureClass::GetGeometryPropertyIndexBySrcElement(
     212             :     const char *pszElement) const
     213             : 
     214             : {
     215        2460 :     for (int i = 0; i < m_nGeometryPropertyCount; i++)
     216        1426 :         if (strcmp(pszElement, m_papoGeometryProperty[i]->GetSrcElement()) == 0)
     217        1151 :             return i;
     218             : 
     219        1034 :     return -1;
     220             : }
     221             : 
     222             : /************************************************************************/
     223             : /*                         AddGeometryProperty()                        */
     224             : /************************************************************************/
     225             : 
     226         904 : int GMLFeatureClass::AddGeometryProperty(GMLGeometryPropertyDefn *poDefn)
     227             : 
     228             : {
     229         904 :     if (GetGeometryPropertyIndexBySrcElement(poDefn->GetSrcElement()) >= 0)
     230             :     {
     231           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     232             :                  "Geometry field with same name (%s) already exists in (%s). "
     233             :                  "Skipping newer ones",
     234             :                  poDefn->GetSrcElement(), m_pszName);
     235           0 :         return -1;
     236             :     }
     237             : 
     238         904 :     m_nGeometryPropertyCount++;
     239        1808 :     m_papoGeometryProperty = static_cast<GMLGeometryPropertyDefn **>(CPLRealloc(
     240         904 :         m_papoGeometryProperty, sizeof(void *) * m_nGeometryPropertyCount));
     241             : 
     242         904 :     m_papoGeometryProperty[m_nGeometryPropertyCount - 1] = poDefn;
     243             : 
     244         904 :     return m_nGeometryPropertyCount - 1;
     245             : }
     246             : 
     247             : /************************************************************************/
     248             : /*                       ClearGeometryProperties()                      */
     249             : /************************************************************************/
     250             : 
     251         876 : void GMLFeatureClass::ClearGeometryProperties()
     252             : {
     253        1776 :     for (int i = 0; i < m_nGeometryPropertyCount; i++)
     254         900 :         delete m_papoGeometryProperty[i];
     255         876 :     CPLFree(m_papoGeometryProperty);
     256         876 :     m_nGeometryPropertyCount = 0;
     257         876 :     m_papoGeometryProperty = nullptr;
     258         876 : }
     259             : 
     260             : /************************************************************************/
     261             : /*                         HasFeatureProperties()                       */
     262             : /************************************************************************/
     263             : 
     264        1056 : bool GMLFeatureClass::HasFeatureProperties()
     265             : {
     266        3979 :     for (int i = 0; i < m_nPropertyCount; i++)
     267             :     {
     268        5860 :         if (m_papoProperty[i]->GetType() == GMLPT_FeatureProperty ||
     269        2928 :             m_papoProperty[i]->GetType() == GMLPT_FeaturePropertyList)
     270           9 :             return true;
     271             :     }
     272        1047 :     return false;
     273             : }
     274             : 
     275             : /************************************************************************/
     276             : /*                           SetElementName()                           */
     277             : /************************************************************************/
     278             : 
     279         152 : void GMLFeatureClass::SetElementName(const char *pszElementName)
     280             : 
     281             : {
     282         152 :     CPLFree(m_pszElementName);
     283         152 :     m_pszElementName = CPLStrdup(pszElementName);
     284         152 :     n_nElementNameLen = static_cast<int>(strlen(pszElementName));
     285         152 : }
     286             : 
     287             : /************************************************************************/
     288             : /*                           GetElementName()                           */
     289             : /************************************************************************/
     290             : 
     291        7140 : const char *GMLFeatureClass::GetElementName() const
     292             : 
     293             : {
     294        7140 :     if (m_pszElementName == nullptr)
     295        5304 :         return m_pszName;
     296             : 
     297        1836 :     return m_pszElementName;
     298             : }
     299             : 
     300             : /************************************************************************/
     301             : /*                           GetElementName()                           */
     302             : /************************************************************************/
     303             : 
     304       26421 : size_t GMLFeatureClass::GetElementNameLen() const
     305             : 
     306             : {
     307       26421 :     if (m_pszElementName == nullptr)
     308       11312 :         return n_nNameLen;
     309             : 
     310       15109 :     return n_nElementNameLen;
     311             : }
     312             : 
     313             : /************************************************************************/
     314             : /*                         GetFeatureCount()                          */
     315             : /************************************************************************/
     316             : 
     317        1590 : GIntBig GMLFeatureClass::GetFeatureCount()
     318             : {
     319        1590 :     return m_nFeatureCount;
     320             : }
     321             : 
     322             : /************************************************************************/
     323             : /*                          SetFeatureCount()                           */
     324             : /************************************************************************/
     325             : 
     326         744 : void GMLFeatureClass::SetFeatureCount(GIntBig nNewCount)
     327             : 
     328             : {
     329         744 :     m_nFeatureCount = nNewCount;
     330         744 : }
     331             : 
     332             : /************************************************************************/
     333             : /*                            GetExtraInfo()                            */
     334             : /************************************************************************/
     335             : 
     336           0 : const char *GMLFeatureClass::GetExtraInfo()
     337             : {
     338           0 :     return m_pszExtraInfo;
     339             : }
     340             : 
     341             : /************************************************************************/
     342             : /*                            SetExtraInfo()                            */
     343             : /************************************************************************/
     344             : 
     345           0 : void GMLFeatureClass::SetExtraInfo(const char *pszExtraInfo)
     346             : 
     347             : {
     348           0 :     CPLFree(m_pszExtraInfo);
     349           0 :     m_pszExtraInfo = nullptr;
     350             : 
     351           0 :     if (pszExtraInfo != nullptr)
     352           0 :         m_pszExtraInfo = CPLStrdup(pszExtraInfo);
     353           0 : }
     354             : 
     355             : /************************************************************************/
     356             : /*                             SetExtents()                             */
     357             : /************************************************************************/
     358             : 
     359         580 : void GMLFeatureClass::SetExtents(double dfXMin, double dfXMax, double dfYMin,
     360             :                                  double dfYMax)
     361             : 
     362             : {
     363         580 :     m_dfXMin = dfXMin;
     364         580 :     m_dfXMax = dfXMax;
     365         580 :     m_dfYMin = dfYMin;
     366         580 :     m_dfYMax = dfYMax;
     367             : 
     368         580 :     m_bHaveExtents = true;
     369         580 : }
     370             : 
     371             : /************************************************************************/
     372             : /*                             GetExtents()                             */
     373             : /************************************************************************/
     374             : 
     375         509 : bool GMLFeatureClass::GetExtents(double *pdfXMin, double *pdfXMax,
     376             :                                  double *pdfYMin, double *pdfYMax)
     377             : 
     378             : {
     379         509 :     if (m_bHaveExtents)
     380             :     {
     381         396 :         *pdfXMin = m_dfXMin;
     382         396 :         *pdfXMax = m_dfXMax;
     383         396 :         *pdfYMin = m_dfYMin;
     384         396 :         *pdfYMax = m_dfYMax;
     385             :     }
     386             : 
     387         509 :     return m_bHaveExtents;
     388             : }
     389             : 
     390             : /************************************************************************/
     391             : /*                            SetSRSName()                              */
     392             : /************************************************************************/
     393             : 
     394         149 : void GMLFeatureClass::SetSRSName(const char *pszSRSName)
     395             : 
     396             : {
     397         149 :     m_bSRSNameConsistent = true;
     398         149 :     CPLFree(m_pszSRSName);
     399         149 :     m_pszSRSName = pszSRSName ? CPLStrdup(pszSRSName) : nullptr;
     400         149 : }
     401             : 
     402             : /************************************************************************/
     403             : /*                           MergeSRSName()                             */
     404             : /************************************************************************/
     405             : 
     406         229 : void GMLFeatureClass::MergeSRSName(const char *pszSRSName)
     407             : 
     408             : {
     409         229 :     if (!m_bSRSNameConsistent)
     410           0 :         return;
     411             : 
     412         229 :     if (m_pszSRSName == nullptr)
     413             :     {
     414         125 :         if (pszSRSName)
     415          33 :             m_pszSRSName = CPLStrdup(pszSRSName);
     416             :     }
     417             :     else
     418             :     {
     419         104 :         m_bSRSNameConsistent =
     420         104 :             pszSRSName != nullptr && strcmp(m_pszSRSName, pszSRSName) == 0;
     421         104 :         if (!m_bSRSNameConsistent)
     422             :         {
     423           1 :             CPLFree(m_pszSRSName);
     424           1 :             m_pszSRSName = nullptr;
     425             :         }
     426             :     }
     427             : }
     428             : 
     429             : /************************************************************************/
     430             : /*                         InitializeFromXML()                          */
     431             : /************************************************************************/
     432             : 
     433         103 : bool GMLFeatureClass::InitializeFromXML(CPLXMLNode *psRoot)
     434             : 
     435             : {
     436             :     // Do some rudimentary checking that this is a well formed node.
     437         103 :     if (psRoot == nullptr || psRoot->eType != CXT_Element ||
     438         103 :         !EQUAL(psRoot->pszValue, "GMLFeatureClass"))
     439             :     {
     440           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     441             :                  "GMLFeatureClass::InitializeFromXML() called on %s node!",
     442             :                  psRoot ? psRoot->pszValue : "(null)");
     443           0 :         return false;
     444             :     }
     445             : 
     446         103 :     if (CPLGetXMLValue(psRoot, "Name", nullptr) == nullptr)
     447             :     {
     448           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     449             :                  "GMLFeatureClass has no <Name> element.");
     450           0 :         return false;
     451             :     }
     452             : 
     453             :     // Collect base info.
     454         103 :     CPLFree(m_pszName);
     455         103 :     m_pszName = CPLStrdup(CPLGetXMLValue(psRoot, "Name", nullptr));
     456         103 :     n_nNameLen = static_cast<int>(strlen(m_pszName));
     457             : 
     458         103 :     SetElementName(CPLGetXMLValue(psRoot, "ElementPath", m_pszName));
     459             : 
     460             :     // Collect geometry properties.
     461         103 :     bool bHasValidGeometryName = false;
     462         103 :     bool bHasValidGeometryElementPath = false;
     463         103 :     bool bHasFoundGeomType = false;
     464         103 :     bool bHasFoundGeomElements = false;
     465         103 :     const char *pszGName = "";
     466         103 :     const char *pszGPath = "";
     467         103 :     OGRwkbGeometryType nGeomType = wkbUnknown;
     468             : 
     469         131 :     const auto FlattenGeomTypeFromInt = [](int eType)
     470             :     {
     471         131 :         eType = eType & (~wkb25DBitInternalUse);
     472         131 :         if (eType >= 1000 && eType < 2000)  // ISO Z.
     473           0 :             return eType - 1000;
     474         131 :         if (eType >= 2000 && eType < 3000)  // ISO M.
     475           0 :             return eType - 2000;
     476         131 :         if (eType >= 3000 && eType < 4000)  // ISO ZM.
     477           0 :             return eType - 3000;
     478         131 :         return eType;
     479             :     };
     480             : 
     481         103 :     CPLXMLNode *psThis = nullptr;
     482        1637 :     for (psThis = psRoot->psChild; psThis != nullptr; psThis = psThis->psNext)
     483             :     {
     484        1546 :         if (psThis->eType == CXT_Element &&
     485        1120 :             EQUAL(psThis->pszValue, "GeomPropertyDefn"))
     486             :         {
     487          79 :             const char *pszName = CPLGetXMLValue(psThis, "Name", "");
     488             :             const char *pszElementPath =
     489          79 :                 CPLGetXMLValue(psThis, "ElementPath", "");
     490          79 :             const char *pszType = CPLGetXMLValue(psThis, "Type", nullptr);
     491             :             const bool bNullable =
     492          79 :                 CPLTestBool(CPLGetXMLValue(psThis, "Nullable", "true"));
     493          79 :             nGeomType = wkbUnknown;
     494          79 :             if (pszType != nullptr && !EQUAL(pszType, "0"))
     495             :             {
     496          77 :                 int nGeomTypeInt = atoi(pszType);
     497             :                 const int nFlattenGeomTypeInt =
     498          77 :                     FlattenGeomTypeFromInt(nGeomTypeInt);
     499          77 :                 if (nGeomTypeInt != 0 &&
     500           6 :                     !(nFlattenGeomTypeInt >= static_cast<int>(wkbPoint) &&
     501             :                       nFlattenGeomTypeInt <= static_cast<int>(wkbTIN)))
     502             :                 {
     503           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     504             :                              "Unrecognized geometry type : %s", pszType);
     505             :                 }
     506          77 :                 else if (nGeomTypeInt == 0)
     507             :                 {
     508          71 :                     nGeomType = OGRFromOGCGeomType(pszType);
     509             :                 }
     510             :                 else
     511             :                 {
     512           6 :                     nGeomType = static_cast<OGRwkbGeometryType>(nGeomTypeInt);
     513             :                 }
     514             :             }
     515          79 :             bHasFoundGeomElements = true;
     516             :             auto poDefn = new GMLGeometryPropertyDefn(pszName, pszElementPath,
     517          79 :                                                       nGeomType, -1, bNullable);
     518          79 :             if (AddGeometryProperty(poDefn) < 0)
     519           0 :                 delete poDefn;
     520          79 :             bHasValidGeometryName = false;
     521          79 :             bHasValidGeometryElementPath = false;
     522          79 :             bHasFoundGeomType = false;
     523             :         }
     524        1467 :         else if (psThis->eType == CXT_Element &&
     525        1041 :                  strcmp(psThis->pszValue, "GeometryName") == 0)
     526             :         {
     527          37 :             bHasFoundGeomElements = true;
     528             : 
     529          37 :             if (bHasValidGeometryName)
     530             :             {
     531             :                 auto poDefn = new GMLGeometryPropertyDefn(pszGName, pszGPath,
     532           0 :                                                           nGeomType, -1, true);
     533           0 :                 if (AddGeometryProperty(poDefn) < 0)
     534           0 :                     delete poDefn;
     535             :                 // bHasValidGeometryName = false;
     536           0 :                 bHasValidGeometryElementPath = false;
     537           0 :                 bHasFoundGeomType = false;
     538           0 :                 pszGPath = "";
     539           0 :                 nGeomType = wkbUnknown;
     540             :             }
     541          37 :             pszGName = CPLGetXMLValue(psThis, nullptr, "");
     542          37 :             bHasValidGeometryName = true;
     543             :         }
     544        1430 :         else if (psThis->eType == CXT_Element &&
     545        1004 :                  strcmp(psThis->pszValue, "GeometryElementPath") == 0)
     546             :         {
     547          43 :             bHasFoundGeomElements = true;
     548             : 
     549          43 :             if (bHasValidGeometryElementPath)
     550             :             {
     551             :                 auto poDefn = new GMLGeometryPropertyDefn(pszGName, pszGPath,
     552           0 :                                                           nGeomType, -1, true);
     553           0 :                 if (AddGeometryProperty(poDefn) < 0)
     554           0 :                     delete poDefn;
     555           0 :                 bHasValidGeometryName = false;
     556             :                 // bHasValidGeometryElementPath = false;
     557           0 :                 bHasFoundGeomType = false;
     558           0 :                 pszGName = "";
     559           0 :                 nGeomType = wkbUnknown;
     560             :             }
     561          43 :             pszGPath = CPLGetXMLValue(psThis, nullptr, "");
     562          43 :             bHasValidGeometryElementPath = true;
     563             :         }
     564        1387 :         else if (psThis->eType == CXT_Element &&
     565         961 :                  strcmp(psThis->pszValue, "GeometryType") == 0)
     566             :         {
     567          54 :             bHasFoundGeomElements = true;
     568             : 
     569          54 :             if (bHasFoundGeomType)
     570             :             {
     571             :                 auto poDefn = new GMLGeometryPropertyDefn(pszGName, pszGPath,
     572           0 :                                                           nGeomType, -1, true);
     573           0 :                 if (AddGeometryProperty(poDefn) < 0)
     574           0 :                     delete poDefn;
     575           0 :                 bHasValidGeometryName = false;
     576           0 :                 bHasValidGeometryElementPath = false;
     577             :                 // bHasFoundGeomType = false;
     578           0 :                 pszGName = "";
     579           0 :                 pszGPath = "";
     580             :             }
     581             :             const char *pszGeometryType =
     582          54 :                 CPLGetXMLValue(psThis, nullptr, nullptr);
     583          54 :             nGeomType = wkbUnknown;
     584          54 :             if (pszGeometryType != nullptr && !EQUAL(pszGeometryType, "0"))
     585             :             {
     586          54 :                 const int nGeomTypeInt = atoi(pszGeometryType);
     587             :                 const int nFlattenGeomTypeInt =
     588          54 :                     FlattenGeomTypeFromInt(nGeomTypeInt);
     589          54 :                 if (nGeomTypeInt == 100 || EQUAL(pszGeometryType, "NONE"))
     590             :                 {
     591          12 :                     bHasValidGeometryElementPath = false;
     592          12 :                     bHasFoundGeomType = false;
     593          12 :                     break;
     594             :                 }
     595          42 :                 else if (nGeomTypeInt != 0 &&
     596          38 :                          !(nFlattenGeomTypeInt >= static_cast<int>(wkbPoint) &&
     597             :                            nFlattenGeomTypeInt <= static_cast<int>(wkbTIN)))
     598             :                 {
     599           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     600             :                              "Unrecognized geometry type : %s",
     601             :                              pszGeometryType);
     602             :                 }
     603          42 :                 else if (nGeomTypeInt == 0)
     604             :                 {
     605           4 :                     nGeomType = OGRFromOGCGeomType(pszGeometryType);
     606             :                 }
     607             :                 else
     608             :                 {
     609          38 :                     nGeomType = static_cast<OGRwkbGeometryType>(nGeomTypeInt);
     610             :                 }
     611             :             }
     612          42 :             bHasFoundGeomType = true;
     613             :         }
     614             :     }
     615             : 
     616             :     // If there was a dangling <GeometryElementPath> or <GeometryType> or
     617             :     // that no explicit geometry information has been found, then add
     618             :     // a geometry field.
     619         103 :     if (bHasValidGeometryElementPath || bHasFoundGeomType ||
     620          58 :         !bHasFoundGeomElements)
     621             :     {
     622             :         auto poDefn = new GMLGeometryPropertyDefn(pszGName, pszGPath, nGeomType,
     623          57 :                                                   -1, true);
     624          57 :         if (AddGeometryProperty(poDefn) < 0)
     625           0 :             delete poDefn;
     626             :     }
     627             : 
     628         103 :     SetSRSName(CPLGetXMLValue(psRoot, "SRSName", nullptr));
     629             : 
     630             :     // Collect dataset specific info.
     631         103 :     CPLXMLNode *psDSI = CPLGetXMLNode(psRoot, "DatasetSpecificInfo");
     632         103 :     if (psDSI != nullptr)
     633             :     {
     634          56 :         const char *pszValue = CPLGetXMLValue(psDSI, "FeatureCount", nullptr);
     635          56 :         if (pszValue != nullptr)
     636          56 :             SetFeatureCount(CPLAtoGIntBig(pszValue));
     637             : 
     638             :         // Eventually we should support XML subtrees.
     639          56 :         pszValue = CPLGetXMLValue(psDSI, "ExtraInfo", nullptr);
     640          56 :         if (pszValue != nullptr)
     641           0 :             SetExtraInfo(pszValue);
     642             : 
     643          56 :         if (CPLGetXMLValue(psDSI, "ExtentXMin", nullptr) != nullptr &&
     644          50 :             CPLGetXMLValue(psDSI, "ExtentXMax", nullptr) != nullptr &&
     645         156 :             CPLGetXMLValue(psDSI, "ExtentYMin", nullptr) != nullptr &&
     646          50 :             CPLGetXMLValue(psDSI, "ExtentYMax", nullptr) != nullptr)
     647             :         {
     648          50 :             SetExtents(CPLAtof(CPLGetXMLValue(psDSI, "ExtentXMin", "0.0")),
     649             :                        CPLAtof(CPLGetXMLValue(psDSI, "ExtentXMax", "0.0")),
     650             :                        CPLAtof(CPLGetXMLValue(psDSI, "ExtentYMin", "0.0")),
     651             :                        CPLAtof(CPLGetXMLValue(psDSI, "ExtentYMax", "0.0")));
     652             :         }
     653             :     }
     654             : 
     655             :     // Collect property definitions.
     656        1697 :     for (psThis = psRoot->psChild; psThis != nullptr; psThis = psThis->psNext)
     657             :     {
     658        1594 :         if (psThis->eType == CXT_Element &&
     659        1168 :             EQUAL(psThis->pszValue, "PropertyDefn"))
     660             :         {
     661         643 :             const char *pszName = CPLGetXMLValue(psThis, "Name", nullptr);
     662         643 :             const char *pszType = CPLGetXMLValue(psThis, "Type", "Untyped");
     663         643 :             const char *pszSubType = CPLGetXMLValue(psThis, "Subtype", "");
     664             :             const char *pszCondition =
     665         643 :                 CPLGetXMLValue(psThis, "Condition", nullptr);
     666             :             const bool bNullable =
     667         643 :                 CPLTestBool(CPLGetXMLValue(psThis, "Nullable", "true"));
     668             :             const bool bUnique =
     669         643 :                 CPLTestBool(CPLGetXMLValue(psThis, "Unique", "false"));
     670         643 :             const char *pszComment = CPLGetXMLValue(psThis, "Comment", nullptr);
     671             : 
     672         643 :             if (pszName == nullptr)
     673             :             {
     674           0 :                 CPLError(
     675             :                     CE_Failure, CPLE_AppDefined,
     676             :                     "GMLFeatureClass %s has a PropertyDefn without a <Name>.",
     677             :                     m_pszName);
     678           0 :                 return false;
     679             :             }
     680             : 
     681             :             GMLPropertyDefn *poPDefn = new GMLPropertyDefn(
     682         643 :                 pszName, CPLGetXMLValue(psThis, "ElementPath", nullptr));
     683             : 
     684         643 :             poPDefn->SetNullable(bNullable);
     685         643 :             poPDefn->SetUnique(bUnique);
     686         643 :             if (EQUAL(pszType, "Untyped"))
     687             :             {
     688           0 :                 poPDefn->SetType(GMLPT_Untyped);
     689             :             }
     690         643 :             else if (EQUAL(pszType, "String"))
     691             :             {
     692         352 :                 if (EQUAL(pszSubType, "Boolean"))
     693             :                 {
     694           4 :                     poPDefn->SetType(GMLPT_Boolean);
     695           4 :                     poPDefn->SetWidth(1);
     696             :                 }
     697         348 :                 else if (EQUAL(pszSubType, "Date"))
     698             :                 {
     699           0 :                     poPDefn->SetType(GMLPT_Date);
     700             :                 }
     701         348 :                 else if (EQUAL(pszSubType, "Time"))
     702             :                 {
     703           0 :                     poPDefn->SetType(GMLPT_Time);
     704             :                 }
     705         348 :                 else if (EQUAL(pszSubType, "Datetime"))
     706             :                 {
     707           0 :                     poPDefn->SetType(GMLPT_DateTime);
     708             :                 }
     709             :                 else
     710             :                 {
     711         348 :                     poPDefn->SetType(GMLPT_String);
     712         348 :                     poPDefn->SetWidth(
     713             :                         atoi(CPLGetXMLValue(psThis, "Width", "0")));
     714             :                 }
     715             :             }
     716         291 :             else if (EQUAL(pszType, "Integer"))
     717             :             {
     718         191 :                 if (EQUAL(pszSubType, "Short"))
     719             :                 {
     720           0 :                     poPDefn->SetType(GMLPT_Short);
     721             :                 }
     722         191 :                 else if (EQUAL(pszSubType, "Integer64"))
     723             :                 {
     724          60 :                     poPDefn->SetType(GMLPT_Integer64);
     725             :                 }
     726             :                 else
     727             :                 {
     728         131 :                     poPDefn->SetType(GMLPT_Integer);
     729             :                 }
     730         191 :                 poPDefn->SetWidth(atoi(CPLGetXMLValue(psThis, "Width", "0")));
     731             :             }
     732         100 :             else if (EQUAL(pszType, "Real"))
     733             :             {
     734          11 :                 if (EQUAL(pszSubType, "Float"))
     735             :                 {
     736           0 :                     poPDefn->SetType(GMLPT_Float);
     737             :                 }
     738             :                 else
     739             :                 {
     740          11 :                     poPDefn->SetType(GMLPT_Real);
     741             :                 }
     742          11 :                 poPDefn->SetWidth(atoi(CPLGetXMLValue(psThis, "Width", "0")));
     743          11 :                 poPDefn->SetPrecision(
     744             :                     atoi(CPLGetXMLValue(psThis, "Precision", "0")));
     745             :             }
     746          89 :             else if (EQUAL(pszType, "StringList"))
     747             :             {
     748          33 :                 if (EQUAL(pszSubType, "Boolean"))
     749           1 :                     poPDefn->SetType(GMLPT_BooleanList);
     750             :                 else
     751          32 :                     poPDefn->SetType(GMLPT_StringList);
     752             :             }
     753          56 :             else if (EQUAL(pszType, "IntegerList"))
     754             :             {
     755          27 :                 if (EQUAL(pszSubType, "Integer64"))
     756           6 :                     poPDefn->SetType(GMLPT_Integer64List);
     757             :                 else
     758          21 :                     poPDefn->SetType(GMLPT_IntegerList);
     759             :             }
     760          29 :             else if (EQUAL(pszType, "RealList"))
     761             :             {
     762          11 :                 poPDefn->SetType(GMLPT_RealList);
     763             :             }
     764          18 :             else if (EQUAL(pszType, "Complex"))
     765             :             {
     766           8 :                 poPDefn->SetType(GMLPT_Complex);
     767             :             }
     768          10 :             else if (EQUAL(pszType, "FeatureProperty"))
     769             :             {
     770           2 :                 poPDefn->SetType(GMLPT_FeatureProperty);
     771             :             }
     772           8 :             else if (EQUAL(pszType, "FeaturePropertyList"))
     773             :             {
     774           8 :                 poPDefn->SetType(GMLPT_FeaturePropertyList);
     775             :             }
     776             :             else
     777             :             {
     778           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     779             :                          "Unrecognized property type (%s) in (%s).", pszType,
     780             :                          pszName);
     781           0 :                 delete poPDefn;
     782           0 :                 return false;
     783             :             }
     784         643 :             if (pszCondition != nullptr)
     785           4 :                 poPDefn->SetCondition(pszCondition);
     786         643 :             if (pszComment != nullptr)
     787           1 :                 poPDefn->SetDocumentation(pszComment);
     788             : 
     789         643 :             if (AddProperty(poPDefn) < 0)
     790           0 :                 delete poPDefn;
     791             :         }
     792             :     }
     793             : 
     794         103 :     return true;
     795             : }
     796             : 
     797             : /************************************************************************/
     798             : /*                           SerializeToXML()                           */
     799             : /************************************************************************/
     800             : 
     801         118 : CPLXMLNode *GMLFeatureClass::SerializeToXML()
     802             : 
     803             : {
     804             :     // Set feature class and core information.
     805             :     CPLXMLNode *psRoot =
     806         118 :         CPLCreateXMLNode(nullptr, CXT_Element, "GMLFeatureClass");
     807             : 
     808         118 :     CPLCreateXMLElementAndValue(psRoot, "Name", GetName());
     809         118 :     CPLCreateXMLElementAndValue(psRoot, "ElementPath", GetElementName());
     810             : 
     811         118 :     if (m_nGeometryPropertyCount > 1)
     812             :     {
     813           6 :         for (int i = 0; i < m_nGeometryPropertyCount; i++)
     814             :         {
     815           4 :             GMLGeometryPropertyDefn *poGeomFDefn = m_papoGeometryProperty[i];
     816             : 
     817             :             CPLXMLNode *psPDefnNode =
     818           4 :                 CPLCreateXMLNode(psRoot, CXT_Element, "GeomPropertyDefn");
     819           4 :             if (strlen(poGeomFDefn->GetName()) > 0)
     820           4 :                 CPLCreateXMLElementAndValue(psPDefnNode, "Name",
     821             :                                             poGeomFDefn->GetName());
     822           8 :             if (poGeomFDefn->GetSrcElement() != nullptr &&
     823           4 :                 strlen(poGeomFDefn->GetSrcElement()) > 0)
     824           4 :                 CPLCreateXMLElementAndValue(psPDefnNode, "ElementPath",
     825             :                                             poGeomFDefn->GetSrcElement());
     826             : 
     827           4 :             if (poGeomFDefn->GetType() != 0 /* wkbUnknown */)
     828             :             {
     829           0 :                 char szValue[128] = {};
     830             : 
     831             :                 const OGRwkbGeometryType eType =
     832           0 :                     static_cast<OGRwkbGeometryType>(poGeomFDefn->GetType());
     833             : 
     834           0 :                 CPLString osStr(OGRToOGCGeomType(eType));
     835           0 :                 if (wkbHasZ(eType))
     836           0 :                     osStr += "Z";
     837           0 :                 CPLCreateXMLNode(psPDefnNode, CXT_Comment, osStr.c_str());
     838             : 
     839           0 :                 snprintf(szValue, sizeof(szValue), "%d", eType);
     840           0 :                 CPLCreateXMLElementAndValue(psPDefnNode, "Type", szValue);
     841             :             }
     842             :         }
     843             :     }
     844         116 :     else if (m_nGeometryPropertyCount == 1)
     845             :     {
     846          96 :         GMLGeometryPropertyDefn *poGeomFDefn = m_papoGeometryProperty[0];
     847             : 
     848          96 :         if (strlen(poGeomFDefn->GetName()) > 0)
     849          71 :             CPLCreateXMLElementAndValue(psRoot, "GeometryName",
     850             :                                         poGeomFDefn->GetName());
     851             : 
     852         192 :         if (poGeomFDefn->GetSrcElement() != nullptr &&
     853          96 :             strlen(poGeomFDefn->GetSrcElement()) > 0)
     854          71 :             CPLCreateXMLElementAndValue(psRoot, "GeometryElementPath",
     855             :                                         poGeomFDefn->GetSrcElement());
     856             : 
     857          96 :         if (poGeomFDefn->GetType() != 0 /* wkbUnknown */)
     858             :         {
     859          87 :             char szValue[128] = {};
     860             : 
     861             :             OGRwkbGeometryType eType =
     862          87 :                 static_cast<OGRwkbGeometryType>(poGeomFDefn->GetType());
     863             : 
     864         174 :             CPLString osStr(OGRToOGCGeomType(eType));
     865          87 :             if (wkbHasZ(eType))
     866           7 :                 osStr += "Z";
     867          87 :             CPLCreateXMLNode(psRoot, CXT_Comment, osStr.c_str());
     868             : 
     869          87 :             snprintf(szValue, sizeof(szValue), "%d", eType);
     870          87 :             CPLCreateXMLElementAndValue(psRoot, "GeometryType", szValue);
     871             :         }
     872             :     }
     873             :     else
     874             :     {
     875          20 :         CPLCreateXMLElementAndValue(psRoot, "GeometryType", "100");
     876             :     }
     877             : 
     878         118 :     const char *pszSRSName = GetSRSName();
     879         118 :     if (pszSRSName)
     880             :     {
     881          57 :         CPLCreateXMLElementAndValue(psRoot, "SRSName", pszSRSName);
     882             :     }
     883             : 
     884             :     // Write out dataset specific information.
     885         118 :     if (m_bHaveExtents || m_nFeatureCount != -1 || m_pszExtraInfo != nullptr)
     886             :     {
     887             :         CPLXMLNode *psDSI =
     888         117 :             CPLCreateXMLNode(psRoot, CXT_Element, "DatasetSpecificInfo");
     889             : 
     890         117 :         if (m_nFeatureCount != -1)
     891             :         {
     892         117 :             char szValue[128] = {};
     893             : 
     894         117 :             snprintf(szValue, sizeof(szValue), CPL_FRMT_GIB, m_nFeatureCount);
     895         117 :             CPLCreateXMLElementAndValue(psDSI, "FeatureCount", szValue);
     896             :         }
     897             : 
     898         117 :         if (m_bHaveExtents && fabs(m_dfXMin) < 1e100 &&
     899          95 :             fabs(m_dfXMax) < 1e100 && fabs(m_dfYMin) < 1e100 &&
     900          95 :             fabs(m_dfYMax) < 1e100)
     901             :         {
     902          95 :             char szValue[128] = {};
     903             : 
     904          95 :             CPLsnprintf(szValue, sizeof(szValue), "%.5f", m_dfXMin);
     905          95 :             CPLCreateXMLElementAndValue(psDSI, "ExtentXMin", szValue);
     906             : 
     907          95 :             CPLsnprintf(szValue, sizeof(szValue), "%.5f", m_dfXMax);
     908          95 :             CPLCreateXMLElementAndValue(psDSI, "ExtentXMax", szValue);
     909             : 
     910          95 :             CPLsnprintf(szValue, sizeof(szValue), "%.5f", m_dfYMin);
     911          95 :             CPLCreateXMLElementAndValue(psDSI, "ExtentYMin", szValue);
     912             : 
     913          95 :             CPLsnprintf(szValue, sizeof(szValue), "%.5f", m_dfYMax);
     914          95 :             CPLCreateXMLElementAndValue(psDSI, "ExtentYMax", szValue);
     915             :         }
     916             : 
     917         117 :         if (m_pszExtraInfo)
     918           0 :             CPLCreateXMLElementAndValue(psDSI, "ExtraInfo", m_pszExtraInfo);
     919             :     }
     920             : 
     921         118 :     CPLXMLNode *psLastChild = psRoot->psChild;
     922         750 :     while (psLastChild->psNext)
     923             :     {
     924         632 :         psLastChild = psLastChild->psNext;
     925             :     }
     926             : 
     927             :     // Emit property information.
     928         591 :     for (int iProperty = 0; iProperty < GetPropertyCount(); iProperty++)
     929             :     {
     930         473 :         GMLPropertyDefn *poPDefn = GetProperty(iProperty);
     931         473 :         const char *pszTypeName = "Unknown";
     932         473 :         CPL_IGNORE_RET_VAL(pszTypeName);  // Make CSA happy
     933             : 
     934             :         CPLXMLNode *psPDefnNode =
     935         473 :             CPLCreateXMLNode(nullptr, CXT_Element, "PropertyDefn");
     936         473 :         psLastChild->psNext = psPDefnNode;
     937         473 :         psLastChild = psPDefnNode;
     938         473 :         CPLCreateXMLElementAndValue(psPDefnNode, "Name", poPDefn->GetName());
     939         473 :         CPLCreateXMLElementAndValue(psPDefnNode, "ElementPath",
     940             :                                     poPDefn->GetSrcElement());
     941         473 :         const auto gmlType = poPDefn->GetType();
     942         473 :         const char *pszSubTypeName = nullptr;
     943         473 :         switch (gmlType)
     944             :         {
     945          10 :             case GMLPT_Untyped:
     946          10 :                 pszTypeName = "Untyped";
     947          10 :                 break;
     948             : 
     949         282 :             case GMLPT_String:
     950         282 :                 pszTypeName = "String";
     951         282 :                 break;
     952             : 
     953          10 :             case GMLPT_Boolean:
     954          10 :                 pszTypeName = "String";
     955          10 :                 pszSubTypeName = "Boolean";
     956          10 :                 break;
     957             : 
     958           0 :             case GMLPT_Date:
     959           0 :                 pszTypeName = "String";
     960           0 :                 pszSubTypeName = "Date";
     961           0 :                 break;
     962             : 
     963           0 :             case GMLPT_Time:
     964           0 :                 pszTypeName = "String";
     965           0 :                 pszSubTypeName = "Time";
     966           0 :                 break;
     967             : 
     968           0 :             case GMLPT_DateTime:
     969           0 :                 pszTypeName = "String";
     970           0 :                 pszSubTypeName = "DateTime";
     971           0 :                 break;
     972             : 
     973          90 :             case GMLPT_Integer:
     974          90 :                 pszTypeName = "Integer";
     975          90 :                 break;
     976             : 
     977           0 :             case GMLPT_Short:
     978           0 :                 pszTypeName = "Integer";
     979           0 :                 pszSubTypeName = "Short";
     980           0 :                 break;
     981             : 
     982           1 :             case GMLPT_Integer64:
     983           1 :                 pszTypeName = "Integer";
     984           1 :                 pszSubTypeName = "Integer64";
     985           1 :                 break;
     986             : 
     987          35 :             case GMLPT_Real:
     988          35 :                 pszTypeName = "Real";
     989          35 :                 break;
     990             : 
     991           0 :             case GMLPT_Float:
     992           0 :                 pszTypeName = "Real";
     993           0 :                 pszSubTypeName = "Float";
     994           0 :                 break;
     995             : 
     996           0 :             case GMLPT_Complex:
     997           0 :                 pszTypeName = "Complex";
     998           0 :                 break;
     999             : 
    1000           2 :             case GMLPT_IntegerList:
    1001           2 :                 pszTypeName = "IntegerList";
    1002           2 :                 break;
    1003             : 
    1004           1 :             case GMLPT_Integer64List:
    1005           1 :                 pszTypeName = "IntegerList";
    1006           1 :                 pszSubTypeName = "Integer64";
    1007           1 :                 break;
    1008             : 
    1009           2 :             case GMLPT_RealList:
    1010           2 :                 pszTypeName = "RealList";
    1011           2 :                 break;
    1012             : 
    1013          39 :             case GMLPT_StringList:
    1014          39 :                 pszTypeName = "StringList";
    1015          39 :                 break;
    1016             : 
    1017           1 :             case GMLPT_BooleanList:
    1018           1 :                 pszTypeName = "StringList";
    1019           1 :                 pszSubTypeName = "Boolean";
    1020           1 :                 break;
    1021             : 
    1022             :             // Should not happen in practice for now because this is not
    1023             :             // autodetected.
    1024           0 :             case GMLPT_FeatureProperty:
    1025           0 :                 pszTypeName = "FeatureProperty";
    1026           0 :                 break;
    1027             : 
    1028             :             // Should not happen in practice for now because this is not
    1029             :             // autodetected.
    1030           0 :             case GMLPT_FeaturePropertyList:
    1031           0 :                 pszTypeName = "FeaturePropertyList";
    1032           0 :                 break;
    1033             :         }
    1034         473 :         CPLCreateXMLElementAndValue(psPDefnNode, "Type", pszTypeName);
    1035         473 :         if (pszSubTypeName)
    1036          13 :             CPLCreateXMLElementAndValue(psPDefnNode, "Subtype", pszSubTypeName);
    1037             : 
    1038         473 :         if (EQUAL(pszTypeName, "String"))
    1039             :         {
    1040         292 :             char szMaxLength[48] = {};
    1041         292 :             snprintf(szMaxLength, sizeof(szMaxLength), "%d",
    1042             :                      poPDefn->GetWidth());
    1043         292 :             CPLCreateXMLElementAndValue(psPDefnNode, "Width", szMaxLength);
    1044             :         }
    1045         473 :         if (poPDefn->GetWidth() > 0 && EQUAL(pszTypeName, "Integer"))
    1046             :         {
    1047           0 :             char szLength[48] = {};
    1048           0 :             snprintf(szLength, sizeof(szLength), "%d", poPDefn->GetWidth());
    1049           0 :             CPLCreateXMLElementAndValue(psPDefnNode, "Width", szLength);
    1050             :         }
    1051         473 :         if (poPDefn->GetWidth() > 0 && EQUAL(pszTypeName, "Real"))
    1052             :         {
    1053           0 :             char szLength[48] = {};
    1054           0 :             snprintf(szLength, sizeof(szLength), "%d", poPDefn->GetWidth());
    1055           0 :             CPLCreateXMLElementAndValue(psPDefnNode, "Width", szLength);
    1056           0 :             char szPrecision[48] = {};
    1057           0 :             snprintf(szPrecision, sizeof(szPrecision), "%d",
    1058             :                      poPDefn->GetPrecision());
    1059           0 :             CPLCreateXMLElementAndValue(psPDefnNode, "Precision", szPrecision);
    1060             :         }
    1061         473 :         if (!poPDefn->GetDocumentation().empty())
    1062             :         {
    1063           0 :             CPLCreateXMLElementAndValue(psPDefnNode, "Comment",
    1064           0 :                                         poPDefn->GetDocumentation().c_str());
    1065             :         }
    1066             :     }
    1067             : 
    1068         118 :     return psRoot;
    1069             : }
    1070             : 
    1071             : /************************************************************************/
    1072             : /*                       GML_GetOGRFieldType()                          */
    1073             : /************************************************************************/
    1074             : 
    1075        2701 : OGRFieldType GML_GetOGRFieldType(GMLPropertyType eType,
    1076             :                                  OGRFieldSubType &eSubType)
    1077             : {
    1078        2701 :     OGRFieldType eFType = OFTString;
    1079        2701 :     if (eType == GMLPT_Untyped)
    1080           6 :         eFType = OFTString;
    1081        2695 :     else if (eType == GMLPT_String)
    1082        1239 :         eFType = OFTString;
    1083        1456 :     else if (eType == GMLPT_Integer)
    1084         395 :         eFType = OFTInteger;
    1085        1061 :     else if (eType == GMLPT_Boolean)
    1086             :     {
    1087         124 :         eFType = OFTInteger;
    1088         124 :         eSubType = OFSTBoolean;
    1089             :     }
    1090         937 :     else if (eType == GMLPT_Short)
    1091             :     {
    1092         119 :         eFType = OFTInteger;
    1093         119 :         eSubType = OFSTInt16;
    1094             :     }
    1095         818 :     else if (eType == GMLPT_Integer64)
    1096          78 :         eFType = OFTInteger64;
    1097         740 :     else if (eType == GMLPT_Real)
    1098         274 :         eFType = OFTReal;
    1099         466 :     else if (eType == GMLPT_Float)
    1100             :     {
    1101         113 :         eFType = OFTReal;
    1102         113 :         eSubType = OFSTFloat32;
    1103             :     }
    1104         353 :     else if (eType == GMLPT_StringList)
    1105          66 :         eFType = OFTStringList;
    1106         287 :     else if (eType == GMLPT_IntegerList)
    1107          25 :         eFType = OFTIntegerList;
    1108         262 :     else if (eType == GMLPT_BooleanList)
    1109             :     {
    1110           3 :         eFType = OFTIntegerList;
    1111           3 :         eSubType = OFSTBoolean;
    1112             :     }
    1113         259 :     else if (eType == GMLPT_Integer64List)
    1114           9 :         eFType = OFTInteger64List;
    1115         250 :     else if (eType == GMLPT_RealList)
    1116          15 :         eFType = OFTRealList;
    1117         235 :     else if (eType == GMLPT_Date)
    1118          63 :         eFType = OFTDate;
    1119         172 :     else if (eType == GMLPT_Time)
    1120           2 :         eFType = OFTTime;
    1121         170 :     else if (eType == GMLPT_DateTime)
    1122         149 :         eFType = OFTDateTime;
    1123          21 :     else if (eType == GMLPT_FeaturePropertyList)
    1124          10 :         eFType = OFTStringList;
    1125        2701 :     return eFType;
    1126             : }
    1127             : 
    1128             : /************************************************************************/
    1129             : /*                       GML_FromOGRFieldType()                          */
    1130             : /************************************************************************/
    1131             : 
    1132          12 : GMLPropertyType GML_FromOGRFieldType(OGRFieldType eType,
    1133             :                                      OGRFieldSubType eSubType)
    1134             : {
    1135          12 :     GMLPropertyType type{GMLPT_Untyped};
    1136          12 :     switch (eType)
    1137             :     {
    1138           2 :         case OFTString:
    1139           2 :             type = GMLPT_String;
    1140           2 :             break;
    1141           2 :         case OFTInteger:
    1142             :         {
    1143           2 :             if (eSubType == OFSTBoolean)
    1144           0 :                 type = GMLPT_Boolean;
    1145           2 :             else if (eSubType == OFSTInt16)
    1146           2 :                 type = GMLPT_Short;
    1147             :             else
    1148           0 :                 type = GMLPT_Integer;
    1149           2 :             break;
    1150             :         }
    1151           8 :         case OFTReal:
    1152           8 :             type = GMLPT_Real;
    1153           8 :             break;
    1154           0 :         case OFTDate:
    1155           0 :             type = GMLPT_Date;
    1156           0 :             break;
    1157           0 :         case OFTDateTime:
    1158           0 :             type = GMLPT_DateTime;
    1159           0 :             break;
    1160           0 :         case OFTTime:
    1161           0 :             type = GMLPT_Time;
    1162           0 :             break;
    1163           0 :         default:
    1164           0 :             type = GMLPT_Untyped;
    1165           0 :             break;
    1166             :     }
    1167          12 :     return type;
    1168             : }

Generated by: LCOV version 1.14