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

Generated by: LCOV version 1.14