LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ili - imdreader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 308 343 89.8 %
Date: 2024-11-21 22:18:42 Functions: 22 22 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Interlis 1/2 Translator
       4             :  * Purpose:  IlisMeta model reader.
       5             :  * Author:   Pirmin Kalberer, Sourcepole AG
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2014, Pirmin Kalberer, Sourcepole AG
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : // IlisMeta model: http://www.interlis.ch/models/core/IlisMeta07-20111222.ili
      14             : 
      15             : #include "cpl_minixml.h"
      16             : #include "imdreader.h"
      17             : 
      18             : #include <set>
      19             : #include <vector>
      20             : #include <algorithm>
      21             : 
      22             : typedef std::map<CPLString, CPLXMLNode *> StrNodeMap;
      23             : typedef std::vector<CPLXMLNode *> NodeVector;
      24             : typedef std::map<const CPLXMLNode *, int> NodeCountMap;
      25             : class IliClass;
      26             : // All classes with XML node for lookup.
      27             : typedef std::map<const CPLXMLNode *, IliClass *> ClassesMap;
      28             : 
      29             : /* Helper class for collection class infos */
      30             : class IliClass
      31             : {
      32             :   public:
      33             :     CPLXMLNode *node;
      34             :     int iliVersion;
      35             :     OGRFeatureDefn *poTableDefn;
      36             :     StrNodeMap &oTidLookup;
      37             :     ClassesMap &oClasses;
      38             :     NodeCountMap &oAxisCount;
      39             :     GeomFieldInfos poGeomFieldInfos;
      40             :     StructFieldInfos poStructFieldInfos;
      41             :     NodeVector oFields;
      42             :     bool isAssocClass;
      43             :     bool hasDerivedClasses;
      44             : 
      45         621 :     IliClass(CPLXMLNode *node_, int iliVersion_, StrNodeMap &oTidLookup_,
      46             :              ClassesMap &oClasses_, NodeCountMap &oAxisCount_)
      47         621 :         : node(node_), iliVersion(iliVersion_), oTidLookup(oTidLookup_),
      48             :           oClasses(oClasses_), oAxisCount(oAxisCount_), poGeomFieldInfos(),
      49             :           poStructFieldInfos(), oFields(), isAssocClass(false),
      50         621 :           hasDerivedClasses(false)
      51             :     {
      52         621 :         char *layerName = LayerName();
      53         621 :         poTableDefn = new OGRFeatureDefn(layerName);
      54         621 :         poTableDefn->Reference();
      55         621 :         CPLFree(layerName);
      56         621 :     }
      57             : 
      58         621 :     ~IliClass()
      59         621 :     {
      60         621 :         poTableDefn->Release();
      61         621 :     }
      62             : 
      63        1268 :     const char *GetName() const
      64             :     {
      65        1268 :         return poTableDefn->GetName();
      66             :     }
      67             : 
      68        1242 :     const char *GetIliName()
      69             :     {
      70        1242 :         return CPLGetXMLValue(node, "TID", nullptr);
      71             :     }
      72             : 
      73         621 :     char *LayerName()
      74             :     {
      75         621 :         const char *psClassTID = GetIliName();
      76         621 :         if (iliVersion == 1)
      77             :         {
      78             :             // Skip topic and replace . with __
      79             :             char **papszTokens =
      80         467 :                 CSLTokenizeString2(psClassTID, ".", CSLT_ALLOWEMPTYTOKENS);
      81             : 
      82         934 :             CPLString layername;
      83        1021 :             for (int i = 1; papszTokens != nullptr && papszTokens[i] != nullptr;
      84             :                  i++)
      85             :             {
      86         554 :                 if (i > 1)
      87          87 :                     layername += "__";
      88         554 :                 layername += papszTokens[i];
      89             :             }
      90         467 :             CSLDestroy(papszTokens);
      91         467 :             return CPLStrdup(layername);
      92             :         }
      93             : 
      94         154 :         return CPLStrdup(psClassTID);
      95             :     }
      96             : 
      97        1216 :     void AddFieldNode(CPLXMLNode *nodeIn, int iOrderPos)
      98             :     {
      99        1216 :         if (iOrderPos < 0 || iOrderPos > 100000)
     100             :         {
     101           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid order pos = %d",
     102             :                      iOrderPos);
     103           0 :             return;
     104             :         }
     105        1216 :         if (iOrderPos >= (int)oFields.size())
     106        1058 :             oFields.resize(iOrderPos + 1);
     107             : #ifdef DEBUG_VERBOSE
     108             :         CPLDebug("OGR_ILI", "Register field with OrderPos %d to Class %s",
     109             :                  iOrderPos, GetName());
     110             : #endif
     111        1216 :         oFields[iOrderPos] = nodeIn;
     112             :     }
     113             : 
     114          48 :     void AddRoleNode(CPLXMLNode *nodeIn, int iOrderPos)
     115             :     {
     116          48 :         isAssocClass = true;
     117          48 :         AddFieldNode(nodeIn, iOrderPos);
     118          48 :     }
     119             : 
     120         405 :     bool isEmbedded()
     121             :     {
     122         405 :         if (isAssocClass)
     123          43 :             for (NodeVector::const_iterator it = oFields.begin();
     124          62 :                  it != oFields.end(); ++it)
     125             :             {
     126          39 :                 if (*it == nullptr)
     127           0 :                     continue;
     128          39 :                 if (CPLTestBool(
     129          39 :                         CPLGetXMLValue(*it, "EmbeddedTransfer", "FALSE")))
     130          20 :                     return true;
     131             :             }
     132         385 :         return false;
     133             :     }
     134             : 
     135             :     // Add additional Geometry table for Interlis 1
     136          16 :     void AddGeomTable(const CPLString &layerName, const char *psFieldName,
     137             :                       OGRwkbGeometryType eType, bool bRefTIDField = false)
     138             :     {
     139          16 :         OGRFeatureDefn *poGeomTableDefn = new OGRFeatureDefn(layerName);
     140          32 :         OGRFieldDefn fieldDef("_TID", OFTString);
     141          16 :         poGeomTableDefn->AddFieldDefn(&fieldDef);
     142          16 :         if (bRefTIDField)
     143             :         {
     144          18 :             OGRFieldDefn fieldDefRef("_RefTID", OFTString);
     145           9 :             poGeomTableDefn->AddFieldDefn(&fieldDefRef);
     146             :         }
     147          16 :         poGeomTableDefn->DeleteGeomFieldDefn(0);
     148          16 :         OGRGeomFieldDefn fieldDefGeom(psFieldName, eType);
     149          16 :         poGeomTableDefn->AddGeomFieldDefn(&fieldDefGeom);
     150          16 :         CPLDebug("OGR_ILI", "Adding geometry table %s for field %s",
     151          16 :                  poGeomTableDefn->GetName(), psFieldName);
     152          16 :         poGeomFieldInfos[psFieldName].SetGeomTableDefn(poGeomTableDefn);
     153          16 :     }
     154             : 
     155         968 :     void AddField(const char *psName, OGRFieldType fieldType) const
     156             :     {
     157        1936 :         OGRFieldDefn fieldDef(psName, fieldType);
     158         968 :         poTableDefn->AddFieldDefn(&fieldDef);
     159         968 :         CPLDebug("OGR_ILI", "Adding field '%s' to Class %s", psName, GetName());
     160         968 :     }
     161             : 
     162         177 :     void AddGeomField(const char *psName, OGRwkbGeometryType geomType) const
     163             :     {
     164         354 :         OGRGeomFieldDefn fieldDef(psName, geomType);
     165             :         // oGFld.SetSpatialRef(geomlayer->GetSpatialRef());
     166         177 :         poTableDefn->AddGeomFieldDefn(&fieldDef);
     167         177 :         CPLDebug("OGR_ILI", "Adding geometry field '%s' to Class %s", psName,
     168             :                  GetName());
     169         177 :     }
     170             : 
     171         119 :     void AddCoord(const char *psName, const CPLXMLNode *psTypeNode) const
     172             :     {
     173         119 :         auto oIter = oAxisCount.find(psTypeNode);
     174         119 :         int dim = (oIter == oAxisCount.end()) ? 0 : oIter->second;
     175         119 :         if (dim == 0)
     176           7 :             dim = 2;  // Area center points have no Axis spec
     177         119 :         if (iliVersion == 1)
     178             :         {
     179         280 :             for (int i = 0; i < dim; i++)
     180             :             {
     181         187 :                 AddField(CPLSPrintf("%s_%d", psName, i), OFTReal);
     182             :             }
     183             :         }
     184         119 :         OGRwkbGeometryType geomType = (dim > 2) ? wkbPoint25D : wkbPoint;
     185         119 :         AddGeomField(psName, geomType);
     186         119 :     }
     187             : 
     188           7 :     OGRFieldType GetFormattedType(CPLXMLNode *nodeIn)
     189             :     {
     190           7 :         const char *psRefSuper = CPLGetXMLValue(nodeIn, "Super.REF", nullptr);
     191           7 :         if (psRefSuper)
     192           0 :             return GetFormattedType(oTidLookup[psRefSuper]);
     193             : 
     194           7 :         return OFTString;  // TODO: Time, Date, etc. if possible
     195             :     }
     196             : 
     197         621 :     void InitFieldDefinitions()
     198             :     {
     199             :         // Delete default geometry field
     200         621 :         poTableDefn->DeleteGeomFieldDefn(0);
     201             : 
     202         621 :         const char *psKind = CPLGetXMLValue(node, "Kind", "");
     203             : #ifdef DEBUG_VERBOSE
     204             :         CPLDebug("OGR_ILI", "InitFieldDefinitions of '%s' kind: %s", GetName(),
     205             :                  psKind);
     206             : #endif
     207         621 :         if (EQUAL(psKind, "Structure"))
     208             :         {
     209             :             // add foreign_key field
     210         642 :             OGRFieldDefn ofieldDefn1("REF_NAME", OFTString);
     211         321 :             poTableDefn->AddFieldDefn(&ofieldDefn1);
     212         642 :             OGRFieldDefn ofieldDefn2("REF_ID", OFTString);
     213         321 :             poTableDefn->AddFieldDefn(&ofieldDefn2);
     214             :         }
     215             :         else
     216             :         {  // Class
     217             :             // add TID field
     218         300 :             const char *psTidColName = (iliVersion == 1) ? "_TID" : "TID";
     219         600 :             OGRFieldDefn ofieldDefn(psTidColName, OFTString);
     220         300 :             poTableDefn->AddFieldDefn(&ofieldDefn);
     221             :         }
     222         621 :         if (CPLTestBool(CPLGetXMLValue(node, "Abstract", "FALSE")))
     223         185 :             hasDerivedClasses = true;
     224         621 :     }
     225             : 
     226         986 :     const CPLXMLNode *TidLookup(const char *pszKey) const
     227             :     {
     228         986 :         if (pszKey == nullptr)
     229             :         {
     230           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     231             :                      "Null key passed to TidLookup");
     232           0 :             return nullptr;
     233             :         }
     234         986 :         auto oIter = oTidLookup.find(pszKey);
     235         986 :         if (oIter == oTidLookup.end())
     236             :         {
     237           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     238             :                      "Unknown key %s passed to TidLookup", pszKey);
     239           0 :             return nullptr;
     240             :         }
     241         986 :         return oIter->second;
     242             :     }
     243             : 
     244         621 :     void AddFieldDefinitions(NodeVector oArcLineTypes)
     245             :     {
     246        1679 :         for (NodeVector::const_iterator it = oFields.begin();
     247        2737 :              it != oFields.end(); ++it)
     248             :         {
     249        1058 :             if (*it == nullptr)
     250           0 :                 continue;
     251        1058 :             const char *psName = CPLGetXMLValue(*it, "Name", nullptr);
     252        1058 :             if (psName == nullptr)
     253           0 :                 continue;
     254        1058 :             const char *psTypeRef = CPLGetXMLValue(*it, "Type.REF", nullptr);
     255        1058 :             if (psTypeRef == nullptr)         // Assoc Role
     256          72 :                 AddField(psName, OFTString);  // FIXME: numeric?
     257             :             else
     258             :             {
     259         986 :                 const CPLXMLNode *psElementNode = TidLookup(psTypeRef);
     260         986 :                 if (psElementNode == nullptr)
     261           0 :                     continue;
     262         986 :                 const char *typeName = psElementNode->pszValue;
     263         986 :                 if (EQUAL(typeName, "IlisMeta07.ModelData.TextType"))
     264             :                 {  // Kind Text,MText
     265         260 :                     AddField(psName, OFTString);
     266             :                 }
     267         726 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.EnumType"))
     268             :                 {
     269          44 :                     AddField(psName,
     270          44 :                              (iliVersion == 1) ? OFTInteger : OFTString);
     271             :                 }
     272         682 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.BooleanType"))
     273             :                 {
     274           0 :                     AddField(psName, OFTString);  //??
     275             :                 }
     276         682 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.NumType"))
     277             :                 {  //// Unit INTERLIS.ANYUNIT, INTERLIS.TIME, INTERLIS.h,
     278             :                     /// INTERLIS.min, INTERLIS.s, INTERLIS.M, INTERLIS.d
     279         396 :                     AddField(psName, OFTReal);
     280             :                 }
     281         286 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.BlackboxType"))
     282             :                 {
     283           2 :                     AddField(psName, OFTString);
     284             :                 }
     285         284 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.FormattedType"))
     286             :                 {
     287           7 :                     AddField(psName, GetFormattedType(*it));
     288             :                 }
     289         277 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.MultiValue"))
     290             :                 {
     291             :                     // min -> Multiplicity/IlisMeta07.ModelData.Multiplicity/Min
     292             :                     // max -> Multiplicity/IlisMeta07.ModelData.Multiplicity/Max
     293             :                     const char *psClassRef =
     294         107 :                         CPLGetXMLValue(psElementNode, "BaseType.REF", nullptr);
     295         107 :                     if (psClassRef)
     296             :                     {
     297             :                         IliClass *psParentClass =
     298         107 :                             oClasses[oTidLookup[psClassRef]];
     299         107 :                         poStructFieldInfos[psName] = psParentClass->GetName();
     300         107 :                         CPLDebug("OGR_ILI",
     301             :                                  "Register table %s for struct field '%s'",
     302         214 :                                  poStructFieldInfos[psName].c_str(), psName);
     303             :                         /* Option: Embed fields if max == 1
     304             :                         CPLDebug( "OGR_ILI", "Adding embedded struct members of
     305             :                         MultiValue field '%s' from Class %s", psName,
     306             :                         psClassRef);
     307             :                         AddFieldDefinitions(psParentClass->oFields);
     308             :                         */
     309             :                     }
     310             :                 }
     311         170 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.CoordType"))
     312             :                 {
     313         112 :                     AddCoord(psName, psElementNode);
     314             :                 }
     315          58 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.LineType"))
     316             :                 {
     317             :                     const char *psKind =
     318          58 :                         CPLGetXMLValue(psElementNode, "Kind", "");
     319          58 :                     poGeomFieldInfos[psName].iliGeomType = psKind;
     320             :                     bool isLinearType =
     321          58 :                         (std::find(oArcLineTypes.begin(), oArcLineTypes.end(),
     322          58 :                                    psElementNode) == oArcLineTypes.end());
     323             :                     bool linearGeom =
     324          58 :                         isLinearType || CPLTestBool(CPLGetConfigOption(
     325          58 :                                             "OGR_STROKE_CURVE", "FALSE"));
     326          58 :                     OGRwkbGeometryType multiLineType =
     327          58 :                         linearGeom ? wkbMultiLineString : wkbMultiCurve;
     328          58 :                     OGRwkbGeometryType polyType =
     329          58 :                         linearGeom ? wkbPolygon : wkbCurvePolygon;
     330          58 :                     if (iliVersion == 1)
     331             :                     {
     332          43 :                         if (EQUAL(psKind, "Area"))
     333             :                         {
     334             :                             CPLString lineLayerName =
     335          21 :                                 GetName() + CPLString("_") + psName;
     336           7 :                             AddGeomTable(lineLayerName, psName, multiLineType);
     337             : 
     338             :                             // Add geometry field for polygonized areas
     339           7 :                             AddGeomField(psName, wkbPolygon);
     340             : 
     341             :                             // We add the area helper point geometry after
     342             :                             // polygon for better behavior of clients with
     343             :                             // limited multi geometry support
     344             :                             CPLString areaPointGeomName =
     345          21 :                                 psName + CPLString("__Point");
     346           7 :                             AddCoord(areaPointGeomName, psElementNode);
     347             :                         }
     348          36 :                         else if (EQUAL(psKind, "Surface"))
     349             :                         {
     350             :                             CPLString geomLayerName =
     351          27 :                                 GetName() + CPLString("_") + psName;
     352           9 :                             AddGeomTable(geomLayerName, psName, multiLineType,
     353             :                                          true);
     354           9 :                             AddGeomField(psName, polyType);
     355             :                         }
     356             :                         else
     357             :                         {  // Polyline, DirectedPolyline
     358          27 :                             AddGeomField(psName, multiLineType);
     359             :                         }
     360             :                     }
     361             :                     else
     362             :                     {
     363          15 :                         if (EQUAL(psKind, "Area") || EQUAL(psKind, "Surface"))
     364             :                         {
     365           4 :                             AddGeomField(psName, polyType);
     366             :                         }
     367             :                         else
     368             :                         {  // Polyline, DirectedPolyline
     369          11 :                             AddGeomField(psName, multiLineType);
     370             :                         }
     371             :                     }
     372             :                 }
     373             :                 else
     374             :                 {
     375             :                     // ClassRefType
     376           0 :                     CPLError(CE_Warning, CPLE_NotSupported,
     377             :                              "Field '%s' of class %s has unsupported type %s",
     378             :                              psName, GetName(), typeName);
     379             :                 }
     380             :             }
     381             :         }
     382         621 :     }
     383             : 
     384         621 :     FeatureDefnInfo tableDefs()
     385             :     {
     386         621 :         FeatureDefnInfo poLayerInfo;
     387         621 :         if (!hasDerivedClasses && !isEmbedded())
     388             :         {
     389         385 :             poLayerInfo.SetTableDefn(poTableDefn);
     390         385 :             poLayerInfo.poGeomFieldInfos = poGeomFieldInfos;
     391             :         }
     392         621 :         return poLayerInfo;
     393             :     }
     394             : 
     395             :   private:
     396             :     CPL_DISALLOW_COPY_ASSIGN(IliClass)
     397             : };
     398             : 
     399         211 : ImdReader::ImdReader(int iliVersionIn)
     400             :     : iliVersion(iliVersionIn),
     401             :       modelInfos(),  // TODO(schwehr): Remove.  No need for default ctor,
     402             :                      // correct?
     403             :       mainModelName("OGR"), mainTopicName("OGR"), codeBlank('_'),
     404         211 :       codeUndefined('@'), codeContinue('\\')
     405             : {
     406         211 : }
     407             : 
     408         211 : ImdReader::~ImdReader()
     409             : {
     410         211 : }
     411             : 
     412          23 : void ImdReader::ReadModel(const char *pszFilename)
     413             : {
     414          23 :     CPLDebug("OGR_ILI", "Reading model '%s'", pszFilename);
     415             : 
     416          23 :     CPLXMLNode *psRootNode = CPLParseXMLFile(pszFilename);
     417          23 :     if (psRootNode == nullptr)
     418           0 :         return;
     419             :     CPLXMLNode *psSectionNode =
     420          23 :         CPLGetXMLNode(psRootNode, "=TRANSFER.DATASECTION");
     421          23 :     if (psSectionNode == nullptr)
     422             :     {
     423           0 :         CPLDestroyXMLNode(psRootNode);
     424           0 :         return;
     425             :     }
     426             : 
     427          46 :     StrNodeMap oTidLookup; /* for fast lookup of REF relations */
     428          46 :     ClassesMap oClasses;
     429          46 :     NodeCountMap oAxisCount;
     430          46 :     NodeVector oArcLineTypes;
     431             : 
     432        7710 :     const auto TidLookup = [&oTidLookup](const char *pszKey)
     433             :     {
     434        2570 :         if (pszKey == nullptr)
     435             :         {
     436           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     437             :                      "Null key passed to TidLookup");
     438           0 :             return static_cast<CPLXMLNode *>(nullptr);
     439             :         }
     440        2570 :         auto oIter = oTidLookup.find(pszKey);
     441        2570 :         if (oIter == oTidLookup.end())
     442             :         {
     443           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     444             :                      "Unknown key %s passed to TidLookup", pszKey);
     445           0 :             return static_cast<CPLXMLNode *>(nullptr);
     446             :         }
     447        2570 :         return static_cast<CPLXMLNode *>(oIter->second);
     448          23 :     };
     449             : 
     450             :     /* Fill TID lookup map and IliClasses lookup map */
     451          23 :     CPLXMLNode *psModel = psSectionNode->psChild;
     452          77 :     while (psModel != nullptr)
     453             :     {
     454          54 :         const char *modelName = CPLGetXMLValue(psModel, "BID", nullptr);
     455             : #ifdef DEBUG_VERBOSE
     456             :         CPLDebug("OGR_ILI", "Model: '%s'", modelName);
     457             : #endif
     458             : 
     459        8620 :         for (CPLXMLNode *psEntry = psModel->psChild; psEntry != nullptr;
     460        8566 :              psEntry = psEntry->psNext)
     461             :         {
     462        8566 :             if (psEntry->eType != CXT_Attribute)  // ignore BID
     463             :             {
     464             : #ifdef DEBUG_VERBOSE
     465             :                 CPLDebug("OGR_ILI", "Node tag: '%s'", psEntry->pszValue);
     466             : #endif
     467        8512 :                 const char *psTID = CPLGetXMLValue(psEntry, "TID", nullptr);
     468        8512 :                 if (psTID != nullptr)
     469        6721 :                     oTidLookup[psTID] = psEntry;
     470             : 
     471        8512 :                 if (EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.Model") &&
     472          54 :                     !EQUAL(modelName, "MODEL.INTERLIS"))
     473             :                 {
     474          62 :                     IliModelInfo modelInfo;
     475          31 :                     modelInfo.name = CPLGetXMLValue(psEntry, "Name", "OGR");
     476          31 :                     modelInfo.version = CPLGetXMLValue(psEntry, "Version", "");
     477          31 :                     modelInfo.uri = CPLGetXMLValue(psEntry, "At", "");
     478          31 :                     modelInfos.push_back(modelInfo);
     479             :                     mainModelName =
     480          31 :                         modelInfo.name;  // FIXME: check model inheritance
     481             :                     // version = CPLGetXMLValue(psEntry, "iliVersion", "0"); //1
     482             :                     // or 2.3
     483             : 
     484             :                     CPLXMLNode *psFormatNode =
     485          31 :                         CPLGetXMLNode(psEntry, "ili1Format");
     486          31 :                     if (psFormatNode != nullptr)
     487             :                     {
     488          19 :                         psFormatNode = psFormatNode->psChild;
     489          19 :                         codeBlank = static_cast<char>(atoi(
     490             :                             CPLGetXMLValue(psFormatNode, "blankCode", "95")));
     491          19 :                         codeUndefined = static_cast<char>(atoi(CPLGetXMLValue(
     492             :                             psFormatNode, "undefinedCode", "64")));
     493          19 :                         codeContinue = static_cast<char>(atoi(CPLGetXMLValue(
     494             :                             psFormatNode, "continueCode", "92")));
     495          31 :                     }
     496             :                 }
     497        8481 :                 else if (EQUAL(psEntry->pszValue,
     498             :                                "IlisMeta07.ModelData.SubModel"))
     499             :                 {
     500          51 :                     mainBasketName = CPLGetXMLValue(psEntry, "TID", "OGR");
     501          51 :                     mainTopicName = CPLGetXMLValue(psEntry, "Name", "OGR");
     502             :                 }
     503        8430 :                 else if (EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.Class"))
     504             :                 {
     505         621 :                     CPLDebug("OGR_ILI", "Class name: '%s'", psTID);
     506         621 :                     oClasses[psEntry] = new IliClass(
     507         621 :                         psEntry, iliVersion, oTidLookup, oClasses, oAxisCount);
     508             :                 }
     509             :             }
     510             :         }
     511             : 
     512             :         // 2nd pass: add fields via TransferElement entries & role associations
     513        8620 :         for (CPLXMLNode *psEntry = psModel->psChild; psEntry != nullptr;
     514        8566 :              psEntry = psEntry->psNext)
     515             :         {
     516        8566 :             if (psEntry->eType != CXT_Attribute)  // ignore BID
     517             :             {
     518             : #ifdef DEBUG_VERBOSE
     519             :                 CPLDebug("OGR_ILI", "Node tag: '%s'", psEntry->pszValue);
     520             : #endif
     521        8512 :                 if (iliVersion == 1 &&
     522        5545 :                     EQUAL(psEntry->pszValue,
     523             :                           "IlisMeta07.ModelData.Ili1TransferElement"))
     524             :                 {
     525         150 :                     const char *psClassRef = CPLGetXMLValue(
     526             :                         psEntry, "Ili1TransferClass.REF", nullptr);
     527             :                     const char *psElementRef =
     528         150 :                         CPLGetXMLValue(psEntry, "Ili1RefAttr.REF", nullptr);
     529         150 :                     if (psClassRef == nullptr || psElementRef == nullptr)
     530           0 :                         continue;
     531             :                     int iOrderPos =
     532         150 :                         atoi(CPLGetXMLValue(psEntry, "Ili1RefAttr.ORDER_POS",
     533             :                                             "0")) -
     534         150 :                         1;
     535         150 :                     auto tidClassRef = TidLookup(psClassRef);
     536         150 :                     if (tidClassRef == nullptr)
     537           0 :                         continue;
     538         150 :                     auto classesIter = oClasses.find(tidClassRef);
     539         150 :                     if (classesIter == oClasses.end())
     540           0 :                         continue;
     541         150 :                     IliClass *psParentClass = classesIter->second;
     542         150 :                     CPLXMLNode *psElementNode = TidLookup(psElementRef);
     543         150 :                     if (psElementNode == nullptr)
     544           0 :                         continue;
     545         150 :                     psParentClass->AddFieldNode(psElementNode, iOrderPos);
     546             :                 }
     547        8362 :                 else if (EQUAL(psEntry->pszValue,
     548             :                                "IlisMeta07.ModelData.TransferElement"))
     549             :                 {
     550             :                     const char *psClassRef =
     551        1018 :                         CPLGetXMLValue(psEntry, "TransferClass.REF", nullptr);
     552             :                     const char *psElementRef =
     553        1018 :                         CPLGetXMLValue(psEntry, "TransferElement.REF", nullptr);
     554        1018 :                     if (psClassRef == nullptr || psElementRef == nullptr)
     555           0 :                         continue;
     556             :                     int iOrderPos =
     557        1018 :                         atoi(CPLGetXMLValue(psEntry,
     558             :                                             "TransferElement.ORDER_POS", "0")) -
     559        1018 :                         1;
     560        1018 :                     auto tidClassRef = TidLookup(psClassRef);
     561        1018 :                     if (tidClassRef == nullptr)
     562           0 :                         continue;
     563        1018 :                     auto classesIter = oClasses.find(tidClassRef);
     564        1018 :                     if (classesIter == oClasses.end())
     565           0 :                         continue;
     566        1018 :                     IliClass *psParentClass = classesIter->second;
     567        1018 :                     CPLXMLNode *psElementNode = TidLookup(psElementRef);
     568        1018 :                     if (psElementNode == nullptr)
     569           0 :                         continue;
     570        1018 :                     psParentClass->AddFieldNode(psElementNode, iOrderPos);
     571             :                 }
     572        7344 :                 else if (EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.Role"))
     573             :                 {
     574             :                     const char *psRefParent =
     575          48 :                         CPLGetXMLValue(psEntry, "Association.REF", nullptr);
     576          48 :                     if (psRefParent == nullptr)
     577           0 :                         continue;
     578             :                     int iOrderPos =
     579          48 :                         atoi(CPLGetXMLValue(psEntry, "Association.ORDER_POS",
     580             :                                             "0")) -
     581          48 :                         1;
     582          48 :                     auto tidClassRef = TidLookup(psRefParent);
     583          48 :                     if (tidClassRef == nullptr)
     584           0 :                         continue;
     585          48 :                     auto classesIter = oClasses.find(tidClassRef);
     586          48 :                     if (classesIter == oClasses.end())
     587           0 :                         continue;
     588          48 :                     IliClass *psParentClass = classesIter->second;
     589          48 :                     if (psParentClass)
     590          48 :                         psParentClass->AddRoleNode(psEntry, iOrderPos);
     591             :                 }
     592        7296 :                 else if (EQUAL(psEntry->pszValue,
     593             :                                "IlisMeta07.ModelData.AxisSpec"))
     594             :                 {
     595             :                     const char *psClassRef =
     596         160 :                         CPLGetXMLValue(psEntry, "CoordType.REF", nullptr);
     597         160 :                     if (psClassRef == nullptr)
     598           0 :                         continue;
     599             :                     // int iOrderPos = atoi(
     600             :                     //     CPLGetXMLValue( psEntry, "Axis.ORDER_POS", "0" ))-1;
     601         160 :                     CPLXMLNode *psCoordTypeNode = TidLookup(psClassRef);
     602         160 :                     if (psCoordTypeNode == nullptr)
     603           0 :                         continue;
     604         160 :                     oAxisCount[psCoordTypeNode] += 1;
     605             :                 }
     606        7136 :                 else if (EQUAL(psEntry->pszValue,
     607             :                                "IlisMeta07.ModelData.LinesForm"))
     608             :                 {
     609             :                     const char *psLineForm =
     610          58 :                         CPLGetXMLValue(psEntry, "LineForm.REF", nullptr);
     611          58 :                     if (psLineForm != nullptr &&
     612          58 :                         EQUAL(psLineForm, "INTERLIS.ARCS"))
     613             :                     {
     614             :                         const char *psElementRef =
     615          26 :                             CPLGetXMLValue(psEntry, "LineType.REF", nullptr);
     616          26 :                         CPLXMLNode *psElementNode = TidLookup(psElementRef);
     617          26 :                         if (psElementNode == nullptr)
     618           0 :                             continue;
     619          26 :                         oArcLineTypes.push_back(psElementNode);
     620             :                     }
     621             :                 }
     622             :             }
     623             :         }
     624             : 
     625          54 :         psModel = psModel->psNext;
     626             :     }
     627             : 
     628             :     /* Analyze class inheritance & add fields to class table defn */
     629         644 :     for (ClassesMap::const_iterator it = oClasses.begin(); it != oClasses.end();
     630         621 :          ++it)
     631             :     {
     632             : #ifdef DEBUG_VERBOSE
     633             :         CPLDebug("OGR_ILI", "Class: '%s'", it->second->GetName());
     634             : #endif
     635             :         const char *psRefSuper =
     636         621 :             CPLGetXMLValue(it->first, "Super.REF", nullptr);
     637         621 :         if (psRefSuper)
     638             :         {
     639         789 :             if (oTidLookup.find(psRefSuper) != oTidLookup.end() &&
     640         526 :                 oClasses.find(oTidLookup[psRefSuper]) != oClasses.end())
     641             :             {
     642         263 :                 oClasses[oTidLookup[psRefSuper]]->hasDerivedClasses = true;
     643             :             }
     644             :             else
     645             :             {
     646           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     647             :                          "Couldn't reference super class '%s'", psRefSuper);
     648             :             }
     649             :         }
     650         621 :         it->second->InitFieldDefinitions();
     651         621 :         it->second->AddFieldDefinitions(oArcLineTypes);
     652             :     }
     653             : 
     654             :     /* Filter relevant classes */
     655         644 :     for (ClassesMap::const_iterator it = oClasses.begin(); it != oClasses.end();
     656         621 :          ++it)
     657             :     {
     658         621 :         const char *className = it->second->GetIliName();
     659        1242 :         FeatureDefnInfo oClassInfo = it->second->tableDefs();
     660         736 :         if (!STARTS_WITH_CI(className, "INTERLIS.") &&
     661         115 :             oClassInfo.GetTableDefnRef())
     662          86 :             featureDefnInfos.push_back(oClassInfo);
     663             :     }
     664             : 
     665         644 :     for (ClassesMap::iterator it = oClasses.begin(); it != oClasses.end(); ++it)
     666             :     {
     667         621 :         delete it->second;
     668             :     }
     669             : 
     670          23 :     CPLDestroyXMLNode(psRootNode);
     671             : }
     672             : 
     673          39 : FeatureDefnInfo ImdReader::GetFeatureDefnInfo(const char *pszLayerName)
     674             : {
     675          39 :     FeatureDefnInfo featureDefnInfo;
     676          56 :     for (FeatureDefnInfos::const_iterator it = featureDefnInfos.begin();
     677          73 :          it != featureDefnInfos.end(); ++it)
     678             :     {
     679          17 :         OGRFeatureDefn *fdefn = it->GetTableDefnRef();
     680          17 :         if (EQUAL(fdefn->GetName(), pszLayerName))
     681           4 :             featureDefnInfo = *it;
     682             :     }
     683          39 :     return featureDefnInfo;
     684             : }

Generated by: LCOV version 1.14