LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gmlas - ogrgmlaslayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 793 827 95.9 %
Date: 2024-11-21 22:18:42 Functions: 30 30 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Project:  OGR
       3             :  * Purpose:  OGRGMLASDriver implementation
       4             :  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
       5             :  *
       6             :  * Initial development funded by the European Earth observation programme
       7             :  * Copernicus
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "ogr_gmlas.h"
      16             : #include "ogr_pgdump.h"
      17             : #include "cpl_minixml.h"
      18             : 
      19             : /************************************************************************/
      20             : /*                            OGRGMLASLayer()                           */
      21             : /************************************************************************/
      22             : 
      23       15271 : OGRGMLASLayer::OGRGMLASLayer(OGRGMLASDataSource *poDS,
      24             :                              const GMLASFeatureClass &oFC,
      25             :                              OGRGMLASLayer *poParentLayer,
      26       15271 :                              bool bAlwaysGenerateOGRPKId)
      27             :     : m_poDS(poDS), m_oFC(oFC),
      28       15271 :       m_poFeatureDefn(new OGRFeatureDefn(oFC.GetName())),
      29       30542 :       m_poParentLayer(poParentLayer)
      30             : {
      31       15271 :     m_poFeatureDefn->SetGeomType(wkbNone);
      32       15271 :     m_poFeatureDefn->Reference();
      33             : 
      34       15271 :     SetDescription(m_poFeatureDefn->GetName());
      35             : 
      36             :     // Are we a regular table ?
      37       15271 :     if (m_oFC.GetParentXPath().empty())
      38             :     {
      39        6407 :         if (bAlwaysGenerateOGRPKId)
      40             :         {
      41          46 :             OGRFieldDefn oFieldDefn(szOGR_PKID, OFTString);
      42          23 :             oFieldDefn.SetNullable(false);
      43          23 :             m_nIDFieldIdx = m_poFeatureDefn->GetFieldCount();
      44          23 :             m_bIDFieldIsGenerated = true;
      45          23 :             m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
      46             :         }
      47             : 
      48             :         // Determine if we have an xs:ID attribute/elt, and if it is compulsory,
      49             :         // If so, place it as first field (not strictly required, but more
      50             :         // readable) or second field (if we also add a ogr_pkid) Furthermore
      51             :         // restrict that to attributes, because otherwise it is impractical in
      52             :         // the reader when joining related features.
      53        6407 :         const std::vector<GMLASField> &oFields = m_oFC.GetFields();
      54      189925 :         for (int i = 0; i < static_cast<int>(oFields.size()); i++)
      55             :         {
      56      189499 :             if (oFields[i].GetType() == GMLAS_FT_ID &&
      57      189499 :                 oFields[i].IsNotNullable() &&
      58         209 :                 oFields[i].GetXPath().find('@') != std::string::npos)
      59             :             {
      60         108 :                 OGRFieldDefn oFieldDefn(oFields[i].GetName(), OFTString);
      61          54 :                 oFieldDefn.SetNullable(false);
      62          54 :                 const int nOGRIdx = m_poFeatureDefn->GetFieldCount();
      63          54 :                 if (m_nIDFieldIdx < 0)
      64          53 :                     m_nIDFieldIdx = nOGRIdx;
      65          54 :                 m_oMapFieldXPathToOGRFieldIdx[oFields[i].GetXPath()] = nOGRIdx;
      66          54 :                 m_oMapOGRFieldIdxtoFCFieldIdx[nOGRIdx] = i;
      67          54 :                 m_oMapFieldXPathToFCFieldIdx[oFields[i].GetXPath()] = i;
      68          54 :                 m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
      69          54 :                 break;
      70             :             }
      71             :         }
      72             : 
      73             :         // If we don't have an explicit ID, then we need
      74             :         // to generate one, so that potentially related classes can reference it
      75             :         // (We could perhaps try to be clever to determine if we really need it)
      76        6407 :         if (m_nIDFieldIdx < 0)
      77             :         {
      78       12662 :             OGRFieldDefn oFieldDefn(szOGR_PKID, OFTString);
      79        6331 :             oFieldDefn.SetNullable(false);
      80        6331 :             m_nIDFieldIdx = m_poFeatureDefn->GetFieldCount();
      81        6331 :             m_bIDFieldIsGenerated = true;
      82        6331 :             m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
      83             :         }
      84             :     }
      85             : 
      86       15271 :     OGRLayer *poLayersMetadataLayer = m_poDS->GetLayersMetadataLayer();
      87             :     OGRFeature *poLayerDescFeature =
      88       15271 :         new OGRFeature(poLayersMetadataLayer->GetLayerDefn());
      89       15271 :     poLayerDescFeature->SetField(szLAYER_NAME, OGRGMLASLayer::GetName());
      90       15271 :     if (!m_oFC.GetParentXPath().empty())
      91             :     {
      92        8864 :         poLayerDescFeature->SetField(szLAYER_CATEGORY, szJUNCTION_TABLE);
      93             :     }
      94             :     else
      95             :     {
      96        6407 :         poLayerDescFeature->SetField(szLAYER_XPATH, m_oFC.GetXPath());
      97             : 
      98        6407 :         poLayerDescFeature->SetField(szLAYER_CATEGORY, m_oFC.IsTopLevelElt()
      99             :                                                            ? szTOP_LEVEL_ELEMENT
     100             :                                                            : szNESTED_ELEMENT);
     101             : 
     102        6407 :         if (m_nIDFieldIdx >= 0)
     103             :         {
     104        6407 :             poLayerDescFeature->SetField(
     105             :                 szLAYER_PKID_NAME,
     106        6407 :                 m_poFeatureDefn->GetFieldDefn(m_nIDFieldIdx)->GetNameRef());
     107             :         }
     108             : 
     109             :         // If we are a child class, then add a field to reference the parent.
     110        6407 :         if (m_poParentLayer != nullptr)
     111             :         {
     112        6618 :             CPLString osFieldName(szPARENT_PREFIX);
     113        3309 :             osFieldName += m_poParentLayer->GetLayerDefn()
     114        3309 :                                ->GetFieldDefn(m_poParentLayer->GetIDFieldIdx())
     115        3309 :                                ->GetNameRef();
     116        3309 :             poLayerDescFeature->SetField(szLAYER_PARENT_PKID_NAME,
     117             :                                          osFieldName.c_str());
     118             :         }
     119             : 
     120        6407 :         if (!m_oFC.GetDocumentation().empty())
     121             :         {
     122        5065 :             poLayerDescFeature->SetField(szLAYER_DOCUMENTATION,
     123        5065 :                                          m_oFC.GetDocumentation());
     124             :         }
     125             :     }
     126       15271 :     CPL_IGNORE_RET_VAL(
     127       15271 :         poLayersMetadataLayer->CreateFeature(poLayerDescFeature));
     128       15271 :     delete poLayerDescFeature;
     129       15271 : }
     130             : 
     131             : /************************************************************************/
     132             : /*                            OGRGMLASLayer()                           */
     133             : /************************************************************************/
     134             : 
     135           3 : OGRGMLASLayer::OGRGMLASLayer(const char *pszLayerName)
     136             :     : m_bLayerDefnFinalized(true),
     137           3 :       m_poFeatureDefn(new OGRFeatureDefn(pszLayerName))
     138             : 
     139             : {
     140           3 :     m_poFeatureDefn->SetGeomType(wkbNone);
     141           3 :     m_poFeatureDefn->Reference();
     142             : 
     143           3 :     SetDescription(m_poFeatureDefn->GetName());
     144           3 : }
     145             : 
     146             : /************************************************************************/
     147             : /*                        GetSWEChildAndType()                          */
     148             : /************************************************************************/
     149             : 
     150          36 : static CPLXMLNode *GetSWEChildAndType(CPLXMLNode *psNode, OGRFieldType &eType,
     151             :                                       OGRFieldSubType &eSubType)
     152             : {
     153          36 :     eType = OFTString;
     154          36 :     eSubType = OFSTNone;
     155          36 :     CPLXMLNode *psChildNode = nullptr;
     156          36 :     if ((psChildNode = CPLGetXMLNode(psNode, "Time")) != nullptr)
     157             :     {
     158           8 :         eType = OFTDateTime;
     159             :     }
     160          28 :     else if ((psChildNode = CPLGetXMLNode(psNode, "Quantity")) != nullptr)
     161             :     {
     162           8 :         eType = OFTReal;
     163             :     }
     164          20 :     else if ((psChildNode = CPLGetXMLNode(psNode, "Category")) != nullptr)
     165             :     {
     166           8 :         eType = OFTString;
     167             :     }
     168          12 :     else if ((psChildNode = CPLGetXMLNode(psNode, "Count")) != nullptr)
     169             :     {
     170           4 :         eType = OFTInteger;
     171             :     }
     172           8 :     else if ((psChildNode = CPLGetXMLNode(psNode, "Text")) != nullptr)
     173             :     {
     174           4 :         eType = OFTString;
     175             :     }
     176           4 :     else if ((psChildNode = CPLGetXMLNode(psNode, "Boolean")) != nullptr)
     177             :     {
     178           4 :         eType = OFTInteger;
     179           4 :         eSubType = OFSTBoolean;
     180             :     }
     181          36 :     return psChildNode;
     182             : }
     183             : 
     184             : /************************************************************************/
     185             : /*              ProcessDataRecordOfDataArrayCreateFields()               */
     186             : /************************************************************************/
     187             : 
     188           3 : void OGRGMLASLayer::ProcessDataRecordOfDataArrayCreateFields(
     189             :     OGRGMLASLayer *poParentLayer, CPLXMLNode *psDataRecord,
     190             :     OGRLayer *poFieldsMetadataLayer)
     191             : {
     192             :     {
     193           6 :         CPLString osFieldName(szPARENT_PREFIX);
     194           3 :         osFieldName += poParentLayer->GetLayerDefn()
     195           3 :                            ->GetFieldDefn(poParentLayer->GetIDFieldIdx())
     196           3 :                            ->GetNameRef();
     197           6 :         OGRFieldDefn oFieldDefn(osFieldName, OFTString);
     198           3 :         oFieldDefn.SetNullable(false);
     199           3 :         m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
     200             :     }
     201             : 
     202          30 :     for (CPLXMLNode *psIter = psDataRecord->psChild; psIter != nullptr;
     203          27 :          psIter = psIter->psNext)
     204             :     {
     205          27 :         if (psIter->eType == CXT_Element &&
     206          12 :             strcmp(psIter->pszValue, "field") == 0)
     207             :         {
     208          12 :             const char *pszName = CPLGetXMLValue(psIter, "name", "");
     209          24 :             OGRFieldDefn oFieldDefn(CPLString(pszName).tolower(), OFTString);
     210             :             OGRFieldType eType;
     211             :             OGRFieldSubType eSubType;
     212          12 :             CPLXMLNode *psNode = GetSWEChildAndType(psIter, eType, eSubType);
     213          12 :             oFieldDefn.SetType(eType);
     214          12 :             oFieldDefn.SetSubType(eSubType);
     215          12 :             m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
     216             : 
     217             :             // Register field in _ogr_fields_metadata
     218             :             OGRFeature *poFieldDescFeature =
     219          12 :                 new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
     220          12 :             poFieldDescFeature->SetField(szLAYER_NAME, GetName());
     221          12 :             m_nMaxFieldIndex = m_poFeatureDefn->GetFieldCount() - 1;
     222          12 :             poFieldDescFeature->SetField(szFIELD_INDEX, m_nMaxFieldIndex);
     223          12 :             poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
     224          12 :             if (psNode)
     225             :             {
     226          12 :                 poFieldDescFeature->SetField(szFIELD_TYPE, psNode->pszValue);
     227             :             }
     228          12 :             poFieldDescFeature->SetField(szFIELD_IS_LIST, 0);
     229          12 :             poFieldDescFeature->SetField(szFIELD_MIN_OCCURS, 0);
     230          12 :             poFieldDescFeature->SetField(szFIELD_MAX_OCCURS, 1);
     231          12 :             poFieldDescFeature->SetField(szFIELD_CATEGORY, szSWE_FIELD);
     232          12 :             if (psNode)
     233             :             {
     234          12 :                 char *pszXML = CPLSerializeXMLTree(psNode);
     235          12 :                 poFieldDescFeature->SetField(szFIELD_DOCUMENTATION, pszXML);
     236          12 :                 CPLFree(pszXML);
     237             :             }
     238          12 :             CPL_IGNORE_RET_VAL(
     239          12 :                 poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
     240          12 :             delete poFieldDescFeature;
     241             :         }
     242             :     }
     243           3 : }
     244             : 
     245             : /************************************************************************/
     246             : /*                ProcessDataRecordCreateFields()                       */
     247             : /************************************************************************/
     248             : 
     249           4 : void OGRGMLASLayer::ProcessDataRecordCreateFields(
     250             :     CPLXMLNode *psDataRecord, const std::vector<OGRFeature *> &apoFeatures,
     251             :     OGRLayer *poFieldsMetadataLayer)
     252             : {
     253          33 :     for (CPLXMLNode *psIter = psDataRecord->psChild; psIter != nullptr;
     254          29 :          psIter = psIter->psNext)
     255             :     {
     256          29 :         if (psIter->eType == CXT_Element &&
     257          18 :             strcmp(psIter->pszValue, "field") == 0)
     258             :         {
     259          18 :             const char *pszName = CPLGetXMLValue(psIter, "name", "");
     260          36 :             CPLString osName = CPLString(pszName).tolower();
     261          36 :             OGRFieldDefn oFieldDefn(osName, OFTString);
     262             :             OGRFieldType eType;
     263             :             OGRFieldSubType eSubType;
     264             :             CPLXMLNode *psChildNode =
     265          18 :                 GetSWEChildAndType(psIter, eType, eSubType);
     266          18 :             oFieldDefn.SetType(eType);
     267          18 :             oFieldDefn.SetSubType(eSubType);
     268          36 :             if (psChildNode != nullptr &&
     269          18 :                 m_oMapSWEFieldToOGRFieldName.find(osName) ==
     270          36 :                     m_oMapSWEFieldToOGRFieldName.end())
     271             :             {
     272          12 :                 const int nValidFields = m_poFeatureDefn->GetFieldCount();
     273             : 
     274          24 :                 CPLString osSWEField(osName);
     275          12 :                 if (m_poFeatureDefn->GetFieldIndex(osName) >= 0)
     276           0 :                     osName = "swe_field_" + osName;
     277          12 :                 m_oMapSWEFieldToOGRFieldName[osSWEField] = osName;
     278          12 :                 oFieldDefn.SetName((osName + "_value").c_str());
     279          12 :                 m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
     280             : 
     281             :                 // Register field in _ogr_fields_metadata
     282             :                 OGRFeature *poFieldDescFeature =
     283          12 :                     new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
     284          12 :                 poFieldDescFeature->SetField(szLAYER_NAME, GetName());
     285          12 :                 m_nMaxFieldIndex++;
     286          12 :                 poFieldDescFeature->SetField(szFIELD_INDEX, m_nMaxFieldIndex);
     287          12 :                 poFieldDescFeature->SetField(szFIELD_NAME,
     288             :                                              oFieldDefn.GetNameRef());
     289          12 :                 poFieldDescFeature->SetField(szFIELD_TYPE,
     290          12 :                                              psChildNode->pszValue);
     291          12 :                 poFieldDescFeature->SetField(szFIELD_IS_LIST, 0);
     292          12 :                 poFieldDescFeature->SetField(szFIELD_MIN_OCCURS, 0);
     293          12 :                 poFieldDescFeature->SetField(szFIELD_MAX_OCCURS, 1);
     294          12 :                 poFieldDescFeature->SetField(szFIELD_CATEGORY, szSWE_FIELD);
     295             :                 {
     296          12 :                     CPLXMLNode *psDupTree = CPLCloneXMLTree(psChildNode);
     297          12 :                     CPLXMLNode *psValue = CPLGetXMLNode(psDupTree, "value");
     298          12 :                     if (psValue != nullptr)
     299             :                     {
     300          12 :                         CPLRemoveXMLChild(psDupTree, psValue);
     301          12 :                         CPLDestroyXMLNode(psValue);
     302             :                     }
     303          12 :                     char *pszXML = CPLSerializeXMLTree(psDupTree);
     304          12 :                     CPLDestroyXMLNode(psDupTree);
     305          12 :                     poFieldDescFeature->SetField(szFIELD_DOCUMENTATION, pszXML);
     306          12 :                     CPLFree(pszXML);
     307             :                 }
     308          12 :                 CPL_IGNORE_RET_VAL(
     309          12 :                     poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
     310          12 :                 delete poFieldDescFeature;
     311             : 
     312          12 :                 for (CPLXMLNode *psIter2 = psChildNode->psChild;
     313          55 :                      psIter2 != nullptr; psIter2 = psIter2->psNext)
     314             :                 {
     315          43 :                     if (psIter2->eType == CXT_Element &&
     316          16 :                         strcmp(psIter2->pszValue, "value") != 0)
     317             :                     {
     318             :                         const CPLString osName2 =
     319           8 :                             CPLString(osName + "_" + psIter2->pszValue)
     320           8 :                                 .tolower();
     321           4 :                         for (CPLXMLNode *psIter3 = psIter2->psChild;
     322           8 :                              psIter3 != nullptr; psIter3 = psIter3->psNext)
     323             :                         {
     324           4 :                             if (psIter3->eType == CXT_Attribute)
     325             :                             {
     326           2 :                                 const char *pszValue = psIter3->pszValue;
     327           2 :                                 const char *pszColon = strchr(pszValue, ':');
     328           2 :                                 if (pszColon)
     329           2 :                                     pszValue = pszColon + 1;
     330             :                                 OGRFieldDefn oFieldDefn2(
     331           4 :                                     CPLString(osName2 + "_" + pszValue)
     332           2 :                                         .tolower(),
     333           4 :                                     OFTString);
     334           2 :                                 m_poFeatureDefn->AddFieldDefn(&oFieldDefn2);
     335             :                             }
     336           2 :                             else if (psIter3->eType == CXT_Text)
     337             :                             {
     338           4 :                                 OGRFieldDefn oFieldDefn2(osName2, OFTString);
     339           2 :                                 m_poFeatureDefn->AddFieldDefn(&oFieldDefn2);
     340             :                             }
     341             :                         }
     342             :                     }
     343             :                 }
     344             : 
     345             :                 int *panRemap = static_cast<int *>(
     346          12 :                     CPLMalloc(sizeof(int) * m_poFeatureDefn->GetFieldCount()));
     347         122 :                 for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); ++i)
     348             :                 {
     349         110 :                     if (i < nValidFields)
     350          94 :                         panRemap[i] = i;
     351             :                     else
     352          16 :                         panRemap[i] = -1;
     353             :                 }
     354             : 
     355          24 :                 for (size_t i = 0; i < apoFeatures.size(); i++)
     356             :                 {
     357          12 :                     apoFeatures[i]->RemapFields(nullptr, panRemap);
     358             :                 }
     359             : 
     360          12 :                 CPLFree(panRemap);
     361             :             }
     362             :         }
     363             :     }
     364           4 : }
     365             : 
     366             : /************************************************************************/
     367             : /*                             SetSWEValue()                            */
     368             : /************************************************************************/
     369             : 
     370           8 : static void SetSWEValue(OGRFeature *poFeature, const CPLString &osFieldName,
     371             :                         const char *pszValue)
     372             : {
     373           8 :     int iField = poFeature->GetDefnRef()->GetFieldIndex(osFieldName);
     374           8 :     OGRFieldDefn *poFieldDefn = poFeature->GetFieldDefnRef(iField);
     375           8 :     OGRFieldType eType(poFieldDefn->GetType());
     376           8 :     OGRFieldSubType eSubType(poFieldDefn->GetSubType());
     377           8 :     if (eType == OFTInteger && eSubType == OFSTBoolean)
     378             :     {
     379           1 :         poFeature->SetField(
     380           1 :             iField, EQUAL(pszValue, "1") || EQUAL(pszValue, "True") ? 1 : 0);
     381             :     }
     382             :     else
     383             :     {
     384           7 :         poFeature->SetField(iField, pszValue);
     385             :     }
     386           8 : }
     387             : 
     388             : /************************************************************************/
     389             : /*                    ProcessDataRecordFillFeature()                    */
     390             : /************************************************************************/
     391             : 
     392           1 : void OGRGMLASLayer::ProcessDataRecordFillFeature(CPLXMLNode *psDataRecord,
     393             :                                                  OGRFeature *poFeature)
     394             : {
     395          14 :     for (CPLXMLNode *psIter = psDataRecord->psChild; psIter != nullptr;
     396          13 :          psIter = psIter->psNext)
     397             :     {
     398          13 :         if (psIter->eType == CXT_Element &&
     399           6 :             strcmp(psIter->pszValue, "field") == 0)
     400             :         {
     401           6 :             const char *pszName = CPLGetXMLValue(psIter, "name", "");
     402           6 :             CPLString osName = CPLString(pszName).tolower();
     403           6 :             OGRFieldDefn oFieldDefn(osName, OFTString);
     404             :             OGRFieldType eType;
     405             :             OGRFieldSubType eSubType;
     406             :             CPLXMLNode *psChildNode =
     407           6 :                 GetSWEChildAndType(psIter, eType, eSubType);
     408           6 :             oFieldDefn.SetType(eType);
     409           6 :             oFieldDefn.SetSubType(eSubType);
     410           6 :             if (psChildNode == nullptr)
     411           0 :                 continue;
     412           6 :             const auto oIter = m_oMapSWEFieldToOGRFieldName.find(osName);
     413           6 :             CPLAssert(oIter != m_oMapSWEFieldToOGRFieldName.end());
     414           6 :             osName = oIter->second;
     415          34 :             for (CPLXMLNode *psIter2 = psChildNode->psChild; psIter2 != nullptr;
     416          28 :                  psIter2 = psIter2->psNext)
     417             :             {
     418          28 :                 if (psIter2->eType == CXT_Element)
     419             :                 {
     420             :                     const CPLString osName2 =
     421          24 :                         CPLString(osName + "_" + psIter2->pszValue).tolower();
     422           8 :                     for (CPLXMLNode *psIter3 = psIter2->psChild;
     423          16 :                          psIter3 != nullptr; psIter3 = psIter3->psNext)
     424             :                     {
     425           8 :                         if (psIter3->eType == CXT_Attribute)
     426             :                         {
     427           1 :                             const char *pszValue = psIter3->pszValue;
     428           1 :                             const char *pszColon = strchr(pszValue, ':');
     429           1 :                             if (pszColon)
     430           1 :                                 pszValue = pszColon + 1;
     431           1 :                             SetSWEValue(
     432             :                                 poFeature,
     433           1 :                                 CPLString(osName2 + "_" + pszValue).tolower(),
     434           1 :                                 psIter3->psChild->pszValue);
     435             :                         }
     436           7 :                         else if (psIter3->eType == CXT_Text)
     437             :                         {
     438           7 :                             SetSWEValue(poFeature, osName2, psIter3->pszValue);
     439             :                         }
     440             :                     }
     441             :                 }
     442             :             }
     443             :         }
     444             :     }
     445           1 : }
     446             : 
     447             : /************************************************************************/
     448             : /*                             PostInit()                               */
     449             : /************************************************************************/
     450             : 
     451       15271 : void OGRGMLASLayer::PostInit(bool bIncludeGeometryXML)
     452             : {
     453       15271 :     const std::vector<GMLASField> &oFields = m_oFC.GetFields();
     454             : 
     455       15271 :     OGRLayer *poFieldsMetadataLayer = m_poDS->GetFieldsMetadataLayer();
     456       15271 :     OGRLayer *poRelationshipsLayer = m_poDS->GetRelationshipsLayer();
     457             : 
     458             :     // Is it a junction table ?
     459       15271 :     if (!m_oFC.GetParentXPath().empty())
     460             :     {
     461             :         {
     462       17728 :             OGRFieldDefn oFieldDefn(szOCCURRENCE, OFTInteger);
     463        8864 :             oFieldDefn.SetNullable(false);
     464        8864 :             m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
     465             : 
     466             :             OGRFeature *poFieldDescFeature =
     467        8864 :                 new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
     468        8864 :             poFieldDescFeature->SetField(szLAYER_NAME, GetName());
     469        8864 :             poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
     470        8864 :             CPL_IGNORE_RET_VAL(
     471        8864 :                 poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
     472        8864 :             delete poFieldDescFeature;
     473             :         }
     474             : 
     475             :         {
     476       17728 :             OGRFieldDefn oFieldDefn(szPARENT_PKID, OFTString);
     477        8864 :             oFieldDefn.SetNullable(false);
     478        8864 :             m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
     479             : 
     480             :             OGRFeature *poFieldDescFeature =
     481        8864 :                 new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
     482        8864 :             poFieldDescFeature->SetField(szLAYER_NAME, GetName());
     483        8864 :             poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
     484        8864 :             CPL_IGNORE_RET_VAL(
     485        8864 :                 poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
     486        8864 :             delete poFieldDescFeature;
     487             :         }
     488             :         {
     489       17728 :             OGRFieldDefn oFieldDefn(szCHILD_PKID, OFTString);
     490        8864 :             oFieldDefn.SetNullable(false);
     491        8864 :             m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
     492             : 
     493             :             OGRFeature *poFieldDescFeature =
     494        8864 :                 new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
     495        8864 :             poFieldDescFeature->SetField(szLAYER_NAME, GetName());
     496        8864 :             poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
     497        8864 :             CPL_IGNORE_RET_VAL(
     498        8864 :                 poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
     499        8864 :             delete poFieldDescFeature;
     500             :         }
     501             : 
     502        8864 :         return;
     503             :     }
     504             : 
     505             :     // If we are a child class, then add a field to reference the parent.
     506        6407 :     if (m_poParentLayer != nullptr)
     507             :     {
     508        6618 :         CPLString osFieldName(szPARENT_PREFIX);
     509        3309 :         osFieldName += m_poParentLayer->GetLayerDefn()
     510        3309 :                            ->GetFieldDefn(m_poParentLayer->GetIDFieldIdx())
     511        3309 :                            ->GetNameRef();
     512        6618 :         OGRFieldDefn oFieldDefn(osFieldName, OFTString);
     513        3309 :         oFieldDefn.SetNullable(false);
     514        3309 :         m_nParentIDFieldIdx = m_poFeatureDefn->GetFieldCount();
     515        3309 :         m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
     516             :     }
     517             : 
     518        6407 :     int nFieldIndex = 0;
     519      194062 :     for (int i = 0; i < static_cast<int>(oFields.size()); i++)
     520             :     {
     521      187655 :         OGRGMLASLayer *poRelatedLayer = nullptr;
     522      187655 :         const GMLASField &oField(oFields[i]);
     523             : 
     524      187655 :         m_oMapFieldXPathToFCFieldIdx[oField.GetXPath()] = i;
     525      187655 :         if (oField.IsIgnored())
     526       13857 :             continue;
     527             : 
     528      187645 :         const GMLASField::Category eCategory(oField.GetCategory());
     529      187645 :         if (!oField.GetRelatedClassXPath().empty())
     530             :         {
     531             :             poRelatedLayer =
     532       19471 :                 m_poDS->GetLayerByXPath(oField.GetRelatedClassXPath());
     533       19471 :             if (poRelatedLayer != nullptr)
     534             :             {
     535             :                 OGRFeature *poRelationshipsFeature =
     536       18308 :                     new OGRFeature(poRelationshipsLayer->GetLayerDefn());
     537       18308 :                 poRelationshipsFeature->SetField(szPARENT_LAYER, GetName());
     538       18308 :                 poRelationshipsFeature->SetField(
     539       18308 :                     szPARENT_PKID, GetLayerDefn()
     540       18308 :                                        ->GetFieldDefn(GetIDFieldIdx())
     541             :                                        ->GetNameRef());
     542       18308 :                 if (!oField.GetName().empty())
     543             :                 {
     544       18090 :                     poRelationshipsFeature->SetField(szPARENT_ELEMENT_NAME,
     545       18090 :                                                      oField.GetName());
     546             :                 }
     547       18308 :                 poRelationshipsFeature->SetField(szCHILD_LAYER,
     548             :                                                  poRelatedLayer->GetName());
     549       18308 :                 if (eCategory ==
     550        9474 :                         GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE ||
     551             :                     eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_WITH_LINK)
     552             :                 {
     553       14999 :                     poRelationshipsFeature->SetField(
     554             :                         szCHILD_PKID,
     555       14999 :                         poRelatedLayer->GetLayerDefn()
     556       14999 :                             ->GetFieldDefn(poRelatedLayer->GetIDFieldIdx())
     557             :                             ->GetNameRef());
     558             :                 }
     559             :                 else
     560             :                 {
     561        3309 :                     CPLAssert(eCategory ==
     562             :                                   GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK ||
     563             :                               eCategory == GMLASField::GROUP);
     564             : 
     565        3309 :                     poRelationshipsFeature->SetField(
     566        6618 :                         szCHILD_PKID, (CPLString(szPARENT_PREFIX) +
     567        3309 :                                        GetLayerDefn()
     568        3309 :                                            ->GetFieldDefn(GetIDFieldIdx())
     569             :                                            ->GetNameRef())
     570             :                                           .c_str());
     571             :                 }
     572       18308 :                 CPL_IGNORE_RET_VAL(poRelationshipsLayer->CreateFeature(
     573             :                     poRelationshipsFeature));
     574       18308 :                 delete poRelationshipsFeature;
     575             :             }
     576             :             else
     577             :             {
     578        1163 :                 CPLDebug("GMLAS", "Cannot find class matching %s",
     579        1163 :                          oField.GetRelatedClassXPath().c_str());
     580             :             }
     581             :         }
     582             : 
     583             :         OGRFeature *poFieldDescFeature =
     584      187645 :             new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
     585      187645 :         poFieldDescFeature->SetField(szLAYER_NAME, GetName());
     586             : 
     587      187645 :         ++nFieldIndex;
     588      187645 :         m_nMaxFieldIndex = nFieldIndex;
     589      187645 :         poFieldDescFeature->SetField(szFIELD_INDEX, nFieldIndex);
     590             : 
     591      187645 :         if (oField.GetName().empty())
     592             :         {
     593         218 :             CPLAssert(eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK ||
     594             :                       eCategory == GMLASField::GROUP);
     595             :         }
     596             :         else
     597             :         {
     598      187427 :             poFieldDescFeature->SetField(szFIELD_NAME,
     599      187427 :                                          oField.GetName().c_str());
     600             :         }
     601      187645 :         if (!oField.GetXPath().empty())
     602             :         {
     603      187391 :             poFieldDescFeature->SetField(szFIELD_XPATH,
     604      187391 :                                          oField.GetXPath().c_str());
     605             :         }
     606         254 :         else if (!oField.GetAlternateXPaths().empty())
     607             :         {
     608         166 :             CPLString osXPath;
     609             :             const std::vector<CPLString> &aoXPaths =
     610          83 :                 oField.GetAlternateXPaths();
     611         818 :             for (size_t j = 0; j < aoXPaths.size(); j++)
     612             :             {
     613         735 :                 if (j != 0)
     614         652 :                     osXPath += ",";
     615         735 :                 osXPath += aoXPaths[j];
     616             :             }
     617          83 :             poFieldDescFeature->SetField(szFIELD_XPATH, osXPath.c_str());
     618             :         }
     619      187645 :         if (oField.GetTypeName().empty())
     620             :         {
     621       13306 :             CPLAssert(
     622             :                 eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK ||
     623             :                 eCategory ==
     624             :                     GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE ||
     625             :                 eCategory == GMLASField::GROUP);
     626             :         }
     627             :         else
     628             :         {
     629      174339 :             poFieldDescFeature->SetField(szFIELD_TYPE,
     630      174339 :                                          oField.GetTypeName().c_str());
     631             :         }
     632      187645 :         poFieldDescFeature->SetField(szFIELD_IS_LIST,
     633      187645 :                                      static_cast<int>(oField.IsList()));
     634      187645 :         if (oField.GetMinOccurs() != -1)
     635             :         {
     636      187456 :             poFieldDescFeature->SetField(szFIELD_MIN_OCCURS,
     637             :                                          oField.GetMinOccurs());
     638             :         }
     639      187645 :         if (oField.GetMaxOccurs() == MAXOCCURS_UNLIMITED)
     640             :         {
     641       12731 :             poFieldDescFeature->SetField(szFIELD_MAX_OCCURS, INT_MAX);
     642             :         }
     643      174914 :         else if (oField.GetMaxOccurs() != -1)
     644             :         {
     645      174678 :             poFieldDescFeature->SetField(szFIELD_MAX_OCCURS,
     646             :                                          oField.GetMaxOccurs());
     647             :         }
     648      362559 :         if (oField.GetMaxOccurs() == MAXOCCURS_UNLIMITED ||
     649      174914 :             oField.GetMaxOccurs() > 1)
     650             :         {
     651       14374 :             poFieldDescFeature->SetField(szFIELD_REPETITION_ON_SEQUENCE,
     652       14374 :                                          oField.GetRepetitionOnSequence() ? 1
     653             :                                                                           : 0);
     654             :         }
     655      187645 :         if (!oField.GetFixedValue().empty())
     656             :         {
     657         415 :             poFieldDescFeature->SetField(szFIELD_FIXED_VALUE,
     658         415 :                                          oField.GetFixedValue());
     659             :         }
     660      187645 :         if (!oField.GetDefaultValue().empty())
     661             :         {
     662         221 :             poFieldDescFeature->SetField(szFIELD_DEFAULT_VALUE,
     663         221 :                                          oField.GetDefaultValue());
     664             :         }
     665      187645 :         switch (eCategory)
     666             :         {
     667      168174 :             case GMLASField::REGULAR:
     668      168174 :                 poFieldDescFeature->SetField(szFIELD_CATEGORY, szREGULAR);
     669      168174 :                 break;
     670        4307 :             case GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK:
     671        4307 :                 poFieldDescFeature->SetField(szFIELD_CATEGORY,
     672             :                                              szPATH_TO_CHILD_ELEMENT_NO_LINK);
     673        4307 :                 break;
     674        6165 :             case GMLASField::PATH_TO_CHILD_ELEMENT_WITH_LINK:
     675        6165 :                 poFieldDescFeature->SetField(szFIELD_CATEGORY,
     676             :                                              szPATH_TO_CHILD_ELEMENT_WITH_LINK);
     677        6165 :                 break;
     678        8834 :             case GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE:
     679        8834 :                 poFieldDescFeature->SetField(
     680             :                     szFIELD_CATEGORY,
     681             :                     szPATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE);
     682        8834 :                 break;
     683         165 :             case GMLASField::GROUP:
     684         165 :                 poFieldDescFeature->SetField(szFIELD_CATEGORY, szGROUP);
     685         165 :                 break;
     686           0 :             default:
     687           0 :                 CPLAssert(FALSE);
     688             :                 break;
     689             :         }
     690      187645 :         if (poRelatedLayer != nullptr)
     691             :         {
     692       18308 :             poFieldDescFeature->SetField(szFIELD_RELATED_LAYER,
     693             :                                          poRelatedLayer->GetName());
     694             :         }
     695             : 
     696      187645 :         if (eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE)
     697             :         {
     698             :             const CPLString &osAbstractElementXPath(
     699        8834 :                 oField.GetAbstractElementXPath());
     700        8834 :             const CPLString &osNestedXPath(oField.GetRelatedClassXPath());
     701        8834 :             CPLAssert(!osAbstractElementXPath.empty());
     702        8834 :             CPLAssert(!osNestedXPath.empty());
     703             : 
     704        8834 :             OGRGMLASLayer *poJunctionLayer = m_poDS->GetLayerByXPath(
     705       17668 :                 osAbstractElementXPath + "|" + osNestedXPath);
     706        8834 :             if (poJunctionLayer != nullptr)
     707             :             {
     708        8834 :                 poFieldDescFeature->SetField(szFIELD_JUNCTION_LAYER,
     709             :                                              poJunctionLayer->GetName());
     710             :             }
     711             :         }
     712             : 
     713      187645 :         if (!oField.GetDocumentation().empty())
     714             :         {
     715      141878 :             poFieldDescFeature->SetField(szFIELD_DOCUMENTATION,
     716      141878 :                                          oField.GetDocumentation());
     717             :         }
     718             : 
     719      187645 :         CPL_IGNORE_RET_VAL(
     720      187645 :             poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
     721      187645 :         delete poFieldDescFeature;
     722             : 
     723             :         // Check whether the field is OGR instanciable
     724      187645 :         if (eCategory == GMLASField::PATH_TO_CHILD_ELEMENT_NO_LINK ||
     725             :             eCategory ==
     726      174504 :                 GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE ||
     727             :             eCategory == GMLASField::GROUP)
     728             :         {
     729       13306 :             continue;
     730             :         }
     731             : 
     732      174339 :         OGRFieldType eType = OFTString;
     733      174339 :         OGRFieldSubType eSubType = OFSTNone;
     734      174339 :         CPLString osOGRFieldName(oField.GetName());
     735      174339 :         switch (oField.GetType())
     736             :         {
     737      112983 :             case GMLAS_FT_STRING:
     738      112983 :                 eType = OFTString;
     739      112983 :                 break;
     740        6017 :             case GMLAS_FT_ID:
     741             :             {
     742        6017 :                 eType = OFTString;
     743        6017 :                 if (oField.IsNotNullable())
     744             :                 {
     745         209 :                     continue;
     746             :                 }
     747        5808 :                 break;
     748             :             }
     749        1235 :             case GMLAS_FT_BOOLEAN:
     750        1235 :                 eType = OFTInteger;
     751        1235 :                 eSubType = OFSTBoolean;
     752        1235 :                 break;
     753          47 :             case GMLAS_FT_SHORT:
     754          47 :                 eType = OFTInteger;
     755          47 :                 eSubType = OFSTInt16;
     756          47 :                 break;
     757        1932 :             case GMLAS_FT_INT32:
     758        1932 :                 eType = OFTInteger;
     759        1932 :                 break;
     760       19179 :             case GMLAS_FT_INT64:
     761       19179 :                 eType = OFTInteger64;
     762       19179 :                 break;
     763          94 :             case GMLAS_FT_FLOAT:
     764          94 :                 eType = OFTReal;
     765          94 :                 eSubType = OFSTFloat32;
     766          94 :                 break;
     767       28925 :             case GMLAS_FT_DOUBLE:
     768       28925 :                 eType = OFTReal;
     769       28925 :                 break;
     770          53 :             case GMLAS_FT_DECIMAL:
     771          53 :                 eType = OFTReal;
     772          53 :                 break;
     773          47 :             case GMLAS_FT_DATE:
     774          47 :                 eType = OFTDate;
     775          47 :                 break;
     776           0 :             case GMLAS_FT_GYEAR:
     777           0 :                 eType = OFTInteger;
     778           0 :                 break;
     779           0 :             case GMLAS_FT_GYEAR_MONTH:
     780           0 :                 eType = OFTDate;
     781           0 :                 break;
     782          47 :             case GMLAS_FT_TIME:
     783          47 :                 eType = OFTTime;
     784          47 :                 break;
     785         355 :             case GMLAS_FT_DATETIME:
     786         355 :                 eType = OFTDateTime;
     787         355 :                 break;
     788          94 :             case GMLAS_FT_BASE64BINARY:
     789             :             case GMLAS_FT_HEXBINARY:
     790          94 :                 eType = OFTBinary;
     791          94 :                 break;
     792        1767 :             case GMLAS_FT_ANYURI:
     793        1767 :                 eType = OFTString;
     794        1767 :                 break;
     795         498 :             case GMLAS_FT_ANYTYPE:
     796         498 :                 eType = OFTString;
     797         498 :                 break;
     798         702 :             case GMLAS_FT_ANYSIMPLETYPE:
     799         702 :                 eType = OFTString;
     800         702 :                 break;
     801         364 :             case GMLAS_FT_GEOMETRY:
     802             :             {
     803             :                 // Create a geometry field
     804             :                 OGRGeomFieldDefn oGeomFieldDefn(osOGRFieldName,
     805         728 :                                                 oField.GetGeomType());
     806         364 :                 m_poFeatureDefn->AddGeomFieldDefn(&oGeomFieldDefn);
     807             : 
     808             :                 const int iOGRGeomIdx =
     809         364 :                     m_poFeatureDefn->GetGeomFieldCount() - 1;
     810         364 :                 if (!oField.GetXPath().empty())
     811             :                 {
     812         333 :                     m_oMapFieldXPathToOGRGeomFieldIdx[oField.GetXPath()] =
     813             :                         iOGRGeomIdx;
     814             :                 }
     815             :                 else
     816             :                 {
     817             :                     const std::vector<CPLString> &aoXPaths =
     818          31 :                         oField.GetAlternateXPaths();
     819         668 :                     for (size_t j = 0; j < aoXPaths.size(); j++)
     820             :                     {
     821         637 :                         m_oMapFieldXPathToOGRGeomFieldIdx[aoXPaths[j]] =
     822             :                             iOGRGeomIdx;
     823             :                     }
     824             :                 }
     825             : 
     826         364 :                 m_oMapOGRGeomFieldIdxtoFCFieldIdx[iOGRGeomIdx] = i;
     827             : 
     828             :                 // Suffix the regular non-geometry field
     829         364 :                 osOGRFieldName += szXML_SUFFIX;
     830         364 :                 eType = OFTString;
     831         364 :                 break;
     832             :             }
     833           0 :             default:
     834           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     835           0 :                          "Unhandled type in enum: %d", oField.GetType());
     836           0 :                 break;
     837             :         }
     838             : 
     839      174130 :         if (oField.GetType() == GMLAS_FT_GEOMETRY && !bIncludeGeometryXML)
     840             :         {
     841         332 :             continue;
     842             :         }
     843             : 
     844      173798 :         if (oField.IsArray())
     845             :         {
     846        3611 :             switch (eType)
     847             :             {
     848        3097 :                 case OFTString:
     849        3097 :                     eType = OFTStringList;
     850        3097 :                     break;
     851         282 :                 case OFTInteger:
     852         282 :                     eType = OFTIntegerList;
     853         282 :                     break;
     854          94 :                 case OFTInteger64:
     855          94 :                     eType = OFTInteger64List;
     856          94 :                     break;
     857         138 :                 case OFTReal:
     858         138 :                     eType = OFTRealList;
     859         138 :                     break;
     860           0 :                 default:
     861           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     862             :                              "Unhandled type in enum: %d", eType);
     863           0 :                     break;
     864             :             }
     865             :         }
     866      347596 :         OGRFieldDefn oFieldDefn(osOGRFieldName, eType);
     867      173798 :         oFieldDefn.SetSubType(eSubType);
     868      173798 :         if (oField.IsNotNullable())
     869       35922 :             oFieldDefn.SetNullable(false);
     870      347596 :         CPLString osDefaultOrFixed = oField.GetDefaultValue();
     871      173798 :         if (osDefaultOrFixed.empty())
     872      173577 :             osDefaultOrFixed = oField.GetFixedValue();
     873      173798 :         if (!osDefaultOrFixed.empty())
     874             :         {
     875         636 :             char *pszEscaped = CPLEscapeString(osDefaultOrFixed, -1, CPLES_SQL);
     876         636 :             oFieldDefn.SetDefault(
     877        1272 :                 (CPLString("'") + pszEscaped + CPLString("'")).c_str());
     878         636 :             CPLFree(pszEscaped);
     879             :         }
     880      173798 :         oFieldDefn.SetWidth(oField.GetWidth());
     881      173798 :         m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
     882             : 
     883      173798 :         const int iOGRIdx = m_poFeatureDefn->GetFieldCount() - 1;
     884      173798 :         if (!oField.GetXPath().empty())
     885             :         {
     886      173738 :             m_oMapFieldXPathToOGRFieldIdx[oField.GetXPath()] = iOGRIdx;
     887             :         }
     888             :         else
     889             :         {
     890             :             const std::vector<CPLString> &aoXPaths =
     891          60 :                 oField.GetAlternateXPaths();
     892         162 :             for (size_t j = 0; j < aoXPaths.size(); j++)
     893             :             {
     894         102 :                 m_oMapFieldXPathToOGRFieldIdx[aoXPaths[j]] = iOGRIdx;
     895             :             }
     896             :         }
     897             : 
     898      173798 :         m_oMapOGRFieldIdxtoFCFieldIdx[iOGRIdx] = i;
     899             : 
     900             :         // Create field to receive resolved xlink:href content, if needed
     901      173798 :         if (oField.GetXPath().find(szAT_XLINK_HREF) != std::string::npos &&
     902      173810 :             m_poDS->GetConf().m_oXLinkResolution.m_bDefaultResolutionEnabled &&
     903          12 :             m_poDS->GetConf().m_oXLinkResolution.m_eDefaultResolutionMode ==
     904             :                 GMLASXLinkResolutionConf::RawContent)
     905             :         {
     906          24 :             CPLString osRawContentFieldname(osOGRFieldName);
     907          12 :             size_t nPos = osRawContentFieldname.find(szHREF_SUFFIX);
     908          12 :             if (nPos != std::string::npos)
     909          12 :                 osRawContentFieldname.resize(nPos);
     910          12 :             osRawContentFieldname += szRAW_CONTENT_SUFFIX;
     911          12 :             OGRFieldDefn oFieldDefnRaw(osRawContentFieldname, OFTString);
     912          12 :             m_poFeatureDefn->AddFieldDefn(&oFieldDefnRaw);
     913             : 
     914             :             m_oMapFieldXPathToOGRFieldIdx
     915          24 :                 [GMLASField::MakeXLinkRawContentFieldXPathFromXLinkHrefXPath(
     916          24 :                     oField.GetXPath())] = m_poFeatureDefn->GetFieldCount() - 1;
     917             :         }
     918             : 
     919      173798 :         CPL_IGNORE_RET_VAL(osOGRFieldName);
     920             :     }
     921             : 
     922        6407 :     CreateCompoundFoldedMappings();
     923             : }
     924             : 
     925             : /************************************************************************/
     926             : /*                   CreateCompoundFoldedMappings()                     */
     927             : /************************************************************************/
     928             : 
     929             : // In the case we have nested elements but we managed to fold into top
     930             : // level class, then register intermediate paths so they are not reported
     931             : // as unexpected in debug traces
     932        6408 : void OGRGMLASLayer::CreateCompoundFoldedMappings()
     933             : {
     934       12816 :     CPLString oFCXPath(m_oFC.GetXPath());
     935        6408 :     if (m_oFC.IsRepeatedSequence())
     936             :     {
     937         313 :         size_t iPosExtra = oFCXPath.find(szEXTRA_SUFFIX);
     938         313 :         if (iPosExtra != std::string::npos)
     939             :         {
     940         218 :             oFCXPath.resize(iPosExtra);
     941             :         }
     942             :     }
     943             : 
     944        6408 :     const std::vector<GMLASField> &oFields = m_oFC.GetFields();
     945      194071 :     for (size_t i = 0; i < oFields.size(); i++)
     946             :     {
     947      375326 :         std::vector<CPLString> aoXPaths = oFields[i].GetAlternateXPaths();
     948      187663 :         if (aoXPaths.empty())
     949      187580 :             aoXPaths.push_back(oFields[i].GetXPath());
     950      375978 :         for (size_t j = 0; j < aoXPaths.size(); j++)
     951             :         {
     952      188315 :             if (aoXPaths[j].size() > oFCXPath.size())
     953             :             {
     954             :                 // Split on both '/' and '@'
     955      375356 :                 char **papszTokens = CSLTokenizeString2(
     956      187678 :                     aoXPaths[j].c_str() + oFCXPath.size() + 1, "/@", 0);
     957      375356 :                 CPLString osSubXPath = oFCXPath;
     958      590935 :                 for (int k = 0;
     959      590935 :                      papszTokens[k] != nullptr && papszTokens[k + 1] != nullptr;
     960             :                      k++)
     961             :                 {
     962      403257 :                     osSubXPath += "/";
     963      403257 :                     osSubXPath += papszTokens[k];
     964      403257 :                     if (m_oMapFieldXPathToOGRFieldIdx.find(osSubXPath) ==
     965      806514 :                         m_oMapFieldXPathToOGRFieldIdx.end())
     966             :                     {
     967       22276 :                         m_oMapFieldXPathToOGRFieldIdx[osSubXPath] =
     968             :                             IDX_COMPOUND_FOLDED;
     969             :                     }
     970             :                 }
     971      187678 :                 CSLDestroy(papszTokens);
     972             :             }
     973             :         }
     974             :     }
     975        6408 : }
     976             : 
     977             : /************************************************************************/
     978             : /*                           ~OGRGMLASLayer()                           */
     979             : /************************************************************************/
     980             : 
     981       30548 : OGRGMLASLayer::~OGRGMLASLayer()
     982             : {
     983       15274 :     m_poFeatureDefn->Release();
     984       30548 : }
     985             : 
     986             : /************************************************************************/
     987             : /*                        DeleteTargetIndex()                           */
     988             : /************************************************************************/
     989             : 
     990           4 : static void DeleteTargetIndex(std::map<CPLString, int> &oMap, int nIdx)
     991             : {
     992           4 :     bool bIterToRemoveValid = false;
     993           4 :     std::map<CPLString, int>::iterator oIterToRemove;
     994           4 :     std::map<CPLString, int>::iterator oIter = oMap.begin();
     995          26 :     for (; oIter != oMap.end(); ++oIter)
     996             :     {
     997          22 :         if (oIter->second > nIdx)
     998          10 :             oIter->second--;
     999          12 :         else if (oIter->second == nIdx)
    1000             :         {
    1001           4 :             bIterToRemoveValid = true;
    1002           4 :             oIterToRemove = oIter;
    1003             :         }
    1004             :     }
    1005           4 :     if (bIterToRemoveValid)
    1006           4 :         oMap.erase(oIterToRemove);
    1007           4 : }
    1008             : 
    1009             : /************************************************************************/
    1010             : /*                            RemoveField()                             */
    1011             : /************************************************************************/
    1012             : 
    1013           4 : bool OGRGMLASLayer::RemoveField(int nIdx)
    1014             : {
    1015           4 :     if (nIdx == m_nIDFieldIdx || nIdx == m_nParentIDFieldIdx)
    1016           0 :         return false;
    1017             : 
    1018           4 :     m_poFeatureDefn->DeleteFieldDefn(nIdx);
    1019             : 
    1020             :     // Refresh maps
    1021           4 :     DeleteTargetIndex(m_oMapFieldXPathToOGRFieldIdx, nIdx);
    1022             : 
    1023             :     {
    1024           8 :         std::map<int, int> oMapOGRFieldIdxtoFCFieldIdx;
    1025          26 :         for (const auto &oIter : m_oMapOGRFieldIdxtoFCFieldIdx)
    1026             :         {
    1027          22 :             if (oIter.first < nIdx)
    1028           8 :                 oMapOGRFieldIdxtoFCFieldIdx[oIter.first] = oIter.second;
    1029          14 :             else if (oIter.first > nIdx)
    1030          10 :                 oMapOGRFieldIdxtoFCFieldIdx[oIter.first - 1] = oIter.second;
    1031             :         }
    1032           4 :         m_oMapOGRFieldIdxtoFCFieldIdx = std::move(oMapOGRFieldIdxtoFCFieldIdx);
    1033             :     }
    1034             : 
    1035           4 :     OGRLayer *poFieldsMetadataLayer = m_poDS->GetFieldsMetadataLayer();
    1036             :     OGRFeature *poFeature;
    1037           4 :     poFieldsMetadataLayer->ResetReading();
    1038          27 :     while ((poFeature = poFieldsMetadataLayer->GetNextFeature()) != nullptr)
    1039             :     {
    1040          44 :         if (strcmp(poFeature->GetFieldAsString(szLAYER_NAME), GetName()) == 0 &&
    1041          18 :             poFeature->GetFieldAsInteger(szFIELD_INDEX) == nIdx)
    1042             :         {
    1043           3 :             poFeature->SetField(szFIELD_INDEX, -1);
    1044           3 :             CPL_IGNORE_RET_VAL(poFieldsMetadataLayer->SetFeature(poFeature));
    1045           3 :             delete poFeature;
    1046           3 :             break;
    1047             :         }
    1048          23 :         delete poFeature;
    1049             :     }
    1050           4 :     poFieldsMetadataLayer->ResetReading();
    1051             : 
    1052           4 :     return true;
    1053             : }
    1054             : 
    1055             : /************************************************************************/
    1056             : /*                        InsertTargetIndex()                           */
    1057             : /************************************************************************/
    1058             : 
    1059          22 : static void InsertTargetIndex(std::map<CPLString, int> &oMap, int nIdx)
    1060             : {
    1061         271 :     for (auto &oIter : oMap)
    1062             :     {
    1063         249 :         if (oIter.second >= nIdx)
    1064          43 :             oIter.second++;
    1065             :     }
    1066          22 : }
    1067             : 
    1068             : /************************************************************************/
    1069             : /*                            InsertNewField()                          */
    1070             : /************************************************************************/
    1071             : 
    1072          22 : void OGRGMLASLayer::InsertNewField(int nInsertPos,
    1073             :                                    const OGRFieldDefn &oFieldDefn,
    1074             :                                    const CPLString &osXPath)
    1075             : {
    1076          22 :     CPLAssert(nInsertPos >= 0 &&
    1077             :               nInsertPos <= m_poFeatureDefn->GetFieldCount());
    1078          22 :     m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
    1079          22 :     int *panMap = new int[m_poFeatureDefn->GetFieldCount()];
    1080         204 :     for (int i = 0; i < nInsertPos; ++i)
    1081             :     {
    1082         182 :         panMap[i] = i;
    1083             :     }
    1084          22 :     panMap[nInsertPos] = m_poFeatureDefn->GetFieldCount() - 1;
    1085          65 :     for (int i = nInsertPos + 1; i < m_poFeatureDefn->GetFieldCount(); ++i)
    1086             :     {
    1087          43 :         panMap[i] = i - 1;
    1088             :     }
    1089          22 :     m_poFeatureDefn->ReorderFieldDefns(panMap);
    1090          22 :     delete[] panMap;
    1091             : 
    1092             :     // Refresh maps
    1093          22 :     InsertTargetIndex(m_oMapFieldXPathToOGRFieldIdx, nInsertPos);
    1094          22 :     m_oMapFieldXPathToOGRFieldIdx[osXPath] = nInsertPos;
    1095             : 
    1096             :     {
    1097          44 :         std::map<int, int> oMapOGRFieldIdxtoFCFieldIdx;
    1098         152 :         for (const auto &oIter : m_oMapOGRFieldIdxtoFCFieldIdx)
    1099             :         {
    1100         130 :             if (oIter.first < nInsertPos)
    1101          87 :                 oMapOGRFieldIdxtoFCFieldIdx[oIter.first] = oIter.second;
    1102             :             else
    1103          43 :                 oMapOGRFieldIdxtoFCFieldIdx[oIter.first + 1] = oIter.second;
    1104             :         }
    1105          22 :         m_oMapOGRFieldIdxtoFCFieldIdx = std::move(oMapOGRFieldIdxtoFCFieldIdx);
    1106             :     }
    1107             : 
    1108          22 :     OGRLayer *poFieldsMetadataLayer = m_poDS->GetFieldsMetadataLayer();
    1109             :     OGRFeature *poFeature;
    1110          22 :     poFieldsMetadataLayer->ResetReading();
    1111         165 :     while ((poFeature = poFieldsMetadataLayer->GetNextFeature()) != nullptr)
    1112             :     {
    1113         143 :         if (strcmp(poFeature->GetFieldAsString(szLAYER_NAME), GetName()) == 0)
    1114             :         {
    1115         131 :             int nFieldIndex = poFeature->GetFieldAsInteger(szFIELD_INDEX);
    1116         131 :             if (nFieldIndex >= nInsertPos && nFieldIndex < INT_MAX)
    1117             :             {
    1118          43 :                 poFeature->SetField(szFIELD_INDEX, nFieldIndex + 1);
    1119          43 :                 CPL_IGNORE_RET_VAL(
    1120          43 :                     poFieldsMetadataLayer->SetFeature(poFeature));
    1121             :             }
    1122             :         }
    1123         143 :         delete poFeature;
    1124             :     }
    1125          22 :     poFieldsMetadataLayer->ResetReading();
    1126          22 : }
    1127             : 
    1128             : /************************************************************************/
    1129             : /*                       GetOGRFieldIndexFromXPath()                    */
    1130             : /************************************************************************/
    1131             : 
    1132     1152680 : int OGRGMLASLayer::GetOGRFieldIndexFromXPath(const CPLString &osXPath) const
    1133             : {
    1134     1152680 :     const auto oIter = m_oMapFieldXPathToOGRFieldIdx.find(osXPath);
    1135     1152680 :     if (oIter == m_oMapFieldXPathToOGRFieldIdx.end())
    1136      932221 :         return -1;
    1137      220455 :     return oIter->second;
    1138             : }
    1139             : 
    1140             : /************************************************************************/
    1141             : /*                       GetXPathFromOGRFieldIndex()                    */
    1142             : /************************************************************************/
    1143             : 
    1144          14 : CPLString OGRGMLASLayer::GetXPathFromOGRFieldIndex(int nIdx) const
    1145             : {
    1146          14 :     const int nFCIdx = GetFCFieldIndexFromOGRFieldIdx(nIdx);
    1147          14 :     if (nFCIdx >= 0)
    1148          10 :         return m_oFC.GetFields()[nFCIdx].GetXPath();
    1149             : 
    1150          31 :     for (const auto &oIter : m_oMapFieldXPathToOGRFieldIdx)
    1151             :     {
    1152          28 :         if (oIter.second == nIdx)
    1153           1 :             return oIter.first;
    1154             :     }
    1155           3 :     return CPLString();
    1156             : }
    1157             : 
    1158             : /************************************************************************/
    1159             : /*                      GetOGRGeomFieldIndexFromXPath()                 */
    1160             : /************************************************************************/
    1161             : 
    1162      188883 : int OGRGMLASLayer::GetOGRGeomFieldIndexFromXPath(const CPLString &osXPath) const
    1163             : {
    1164      188883 :     const auto oIter = m_oMapFieldXPathToOGRGeomFieldIdx.find(osXPath);
    1165      188883 :     if (oIter == m_oMapFieldXPathToOGRGeomFieldIdx.end())
    1166      188439 :         return -1;
    1167         444 :     return oIter->second;
    1168             : }
    1169             : 
    1170             : /************************************************************************/
    1171             : /*                     GetFCFieldIndexFromOGRFieldIdx()                 */
    1172             : /************************************************************************/
    1173             : 
    1174     5410100 : int OGRGMLASLayer::GetFCFieldIndexFromOGRFieldIdx(int iOGRFieldIdx) const
    1175             : {
    1176     5410100 :     const auto oIter = m_oMapOGRFieldIdxtoFCFieldIdx.find(iOGRFieldIdx);
    1177     5410100 :     if (oIter == m_oMapOGRFieldIdxtoFCFieldIdx.end())
    1178      141941 :         return -1;
    1179     5268160 :     return oIter->second;
    1180             : }
    1181             : 
    1182             : /************************************************************************/
    1183             : /*                     GetFCFieldIndexFromXPath()                       */
    1184             : /************************************************************************/
    1185             : 
    1186         746 : int OGRGMLASLayer::GetFCFieldIndexFromXPath(const CPLString &osXPath) const
    1187             : {
    1188         746 :     const auto oIter = m_oMapFieldXPathToFCFieldIdx.find(osXPath);
    1189         746 :     if (oIter == m_oMapFieldXPathToFCFieldIdx.end())
    1190         251 :         return -1;
    1191         495 :     return oIter->second;
    1192             : }
    1193             : 
    1194             : /************************************************************************/
    1195             : /*                  GetFCFieldIndexFromOGRGeomFieldIdx()                */
    1196             : /************************************************************************/
    1197             : 
    1198         368 : int OGRGMLASLayer::GetFCFieldIndexFromOGRGeomFieldIdx(
    1199             :     int iOGRGeomFieldIdx) const
    1200             : {
    1201         368 :     const auto oIter = m_oMapOGRGeomFieldIdxtoFCFieldIdx.find(iOGRGeomFieldIdx);
    1202         368 :     if (oIter == m_oMapOGRGeomFieldIdxtoFCFieldIdx.end())
    1203           0 :         return -1;
    1204         368 :     return oIter->second;
    1205             : }
    1206             : 
    1207             : /************************************************************************/
    1208             : /*                 GetXPathOfFieldLinkForAttrToOtherLayer()             */
    1209             : /************************************************************************/
    1210             : 
    1211           9 : CPLString OGRGMLASLayer::GetXPathOfFieldLinkForAttrToOtherLayer(
    1212             :     const CPLString &osFieldName, const CPLString &osTargetLayerXPath)
    1213             : {
    1214           9 :     const int nOGRFieldIdx = GetLayerDefn()->GetFieldIndex(osFieldName);
    1215           9 :     CPLAssert(nOGRFieldIdx >= 0);
    1216           9 :     const int nFCFieldIdx = GetFCFieldIndexFromOGRFieldIdx(nOGRFieldIdx);
    1217           9 :     CPLAssert(nFCFieldIdx >= 0);
    1218          18 :     CPLString osXPath(m_oFC.GetFields()[nFCFieldIdx].GetXPath());
    1219           9 :     size_t nPos = osXPath.find(szAT_XLINK_HREF);
    1220           9 :     CPLAssert(nPos != std::string::npos);
    1221           9 :     CPLAssert(nPos + strlen(szAT_XLINK_HREF) == osXPath.size());
    1222          18 :     CPLString osTargetFieldXPath(osXPath.substr(0, nPos) + osTargetLayerXPath);
    1223          18 :     return osTargetFieldXPath;
    1224             : }
    1225             : 
    1226             : /************************************************************************/
    1227             : /*                           LaunderFieldName()                         */
    1228             : /************************************************************************/
    1229             : 
    1230           3 : CPLString OGRGMLASLayer::LaunderFieldName(const CPLString &osFieldName)
    1231             : {
    1232           3 :     int nCounter = 1;
    1233           3 :     CPLString osLaunderedName(osFieldName);
    1234           3 :     while (m_poFeatureDefn->GetFieldIndex(osLaunderedName) >= 0)
    1235             :     {
    1236           0 :         nCounter++;
    1237           0 :         osLaunderedName = osFieldName + CPLSPrintf("%d", nCounter);
    1238             :     }
    1239             : 
    1240           3 :     const int nIdentifierMaxLength = m_poDS->GetConf().m_nIdentifierMaxLength;
    1241           6 :     if (nIdentifierMaxLength >= MIN_VALUE_OF_MAX_IDENTIFIER_LENGTH &&
    1242           3 :         osLaunderedName.size() > static_cast<size_t>(nIdentifierMaxLength))
    1243             :     {
    1244             :         osLaunderedName =
    1245           1 :             OGRGMLASTruncateIdentifier(osLaunderedName, nIdentifierMaxLength);
    1246             :     }
    1247             : 
    1248           3 :     if (m_poDS->GetConf().m_bPGIdentifierLaundering)
    1249             :     {
    1250             :         char *pszLaundered =
    1251           3 :             OGRPGCommonLaunderName(osLaunderedName, "GMLAS", false);
    1252           3 :         osLaunderedName = pszLaundered;
    1253           3 :         CPLFree(pszLaundered);
    1254             :     }
    1255             : 
    1256           3 :     if (m_poFeatureDefn->GetFieldIndex(osLaunderedName) >= 0)
    1257             :     {
    1258           0 :         nCounter = 1;
    1259           0 :         std::string osCandidate;
    1260           0 :         do
    1261             :         {
    1262           0 :             nCounter++;
    1263           0 :             osCandidate = OGRGMLASAddSerialNumber(
    1264           0 :                 osLaunderedName, nCounter, nCounter + 1, nIdentifierMaxLength);
    1265           0 :         } while (nCounter < 100 &&
    1266           0 :                  m_poFeatureDefn->GetFieldIndex(osCandidate.c_str()) >= 0);
    1267           0 :         osLaunderedName = std::move(osCandidate);
    1268             :     }
    1269             : 
    1270           3 :     return osLaunderedName;
    1271             : }
    1272             : 
    1273             : /************************************************************************/
    1274             : /*                     CreateLinkForAttrToOtherLayer()                  */
    1275             : /************************************************************************/
    1276             : 
    1277             : /* Create a new field to contain the PKID of the feature pointed by this */
    1278             : /* osFieldName (a xlink:href attribute), when it is an internal link to */
    1279             : /* another layer whose xpath is given by osTargetLayerXPath */
    1280             : 
    1281           4 : CPLString OGRGMLASLayer::CreateLinkForAttrToOtherLayer(
    1282             :     const CPLString &osFieldName, const CPLString &osTargetLayerXPath)
    1283             : {
    1284             :     CPLString osTargetFieldXPath =
    1285           8 :         GetXPathOfFieldLinkForAttrToOtherLayer(osFieldName, osTargetLayerXPath);
    1286             :     const int nExistingTgtOGRFieldIdx =
    1287           4 :         GetOGRFieldIndexFromXPath(osTargetFieldXPath);
    1288           4 :     if (nExistingTgtOGRFieldIdx >= 0)
    1289             :     {
    1290           1 :         return GetLayerDefn()
    1291           1 :             ->GetFieldDefn(nExistingTgtOGRFieldIdx)
    1292           1 :             ->GetNameRef();
    1293             :     }
    1294             : 
    1295           3 :     const int nOGRFieldIdx = GetLayerDefn()->GetFieldIndex(osFieldName);
    1296           3 :     CPLAssert(nOGRFieldIdx >= 0);
    1297           3 :     const int nFCFieldIdx = GetFCFieldIndexFromOGRFieldIdx(nOGRFieldIdx);
    1298           3 :     CPLAssert(nFCFieldIdx >= 0);
    1299           6 :     CPLString osXPath(m_oFC.GetFields()[nFCFieldIdx].GetXPath());
    1300           3 :     size_t nPos = osXPath.find(szAT_XLINK_HREF);
    1301           6 :     CPLString osXPathStart(osXPath.substr(0, nPos));
    1302             : 
    1303             :     // Find at which position to insert the new field in the layer definition
    1304             :     // (we could happen at the end, but it will be nicer to insert close to
    1305             :     // the href field)
    1306           3 :     int nInsertPos = -1;
    1307          14 :     for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
    1308             :     {
    1309          14 :         if (GetXPathFromOGRFieldIndex(i).find(osXPathStart) == 0)
    1310             :         {
    1311           4 :             nInsertPos = i + 1;
    1312             :         }
    1313          10 :         else if (nInsertPos >= 0)
    1314           3 :             break;
    1315             :     }
    1316             : 
    1317           6 :     CPLString osNewFieldName(osFieldName);
    1318           3 :     nPos = osFieldName.find(szHREF_SUFFIX);
    1319           3 :     if (nPos != std::string::npos)
    1320             :     {
    1321           3 :         osNewFieldName.resize(nPos);
    1322             :     }
    1323           3 :     osNewFieldName += "_";
    1324           3 :     OGRGMLASLayer *poTargetLayer = m_poDS->GetLayerByXPath(osTargetLayerXPath);
    1325           3 :     CPLAssert(poTargetLayer);
    1326           3 :     osNewFieldName += poTargetLayer->GetName();
    1327           3 :     osNewFieldName += "_pkid";
    1328           3 :     osNewFieldName = LaunderFieldName(osNewFieldName);
    1329           6 :     OGRFieldDefn oFieldDefn(osNewFieldName, OFTString);
    1330           3 :     InsertNewField(nInsertPos, oFieldDefn, osTargetFieldXPath);
    1331             : 
    1332           3 :     OGRLayer *poFieldsMetadataLayer = m_poDS->GetFieldsMetadataLayer();
    1333           3 :     OGRLayer *poRelationshipsLayer = m_poDS->GetRelationshipsLayer();
    1334             : 
    1335             :     // Find a relevant location of the field metadata layer into which to
    1336             :     // insert the new feature (same as above, we could potentially insert just
    1337             :     // at the end)
    1338           3 :     GIntBig nFieldsMetadataIdxPos = -1;
    1339           3 :     poFieldsMetadataLayer->ResetReading();
    1340             :     OGRFeature *poFeature;
    1341          11 :     while ((poFeature = poFieldsMetadataLayer->GetNextFeature()) != nullptr)
    1342             :     {
    1343          11 :         if (strcmp(poFeature->GetFieldAsString(szLAYER_NAME), GetName()) == 0)
    1344             :         {
    1345          11 :             if (poFeature->GetFieldAsInteger(szFIELD_INDEX) > nInsertPos)
    1346             :             {
    1347           3 :                 delete poFeature;
    1348           3 :                 break;
    1349             :             }
    1350           8 :             nFieldsMetadataIdxPos = poFeature->GetFID() + 1;
    1351             :         }
    1352           0 :         else if (nFieldsMetadataIdxPos >= 0)
    1353             :         {
    1354           0 :             delete poFeature;
    1355           0 :             break;
    1356             :         }
    1357           8 :         delete poFeature;
    1358             :     }
    1359           3 :     poFieldsMetadataLayer->ResetReading();
    1360             : 
    1361             :     // Move down all features beyond that insertion point
    1362          24 :     for (GIntBig nFID = poFieldsMetadataLayer->GetFeatureCount() - 1;
    1363          24 :          nFID >= nFieldsMetadataIdxPos; nFID--)
    1364             :     {
    1365          21 :         poFeature = poFieldsMetadataLayer->GetFeature(nFID);
    1366          21 :         if (poFeature)
    1367             :         {
    1368          21 :             poFeature->SetFID(nFID + 1);
    1369          21 :             CPL_IGNORE_RET_VAL(poFieldsMetadataLayer->SetFeature(poFeature));
    1370          21 :             delete poFeature;
    1371             :         }
    1372             :     }
    1373           3 :     if (nFieldsMetadataIdxPos >= 0)
    1374             :     {
    1375           3 :         CPL_IGNORE_RET_VAL(
    1376           3 :             poFieldsMetadataLayer->DeleteFeature(nFieldsMetadataIdxPos));
    1377             :     }
    1378             : 
    1379             :     // Register field in _ogr_fields_metadata
    1380             :     OGRFeature *poFieldDescFeature =
    1381           3 :         new OGRFeature(poFieldsMetadataLayer->GetLayerDefn());
    1382           3 :     poFieldDescFeature->SetField(szLAYER_NAME, GetName());
    1383           3 :     poFieldDescFeature->SetField(szFIELD_INDEX, nInsertPos);
    1384           3 :     poFieldDescFeature->SetField(szFIELD_XPATH, osTargetFieldXPath);
    1385           3 :     poFieldDescFeature->SetField(szFIELD_NAME, oFieldDefn.GetNameRef());
    1386           3 :     poFieldDescFeature->SetField(szFIELD_TYPE, szXS_STRING);
    1387           3 :     poFieldDescFeature->SetField(szFIELD_IS_LIST, 0);
    1388           3 :     poFieldDescFeature->SetField(szFIELD_MIN_OCCURS, 0);
    1389           3 :     poFieldDescFeature->SetField(szFIELD_MAX_OCCURS, 1);
    1390           3 :     poFieldDescFeature->SetField(szFIELD_CATEGORY,
    1391             :                                  szPATH_TO_CHILD_ELEMENT_WITH_LINK);
    1392           3 :     poFieldDescFeature->SetField(szFIELD_RELATED_LAYER,
    1393             :                                  poTargetLayer->GetName());
    1394           3 :     if (nFieldsMetadataIdxPos >= 0)
    1395           3 :         poFieldDescFeature->SetFID(nFieldsMetadataIdxPos);
    1396           3 :     CPL_IGNORE_RET_VAL(
    1397           3 :         poFieldsMetadataLayer->CreateFeature(poFieldDescFeature));
    1398           3 :     delete poFieldDescFeature;
    1399             : 
    1400             :     // Register relationship in _ogr_layer_relationships
    1401             :     OGRFeature *poRelationshipsFeature =
    1402           3 :         new OGRFeature(poRelationshipsLayer->GetLayerDefn());
    1403           3 :     poRelationshipsFeature->SetField(szPARENT_LAYER, GetName());
    1404           3 :     poRelationshipsFeature->SetField(
    1405             :         szPARENT_PKID,
    1406           3 :         GetLayerDefn()->GetFieldDefn(GetIDFieldIdx())->GetNameRef());
    1407           3 :     poRelationshipsFeature->SetField(szPARENT_ELEMENT_NAME, osNewFieldName);
    1408           3 :     poRelationshipsFeature->SetField(szCHILD_LAYER, poTargetLayer->GetName());
    1409           3 :     poRelationshipsFeature->SetField(
    1410           3 :         szCHILD_PKID, poTargetLayer->GetLayerDefn()
    1411           3 :                           ->GetFieldDefn(poTargetLayer->GetIDFieldIdx())
    1412             :                           ->GetNameRef());
    1413           3 :     CPL_IGNORE_RET_VAL(
    1414           3 :         poRelationshipsLayer->CreateFeature(poRelationshipsFeature));
    1415           3 :     delete poRelationshipsFeature;
    1416             : 
    1417           3 :     return osNewFieldName;
    1418             : }
    1419             : 
    1420             : /************************************************************************/
    1421             : /*                              GetLayerDefn()                          */
    1422             : /************************************************************************/
    1423             : 
    1424      255296 : OGRFeatureDefn *OGRGMLASLayer::GetLayerDefn()
    1425             : {
    1426      255296 :     if (!m_bLayerDefnFinalized && m_poDS->IsLayerInitFinished())
    1427             :     {
    1428             :         // If we haven't yet determined the SRS of geometry columns, do it now
    1429          15 :         m_bLayerDefnFinalized = true;
    1430          15 :         if (m_poFeatureDefn->GetGeomFieldCount() > 0 ||
    1431          20 :             m_poDS->GetConf().m_oXLinkResolution.m_bResolveInternalXLinks ||
    1432           5 :             !m_poDS->GetConf().m_oXLinkResolution.m_aoURLSpecificRules.empty())
    1433             :         {
    1434          10 :             if (m_poReader == nullptr)
    1435             :             {
    1436          10 :                 InitReader();
    1437             :                 // Avoid keeping too many file descriptor opened
    1438          10 :                 if (m_fpGML != nullptr)
    1439           9 :                     m_poDS->PushUnusedGMLFilePointer(m_fpGML);
    1440          10 :                 m_poReader.reset();
    1441             :             }
    1442             :         }
    1443             :     }
    1444      255296 :     return m_poFeatureDefn;
    1445             : }
    1446             : 
    1447             : /************************************************************************/
    1448             : /*                              ResetReading()                          */
    1449             : /************************************************************************/
    1450             : 
    1451        2128 : void OGRGMLASLayer::ResetReading()
    1452             : {
    1453        2128 :     m_poReader.reset();
    1454        2128 :     m_bEOF = false;
    1455        2128 : }
    1456             : 
    1457             : /************************************************************************/
    1458             : /*                              InitReader()                            */
    1459             : /************************************************************************/
    1460             : 
    1461        1110 : bool OGRGMLASLayer::InitReader()
    1462             : {
    1463        1110 :     CPLAssert(m_poReader == nullptr);
    1464             : 
    1465        1110 :     m_bLayerDefnFinalized = true;
    1466        1110 :     m_poReader.reset(m_poDS->CreateReader(m_fpGML));
    1467        1110 :     if (m_poReader != nullptr)
    1468             :     {
    1469        1109 :         m_poReader->SetLayerOfInterest(this);
    1470        1109 :         return true;
    1471             :     }
    1472           1 :     return false;
    1473             : }
    1474             : 
    1475             : /************************************************************************/
    1476             : /*                          GetNextRawFeature()                         */
    1477             : /************************************************************************/
    1478             : 
    1479        2840 : OGRFeature *OGRGMLASLayer::GetNextRawFeature()
    1480             : {
    1481        2840 :     if (m_poReader == nullptr && !InitReader())
    1482           0 :         return nullptr;
    1483             : 
    1484        2840 :     return m_poReader->GetNextFeature();
    1485             : }
    1486             : 
    1487             : /************************************************************************/
    1488             : /*                            EvaluateFilter()                          */
    1489             : /************************************************************************/
    1490             : 
    1491        2822 : bool OGRGMLASLayer::EvaluateFilter(OGRFeature *poFeature)
    1492             : {
    1493        2822 :     return (m_poFilterGeom == nullptr ||
    1494        5644 :             FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
    1495        5644 :            (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature));
    1496             : }
    1497             : 
    1498             : /************************************************************************/
    1499             : /*                            GetNextFeature()                          */
    1500             : /************************************************************************/
    1501             : 
    1502        2579 : OGRFeature *OGRGMLASLayer::GetNextFeature()
    1503             : {
    1504        2579 :     if (m_bEOF)
    1505          27 :         return nullptr;
    1506             : 
    1507             :     while (true)
    1508             :     {
    1509        2840 :         OGRFeature *poFeature = GetNextRawFeature();
    1510        2840 :         if (poFeature == nullptr)
    1511             :         {
    1512             :             // Avoid keeping too many file descriptor opened
    1513         798 :             if (m_fpGML != nullptr)
    1514         798 :                 m_poDS->PushUnusedGMLFilePointer(m_fpGML);
    1515         798 :             m_poReader.reset();
    1516         798 :             m_bEOF = true;
    1517         798 :             return nullptr;
    1518             :         }
    1519             : 
    1520        2042 :         if (EvaluateFilter(poFeature))
    1521             :         {
    1522        1754 :             return poFeature;
    1523             :         }
    1524             : 
    1525         288 :         delete poFeature;
    1526         288 :     }
    1527             : }

Generated by: LCOV version 1.14