LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gmlutils - gmlfeatureclass.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 448 555 80.7 %
Date: 2024-11-21 22:18:42 Functions: 27 29 93.1 %

          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         840 : GMLFeatureClass::GMLFeatureClass(const char *pszName)
      37         840 :     : m_pszName(CPLStrdup(pszName)), m_pszElementName(nullptr),
      38         840 :       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         840 :       m_bSRSNameConsistent(true)
      45             : {
      46         840 : }
      47             : 
      48             : /************************************************************************/
      49             : /*                          ~GMLFeatureClass()                          */
      50             : /************************************************************************/
      51             : 
      52         840 : GMLFeatureClass::~GMLFeatureClass()
      53             : 
      54             : {
      55         840 :     CPLFree(m_pszName);
      56         840 :     CPLFree(m_pszElementName);
      57             : 
      58        3693 :     for (int i = 0; i < m_nPropertyCount; i++)
      59        2853 :         delete m_papoProperty[i];
      60         840 :     CPLFree(m_papoProperty);
      61             : 
      62         840 :     ClearGeometryProperties();
      63             : 
      64         840 :     CPLFree(m_pszSRSName);
      65         840 : }
      66             : 
      67             : /************************************************************************/
      68             : /*                         StealProperties()                            */
      69             : /************************************************************************/
      70             : 
      71           2 : void GMLFeatureClass::StealProperties()
      72             : {
      73           2 :     m_nPropertyCount = 0;
      74           2 :     CPLFree(m_papoProperty);
      75           2 :     m_papoProperty = nullptr;
      76           2 :     m_oMapPropertyNameToIndex.clear();
      77           2 :     m_oMapPropertySrcElementToIndex.clear();
      78           2 : }
      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       29920 : GMLPropertyDefn *GMLFeatureClass::GetProperty(int iIndex) const
     106             : 
     107             : {
     108       29920 :     if (iIndex < 0 || iIndex >= m_nPropertyCount)
     109        3263 :         return nullptr;
     110             : 
     111       26657 :     return m_papoProperty[iIndex];
     112             : }
     113             : 
     114             : /************************************************************************/
     115             : /*                          GetPropertyIndex()                          */
     116             : /************************************************************************/
     117             : 
     118        3362 : int GMLFeatureClass::GetPropertyIndex(const char *pszName) const
     119             : 
     120             : {
     121        3362 :     auto oIter = m_oMapPropertyNameToIndex.find(CPLString(pszName).toupper());
     122        3362 :     if (oIter != m_oMapPropertyNameToIndex.end())
     123          15 :         return oIter->second;
     124             : 
     125        3347 :     return -1;
     126             : }
     127             : 
     128             : /************************************************************************/
     129             : /*                        GetPropertyIndexBySrcElement()                */
     130             : /************************************************************************/
     131             : 
     132        5333 : int GMLFeatureClass::GetPropertyIndexBySrcElement(const char *pszElement,
     133             :                                                   int nLen) const
     134             : 
     135             : {
     136             :     auto oIter =
     137        5333 :         m_oMapPropertySrcElementToIndex.find(CPLString(pszElement, nLen));
     138        5333 :     if (oIter != m_oMapPropertySrcElementToIndex.end())
     139        2787 :         return oIter->second;
     140             : 
     141        2546 :     return -1;
     142             : }
     143             : 
     144             : /************************************************************************/
     145             : /*                            AddProperty()                             */
     146             : /************************************************************************/
     147             : 
     148        2867 : int GMLFeatureClass::AddProperty(GMLPropertyDefn *poDefn, int iPos)
     149             : 
     150             : {
     151        2867 :     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        2865 :     m_nPropertyCount++;
     161        2865 :     m_papoProperty = static_cast<GMLPropertyDefn **>(
     162        2865 :         CPLRealloc(m_papoProperty, sizeof(void *) * m_nPropertyCount));
     163             : 
     164        2865 :     if (iPos < 0)
     165             :     {
     166        2862 :         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        2865 :     m_papoProperty[iPos] = poDefn;
     185        2865 :     m_oMapPropertyNameToIndex[CPLString(poDefn->GetName()).toupper()] = iPos;
     186        2865 :     if (m_oMapPropertySrcElementToIndex.find(poDefn->GetSrcElement()) ==
     187        5730 :         m_oMapPropertySrcElementToIndex.end())
     188             :     {
     189        2863 :         m_oMapPropertySrcElementToIndex[poDefn->GetSrcElement()] = iPos;
     190             :     }
     191             : 
     192        2865 :     return iPos;
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                         GetGeometryProperty(int)                      */
     197             : /************************************************************************/
     198             : 
     199        2872 : GMLGeometryPropertyDefn *GMLFeatureClass::GetGeometryProperty(int iIndex) const
     200             : {
     201        2872 :     if (iIndex < 0 || iIndex >= m_nGeometryPropertyCount)
     202           0 :         return nullptr;
     203             : 
     204        2872 :     return m_papoGeometryProperty[iIndex];
     205             : }
     206             : 
     207             : /************************************************************************/
     208             : /*                   GetGeometryPropertyIndexBySrcElement()             */
     209             : /************************************************************************/
     210             : 
     211        2077 : int GMLFeatureClass::GetGeometryPropertyIndexBySrcElement(
     212             :     const char *pszElement) const
     213             : 
     214             : {
     215        2352 :     for (int i = 0; i < m_nGeometryPropertyCount; i++)
     216        1354 :         if (strcmp(pszElement, m_papoGeometryProperty[i]->GetSrcElement()) == 0)
     217        1079 :             return i;
     218             : 
     219         998 :     return -1;
     220             : }
     221             : 
     222             : /************************************************************************/
     223             : /*                         AddGeometryProperty()                        */
     224             : /************************************************************************/
     225             : 
     226         868 : int GMLFeatureClass::AddGeometryProperty(GMLGeometryPropertyDefn *poDefn)
     227             : 
     228             : {
     229         868 :     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         868 :     m_nGeometryPropertyCount++;
     239        1736 :     m_papoGeometryProperty = static_cast<GMLGeometryPropertyDefn **>(CPLRealloc(
     240         868 :         m_papoGeometryProperty, sizeof(void *) * m_nGeometryPropertyCount));
     241             : 
     242         868 :     m_papoGeometryProperty[m_nGeometryPropertyCount - 1] = poDefn;
     243             : 
     244         868 :     return m_nGeometryPropertyCount - 1;
     245             : }
     246             : 
     247             : /************************************************************************/
     248             : /*                       ClearGeometryProperties()                      */
     249             : /************************************************************************/
     250             : 
     251         840 : void GMLFeatureClass::ClearGeometryProperties()
     252             : {
     253        1704 :     for (int i = 0; i < m_nGeometryPropertyCount; i++)
     254         864 :         delete m_papoGeometryProperty[i];
     255         840 :     CPLFree(m_papoGeometryProperty);
     256         840 :     m_nGeometryPropertyCount = 0;
     257         840 :     m_papoGeometryProperty = nullptr;
     258         840 : }
     259             : 
     260             : /************************************************************************/
     261             : /*                         HasFeatureProperties()                       */
     262             : /************************************************************************/
     263             : 
     264         996 : bool GMLFeatureClass::HasFeatureProperties()
     265             : {
     266        3773 :     for (int i = 0; i < m_nPropertyCount; i++)
     267             :     {
     268        5568 :         if (m_papoProperty[i]->GetType() == GMLPT_FeatureProperty ||
     269        2782 :             m_papoProperty[i]->GetType() == GMLPT_FeaturePropertyList)
     270           9 :             return true;
     271             :     }
     272         987 :     return false;
     273             : }
     274             : 
     275             : /************************************************************************/
     276             : /*                           SetElementName()                           */
     277             : /************************************************************************/
     278             : 
     279         150 : void GMLFeatureClass::SetElementName(const char *pszElementName)
     280             : 
     281             : {
     282         150 :     CPLFree(m_pszElementName);
     283         150 :     m_pszElementName = CPLStrdup(pszElementName);
     284         150 :     n_nElementNameLen = static_cast<int>(strlen(pszElementName));
     285         150 : }
     286             : 
     287             : /************************************************************************/
     288             : /*                           GetElementName()                           */
     289             : /************************************************************************/
     290             : 
     291        6993 : const char *GMLFeatureClass::GetElementName() const
     292             : 
     293             : {
     294        6993 :     if (m_pszElementName == nullptr)
     295        5159 :         return m_pszName;
     296             : 
     297        1834 :     return m_pszElementName;
     298             : }
     299             : 
     300             : /************************************************************************/
     301             : /*                           GetElementName()                           */
     302             : /************************************************************************/
     303             : 
     304       26205 : size_t GMLFeatureClass::GetElementNameLen() const
     305             : 
     306             : {
     307       26205 :     if (m_pszElementName == nullptr)
     308       11102 :         return n_nNameLen;
     309             : 
     310       15103 :     return n_nElementNameLen;
     311             : }
     312             : 
     313             : /************************************************************************/
     314             : /*                         GetFeatureCount()                          */
     315             : /************************************************************************/
     316             : 
     317        1503 : GIntBig GMLFeatureClass::GetFeatureCount()
     318             : {
     319        1503 :     return m_nFeatureCount;
     320             : }
     321             : 
     322             : /************************************************************************/
     323             : /*                          SetFeatureCount()                           */
     324             : /************************************************************************/
     325             : 
     326         707 : void GMLFeatureClass::SetFeatureCount(GIntBig nNewCount)
     327             : 
     328             : {
     329         707 :     m_nFeatureCount = nNewCount;
     330         707 : }
     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         543 : void GMLFeatureClass::SetExtents(double dfXMin, double dfXMax, double dfYMin,
     360             :                                  double dfYMax)
     361             : 
     362             : {
     363         543 :     m_dfXMin = dfXMin;
     364         543 :     m_dfXMax = dfXMax;
     365         543 :     m_dfYMin = dfYMin;
     366         543 :     m_dfYMax = dfYMax;
     367             : 
     368         543 :     m_bHaveExtents = true;
     369         543 : }
     370             : 
     371             : /************************************************************************/
     372             : /*                             GetExtents()                             */
     373             : /************************************************************************/
     374             : 
     375         474 : bool GMLFeatureClass::GetExtents(double *pdfXMin, double *pdfXMax,
     376             :                                  double *pdfYMin, double *pdfYMax)
     377             : 
     378             : {
     379         474 :     if (m_bHaveExtents)
     380             :     {
     381         371 :         *pdfXMin = m_dfXMin;
     382         371 :         *pdfXMax = m_dfXMax;
     383         371 :         *pdfYMin = m_dfYMin;
     384         371 :         *pdfYMax = m_dfYMax;
     385             :     }
     386             : 
     387         474 :     return m_bHaveExtents;
     388             : }
     389             : 
     390             : /************************************************************************/
     391             : /*                            SetSRSName()                              */
     392             : /************************************************************************/
     393             : 
     394         147 : void GMLFeatureClass::SetSRSName(const char *pszSRSName)
     395             : 
     396             : {
     397         147 :     m_bSRSNameConsistent = true;
     398         147 :     CPLFree(m_pszSRSName);
     399         147 :     m_pszSRSName = pszSRSName ? CPLStrdup(pszSRSName) : nullptr;
     400         147 : }
     401             : 
     402             : /************************************************************************/
     403             : /*                           MergeSRSName()                             */
     404             : /************************************************************************/
     405             : 
     406         194 : void GMLFeatureClass::MergeSRSName(const char *pszSRSName)
     407             : 
     408             : {
     409         194 :     if (!m_bSRSNameConsistent)
     410           0 :         return;
     411             : 
     412         194 :     if (m_pszSRSName == nullptr)
     413             :     {
     414          91 :         if (pszSRSName)
     415          30 :             m_pszSRSName = CPLStrdup(pszSRSName);
     416             :     }
     417             :     else
     418             :     {
     419         103 :         m_bSRSNameConsistent =
     420         103 :             pszSRSName != nullptr && strcmp(m_pszSRSName, pszSRSName) == 0;
     421         103 :         if (!m_bSRSNameConsistent)
     422             :         {
     423           1 :             CPLFree(m_pszSRSName);
     424           1 :             m_pszSRSName = nullptr;
     425             :         }
     426             :     }
     427             : }
     428             : 
     429             : /************************************************************************/
     430             : /*                         InitializeFromXML()                          */
     431             : /************************************************************************/
     432             : 
     433         101 : bool GMLFeatureClass::InitializeFromXML(CPLXMLNode *psRoot)
     434             : 
     435             : {
     436             :     // Do some rudimentary checking that this is a well formed node.
     437         101 :     if (psRoot == nullptr || psRoot->eType != CXT_Element ||
     438         101 :         !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         101 :     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         101 :     CPLFree(m_pszName);
     455         101 :     m_pszName = CPLStrdup(CPLGetXMLValue(psRoot, "Name", nullptr));
     456         101 :     n_nNameLen = static_cast<int>(strlen(m_pszName));
     457             : 
     458         101 :     SetElementName(CPLGetXMLValue(psRoot, "ElementPath", m_pszName));
     459             : 
     460             :     // Collect geometry properties.
     461         101 :     bool bHasValidGeometryName = false;
     462         101 :     bool bHasValidGeometryElementPath = false;
     463         101 :     bool bHasFoundGeomType = false;
     464         101 :     bool bHasFoundGeomElements = false;
     465         101 :     const char *pszGName = "";
     466         101 :     const char *pszGPath = "";
     467         101 :     OGRwkbGeometryType nGeomType = wkbUnknown;
     468             : 
     469         129 :     const auto FlattenGeomTypeFromInt = [](int eType)
     470             :     {
     471         129 :         eType = eType & (~wkb25DBitInternalUse);
     472         129 :         if (eType >= 1000 && eType < 2000)  // ISO Z.
     473           0 :             return eType - 1000;
     474         129 :         if (eType >= 2000 && eType < 3000)  // ISO M.
     475           0 :             return eType - 2000;
     476         129 :         if (eType >= 3000 && eType < 4000)  // ISO ZM.
     477           0 :             return eType - 3000;
     478         129 :         return eType;
     479             :     };
     480             : 
     481         101 :     CPLXMLNode *psThis = nullptr;
     482        1619 :     for (psThis = psRoot->psChild; psThis != nullptr; psThis = psThis->psNext)
     483             :     {
     484        1530 :         if (psThis->eType == CXT_Element &&
     485        1106 :             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        1451 :         else if (psThis->eType == CXT_Element &&
     525        1027 :                  strcmp(psThis->pszValue, "GeometryName") == 0)
     526             :         {
     527          35 :             bHasFoundGeomElements = true;
     528             : 
     529          35 :             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          35 :             pszGName = CPLGetXMLValue(psThis, nullptr, "");
     542          35 :             bHasValidGeometryName = true;
     543             :         }
     544        1416 :         else if (psThis->eType == CXT_Element &&
     545         992 :                  strcmp(psThis->pszValue, "GeometryElementPath") == 0)
     546             :         {
     547          41 :             bHasFoundGeomElements = true;
     548             : 
     549          41 :             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          41 :             pszGPath = CPLGetXMLValue(psThis, nullptr, "");
     562          41 :             bHasValidGeometryElementPath = true;
     563             :         }
     564        1375 :         else if (psThis->eType == CXT_Element &&
     565         951 :                  strcmp(psThis->pszValue, "GeometryType") == 0)
     566             :         {
     567          52 :             bHasFoundGeomElements = true;
     568             : 
     569          52 :             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          52 :                 CPLGetXMLValue(psThis, nullptr, nullptr);
     583          52 :             nGeomType = wkbUnknown;
     584          52 :             if (pszGeometryType != nullptr && !EQUAL(pszGeometryType, "0"))
     585             :             {
     586          52 :                 const int nGeomTypeInt = atoi(pszGeometryType);
     587             :                 const int nFlattenGeomTypeInt =
     588          52 :                     FlattenGeomTypeFromInt(nGeomTypeInt);
     589          52 :                 if (nGeomTypeInt == 100 || EQUAL(pszGeometryType, "NONE"))
     590             :                 {
     591          12 :                     bHasValidGeometryElementPath = false;
     592          12 :                     bHasFoundGeomType = false;
     593          12 :                     break;
     594             :                 }
     595          40 :                 else if (nGeomTypeInt != 0 &&
     596          36 :                          !(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          40 :                 else if (nGeomTypeInt == 0)
     604             :                 {
     605           4 :                     nGeomType = OGRFromOGCGeomType(pszGeometryType);
     606             :                 }
     607             :                 else
     608             :                 {
     609          36 :                     nGeomType = static_cast<OGRwkbGeometryType>(nGeomTypeInt);
     610             :                 }
     611             :             }
     612          40 :             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         101 :     if (bHasValidGeometryElementPath || bHasFoundGeomType ||
     620          58 :         !bHasFoundGeomElements)
     621             :     {
     622             :         auto poDefn = new GMLGeometryPropertyDefn(pszGName, pszGPath, nGeomType,
     623          55 :                                                   -1, true);
     624          55 :         if (AddGeometryProperty(poDefn) < 0)
     625           0 :             delete poDefn;
     626             :     }
     627             : 
     628         101 :     SetSRSName(CPLGetXMLValue(psRoot, "SRSName", nullptr));
     629             : 
     630             :     // Collect dataset specific info.
     631         101 :     CPLXMLNode *psDSI = CPLGetXMLNode(psRoot, "DatasetSpecificInfo");
     632         101 :     if (psDSI != nullptr)
     633             :     {
     634          54 :         const char *pszValue = CPLGetXMLValue(psDSI, "FeatureCount", nullptr);
     635          54 :         if (pszValue != nullptr)
     636          54 :             SetFeatureCount(CPLAtoGIntBig(pszValue));
     637             : 
     638             :         // Eventually we should support XML subtrees.
     639          54 :         pszValue = CPLGetXMLValue(psDSI, "ExtraInfo", nullptr);
     640          54 :         if (pszValue != nullptr)
     641           0 :             SetExtraInfo(pszValue);
     642             : 
     643          54 :         if (CPLGetXMLValue(psDSI, "ExtentXMin", nullptr) != nullptr &&
     644          48 :             CPLGetXMLValue(psDSI, "ExtentXMax", nullptr) != nullptr &&
     645         150 :             CPLGetXMLValue(psDSI, "ExtentYMin", nullptr) != nullptr &&
     646          48 :             CPLGetXMLValue(psDSI, "ExtentYMax", nullptr) != nullptr)
     647             :         {
     648          48 :             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        1679 :     for (psThis = psRoot->psChild; psThis != nullptr; psThis = psThis->psNext)
     657             :     {
     658        1578 :         if (psThis->eType == CXT_Element &&
     659        1154 :             EQUAL(psThis->pszValue, "PropertyDefn"))
     660             :         {
     661         641 :             const char *pszName = CPLGetXMLValue(psThis, "Name", nullptr);
     662         641 :             const char *pszType = CPLGetXMLValue(psThis, "Type", "Untyped");
     663         641 :             const char *pszSubType = CPLGetXMLValue(psThis, "Subtype", "");
     664             :             const char *pszCondition =
     665         641 :                 CPLGetXMLValue(psThis, "Condition", nullptr);
     666             :             const bool bNullable =
     667         641 :                 CPLTestBool(CPLGetXMLValue(psThis, "Nullable", "true"));
     668             :             const bool bUnique =
     669         641 :                 CPLTestBool(CPLGetXMLValue(psThis, "Unique", "false"));
     670         641 :             const char *pszComment = CPLGetXMLValue(psThis, "Comment", nullptr);
     671             : 
     672         641 :             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         641 :                 pszName, CPLGetXMLValue(psThis, "ElementPath", nullptr));
     683             : 
     684         641 :             poPDefn->SetNullable(bNullable);
     685         641 :             poPDefn->SetUnique(bUnique);
     686         641 :             if (EQUAL(pszType, "Untyped"))
     687             :             {
     688           0 :                 poPDefn->SetType(GMLPT_Untyped);
     689             :             }
     690         641 :             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         289 :             else if (EQUAL(pszType, "Integer"))
     717             :             {
     718         189 :                 if (EQUAL(pszSubType, "Short"))
     719             :                 {
     720           0 :                     poPDefn->SetType(GMLPT_Short);
     721             :                 }
     722         189 :                 else if (EQUAL(pszSubType, "Integer64"))
     723             :                 {
     724          60 :                     poPDefn->SetType(GMLPT_Integer64);
     725             :                 }
     726             :                 else
     727             :                 {
     728         129 :                     poPDefn->SetType(GMLPT_Integer);
     729             :                 }
     730         189 :                 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         641 :             if (pszCondition != nullptr)
     785           4 :                 poPDefn->SetCondition(pszCondition);
     786         641 :             if (pszComment != nullptr)
     787           1 :                 poPDefn->SetDocumentation(pszComment);
     788             : 
     789         641 :             if (AddProperty(poPDefn) < 0)
     790           0 :                 delete poPDefn;
     791             :         }
     792             :     }
     793             : 
     794         101 :     return true;
     795             : }
     796             : 
     797             : /************************************************************************/
     798             : /*                           SerializeToXML()                           */
     799             : /************************************************************************/
     800             : 
     801         108 : CPLXMLNode *GMLFeatureClass::SerializeToXML()
     802             : 
     803             : {
     804             :     // Set feature class and core information.
     805             :     CPLXMLNode *psRoot =
     806         108 :         CPLCreateXMLNode(nullptr, CXT_Element, "GMLFeatureClass");
     807             : 
     808         108 :     CPLCreateXMLElementAndValue(psRoot, "Name", GetName());
     809         108 :     CPLCreateXMLElementAndValue(psRoot, "ElementPath", GetElementName());
     810             : 
     811         108 :     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         106 :     else if (m_nGeometryPropertyCount == 1)
     845             :     {
     846          86 :         GMLGeometryPropertyDefn *poGeomFDefn = m_papoGeometryProperty[0];
     847             : 
     848          86 :         if (strlen(poGeomFDefn->GetName()) > 0)
     849          65 :             CPLCreateXMLElementAndValue(psRoot, "GeometryName",
     850             :                                         poGeomFDefn->GetName());
     851             : 
     852         172 :         if (poGeomFDefn->GetSrcElement() != nullptr &&
     853          86 :             strlen(poGeomFDefn->GetSrcElement()) > 0)
     854          65 :             CPLCreateXMLElementAndValue(psRoot, "GeometryElementPath",
     855             :                                         poGeomFDefn->GetSrcElement());
     856             : 
     857          86 :         if (poGeomFDefn->GetType() != 0 /* wkbUnknown */)
     858             :         {
     859          78 :             char szValue[128] = {};
     860             : 
     861             :             OGRwkbGeometryType eType =
     862          78 :                 static_cast<OGRwkbGeometryType>(poGeomFDefn->GetType());
     863             : 
     864         156 :             CPLString osStr(OGRToOGCGeomType(eType));
     865          78 :             if (wkbHasZ(eType))
     866           7 :                 osStr += "Z";
     867          78 :             CPLCreateXMLNode(psRoot, CXT_Comment, osStr.c_str());
     868             : 
     869          78 :             snprintf(szValue, sizeof(szValue), "%d", eType);
     870          78 :             CPLCreateXMLElementAndValue(psRoot, "GeometryType", szValue);
     871             :         }
     872             :     }
     873             :     else
     874             :     {
     875          20 :         CPLCreateXMLElementAndValue(psRoot, "GeometryType", "100");
     876             :     }
     877             : 
     878         108 :     const char *pszSRSName = GetSRSName();
     879         108 :     if (pszSRSName)
     880             :     {
     881          54 :         CPLCreateXMLElementAndValue(psRoot, "SRSName", pszSRSName);
     882             :     }
     883             : 
     884             :     // Write out dataset specific information.
     885         108 :     if (m_bHaveExtents || m_nFeatureCount != -1 || m_pszExtraInfo != nullptr)
     886             :     {
     887             :         CPLXMLNode *psDSI =
     888         107 :             CPLCreateXMLNode(psRoot, CXT_Element, "DatasetSpecificInfo");
     889             : 
     890         107 :         if (m_nFeatureCount != -1)
     891             :         {
     892         107 :             char szValue[128] = {};
     893             : 
     894         107 :             snprintf(szValue, sizeof(szValue), CPL_FRMT_GIB, m_nFeatureCount);
     895         107 :             CPLCreateXMLElementAndValue(psDSI, "FeatureCount", szValue);
     896             :         }
     897             : 
     898         107 :         if (m_bHaveExtents && fabs(m_dfXMin) < 1e100 &&
     899          85 :             fabs(m_dfXMax) < 1e100 && fabs(m_dfYMin) < 1e100 &&
     900          85 :             fabs(m_dfYMax) < 1e100)
     901             :         {
     902          85 :             char szValue[128] = {};
     903             : 
     904          85 :             CPLsnprintf(szValue, sizeof(szValue), "%.5f", m_dfXMin);
     905          85 :             CPLCreateXMLElementAndValue(psDSI, "ExtentXMin", szValue);
     906             : 
     907          85 :             CPLsnprintf(szValue, sizeof(szValue), "%.5f", m_dfXMax);
     908          85 :             CPLCreateXMLElementAndValue(psDSI, "ExtentXMax", szValue);
     909             : 
     910          85 :             CPLsnprintf(szValue, sizeof(szValue), "%.5f", m_dfYMin);
     911          85 :             CPLCreateXMLElementAndValue(psDSI, "ExtentYMin", szValue);
     912             : 
     913          85 :             CPLsnprintf(szValue, sizeof(szValue), "%.5f", m_dfYMax);
     914          85 :             CPLCreateXMLElementAndValue(psDSI, "ExtentYMax", szValue);
     915             :         }
     916             : 
     917         107 :         if (m_pszExtraInfo)
     918           0 :             CPLCreateXMLElementAndValue(psDSI, "ExtraInfo", m_pszExtraInfo);
     919             :     }
     920             : 
     921         108 :     CPLXMLNode *psLastChild = psRoot->psChild;
     922         687 :     while (psLastChild->psNext)
     923             :     {
     924         579 :         psLastChild = psLastChild->psNext;
     925             :     }
     926             : 
     927             :     // Emit property information.
     928         513 :     for (int iProperty = 0; iProperty < GetPropertyCount(); iProperty++)
     929             :     {
     930         405 :         GMLPropertyDefn *poPDefn = GetProperty(iProperty);
     931         405 :         const char *pszTypeName = "Unknown";
     932             : 
     933             :         CPLXMLNode *psPDefnNode =
     934         405 :             CPLCreateXMLNode(nullptr, CXT_Element, "PropertyDefn");
     935         405 :         psLastChild->psNext = psPDefnNode;
     936         405 :         psLastChild = psPDefnNode;
     937         405 :         CPLCreateXMLElementAndValue(psPDefnNode, "Name", poPDefn->GetName());
     938         405 :         CPLCreateXMLElementAndValue(psPDefnNode, "ElementPath",
     939             :                                     poPDefn->GetSrcElement());
     940         405 :         const auto gmlType = poPDefn->GetType();
     941         405 :         const char *pszSubTypeName = nullptr;
     942         405 :         switch (gmlType)
     943             :         {
     944           4 :             case GMLPT_Untyped:
     945           4 :                 pszTypeName = "Untyped";
     946           4 :                 break;
     947             : 
     948         249 :             case GMLPT_String:
     949         249 :                 pszTypeName = "String";
     950         249 :                 break;
     951             : 
     952          10 :             case GMLPT_Boolean:
     953          10 :                 pszTypeName = "String";
     954          10 :                 pszSubTypeName = "Boolean";
     955          10 :                 break;
     956             : 
     957           0 :             case GMLPT_Date:
     958           0 :                 pszTypeName = "String";
     959           0 :                 pszSubTypeName = "Date";
     960           0 :                 break;
     961             : 
     962           0 :             case GMLPT_Time:
     963           0 :                 pszTypeName = "String";
     964           0 :                 pszSubTypeName = "Time";
     965           0 :                 break;
     966             : 
     967           0 :             case GMLPT_DateTime:
     968           0 :                 pszTypeName = "String";
     969           0 :                 pszSubTypeName = "DateTime";
     970           0 :                 break;
     971             : 
     972          72 :             case GMLPT_Integer:
     973          72 :                 pszTypeName = "Integer";
     974          72 :                 break;
     975             : 
     976           0 :             case GMLPT_Short:
     977           0 :                 pszTypeName = "Integer";
     978           0 :                 pszSubTypeName = "Short";
     979           0 :                 break;
     980             : 
     981           1 :             case GMLPT_Integer64:
     982           1 :                 pszTypeName = "Integer";
     983           1 :                 pszSubTypeName = "Integer64";
     984           1 :                 break;
     985             : 
     986          24 :             case GMLPT_Real:
     987          24 :                 pszTypeName = "Real";
     988          24 :                 break;
     989             : 
     990           0 :             case GMLPT_Float:
     991           0 :                 pszTypeName = "Real";
     992           0 :                 pszSubTypeName = "Float";
     993           0 :                 break;
     994             : 
     995           0 :             case GMLPT_Complex:
     996           0 :                 pszTypeName = "Complex";
     997           0 :                 break;
     998             : 
     999           2 :             case GMLPT_IntegerList:
    1000           2 :                 pszTypeName = "IntegerList";
    1001           2 :                 break;
    1002             : 
    1003           1 :             case GMLPT_Integer64List:
    1004           1 :                 pszTypeName = "IntegerList";
    1005           1 :                 pszSubTypeName = "Integer64";
    1006           1 :                 break;
    1007             : 
    1008           2 :             case GMLPT_RealList:
    1009           2 :                 pszTypeName = "RealList";
    1010           2 :                 break;
    1011             : 
    1012          39 :             case GMLPT_StringList:
    1013          39 :                 pszTypeName = "StringList";
    1014          39 :                 break;
    1015             : 
    1016           1 :             case GMLPT_BooleanList:
    1017           1 :                 pszTypeName = "StringList";
    1018           1 :                 pszSubTypeName = "Boolean";
    1019           1 :                 break;
    1020             : 
    1021             :             // Should not happen in practice for now because this is not
    1022             :             // autodetected.
    1023           0 :             case GMLPT_FeatureProperty:
    1024           0 :                 pszTypeName = "FeatureProperty";
    1025           0 :                 break;
    1026             : 
    1027             :             // Should not happen in practice for now because this is not
    1028             :             // autodetected.
    1029           0 :             case GMLPT_FeaturePropertyList:
    1030           0 :                 pszTypeName = "FeaturePropertyList";
    1031           0 :                 break;
    1032             :         }
    1033         405 :         CPLCreateXMLElementAndValue(psPDefnNode, "Type", pszTypeName);
    1034         405 :         if (pszSubTypeName)
    1035          13 :             CPLCreateXMLElementAndValue(psPDefnNode, "Subtype", pszSubTypeName);
    1036             : 
    1037         405 :         if (EQUAL(pszTypeName, "String"))
    1038             :         {
    1039         259 :             char szMaxLength[48] = {};
    1040         259 :             snprintf(szMaxLength, sizeof(szMaxLength), "%d",
    1041             :                      poPDefn->GetWidth());
    1042         259 :             CPLCreateXMLElementAndValue(psPDefnNode, "Width", szMaxLength);
    1043             :         }
    1044         405 :         if (poPDefn->GetWidth() > 0 && EQUAL(pszTypeName, "Integer"))
    1045             :         {
    1046           0 :             char szLength[48] = {};
    1047           0 :             snprintf(szLength, sizeof(szLength), "%d", poPDefn->GetWidth());
    1048           0 :             CPLCreateXMLElementAndValue(psPDefnNode, "Width", szLength);
    1049             :         }
    1050         405 :         if (poPDefn->GetWidth() > 0 && EQUAL(pszTypeName, "Real"))
    1051             :         {
    1052           0 :             char szLength[48] = {};
    1053           0 :             snprintf(szLength, sizeof(szLength), "%d", poPDefn->GetWidth());
    1054           0 :             CPLCreateXMLElementAndValue(psPDefnNode, "Width", szLength);
    1055           0 :             char szPrecision[48] = {};
    1056           0 :             snprintf(szPrecision, sizeof(szPrecision), "%d",
    1057             :                      poPDefn->GetPrecision());
    1058           0 :             CPLCreateXMLElementAndValue(psPDefnNode, "Precision", szPrecision);
    1059             :         }
    1060         405 :         if (!poPDefn->GetDocumentation().empty())
    1061             :         {
    1062           0 :             CPLCreateXMLElementAndValue(psPDefnNode, "Comment",
    1063           0 :                                         poPDefn->GetDocumentation().c_str());
    1064             :         }
    1065             :     }
    1066             : 
    1067         108 :     return psRoot;
    1068             : }
    1069             : 
    1070             : /************************************************************************/
    1071             : /*                       GML_GetOGRFieldType()                          */
    1072             : /************************************************************************/
    1073             : 
    1074        2591 : OGRFieldType GML_GetOGRFieldType(GMLPropertyType eType,
    1075             :                                  OGRFieldSubType &eSubType)
    1076             : {
    1077        2591 :     OGRFieldType eFType = OFTString;
    1078        2591 :     eSubType = OFSTNone;
    1079        2591 :     if (eType == GMLPT_Untyped)
    1080           0 :         eFType = OFTString;
    1081        2591 :     else if (eType == GMLPT_String)
    1082        1194 :         eFType = OFTString;
    1083        1397 :     else if (eType == GMLPT_Integer)
    1084         363 :         eFType = OFTInteger;
    1085        1034 :     else if (eType == GMLPT_Boolean)
    1086             :     {
    1087         124 :         eFType = OFTInteger;
    1088         124 :         eSubType = OFSTBoolean;
    1089             :     }
    1090         910 :     else if (eType == GMLPT_Short)
    1091             :     {
    1092         117 :         eFType = OFTInteger;
    1093         117 :         eSubType = OFSTInt16;
    1094             :     }
    1095         793 :     else if (eType == GMLPT_Integer64)
    1096          78 :         eFType = OFTInteger64;
    1097         715 :     else if (eType == GMLPT_Real)
    1098         249 :         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        2591 :     return eFType;
    1126             : }

Generated by: LCOV version 1.14