LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/ili - imdreader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 300 343 87.5 %
Date: 2025-02-20 10:14:44 Functions: 21 22 95.5 %

          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         413 :     IliClass(CPLXMLNode *node_, int iliVersion_, StrNodeMap &oTidLookup_,
      46             :              ClassesMap &oClasses_, NodeCountMap &oAxisCount_)
      47         413 :         : node(node_), iliVersion(iliVersion_), oTidLookup(oTidLookup_),
      48             :           oClasses(oClasses_), oAxisCount(oAxisCount_), poGeomFieldInfos(),
      49             :           poStructFieldInfos(), oFields(), isAssocClass(false),
      50         413 :           hasDerivedClasses(false)
      51             :     {
      52         413 :         char *layerName = LayerName();
      53         413 :         poTableDefn = new OGRFeatureDefn(layerName);
      54         413 :         poTableDefn->Reference();
      55         413 :         CPLFree(layerName);
      56         413 :     }
      57             : 
      58         413 :     ~IliClass()
      59         413 :     {
      60         413 :         poTableDefn->Release();
      61         413 :     }
      62             : 
      63         872 :     const char *GetName() const
      64             :     {
      65         872 :         return poTableDefn->GetName();
      66             :     }
      67             : 
      68         826 :     const char *GetIliName()
      69             :     {
      70         826 :         return CPLGetXMLValue(node, "TID", nullptr);
      71             :     }
      72             : 
      73         413 :     char *LayerName()
      74             :     {
      75         413 :         const char *psClassTID = GetIliName();
      76         413 :         if (iliVersion == 1)
      77             :         {
      78             :             // Skip topic and replace . with __
      79             :             char **papszTokens =
      80         323 :                 CSLTokenizeString2(psClassTID, ".", CSLT_ALLOWEMPTYTOKENS);
      81             : 
      82         646 :             CPLString layername;
      83         709 :             for (int i = 1; papszTokens != nullptr && papszTokens[i] != nullptr;
      84             :                  i++)
      85             :             {
      86         386 :                 if (i > 1)
      87          63 :                     layername += "__";
      88         386 :                 layername += papszTokens[i];
      89             :             }
      90         323 :             CSLDestroy(papszTokens);
      91         323 :             return CPLStrdup(layername);
      92             :         }
      93             : 
      94          90 :         return CPLStrdup(psClassTID);
      95             :     }
      96             : 
      97         880 :     void AddFieldNode(CPLXMLNode *nodeIn, int iOrderPos)
      98             :     {
      99         880 :         if (iOrderPos < 0 || iOrderPos > 100000)
     100             :         {
     101           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid order pos = %d",
     102             :                      iOrderPos);
     103           0 :             return;
     104             :         }
     105         880 :         if (iOrderPos >= (int)oFields.size())
     106         722 :             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         880 :         oFields[iOrderPos] = nodeIn;
     112             :     }
     113             : 
     114          36 :     void AddRoleNode(CPLXMLNode *nodeIn, int iOrderPos)
     115             :     {
     116          36 :         isAssocClass = true;
     117          36 :         AddFieldNode(nodeIn, iOrderPos);
     118          36 :     }
     119             : 
     120         273 :     bool isEmbedded()
     121             :     {
     122         273 :         if (isAssocClass)
     123          35 :             for (NodeVector::const_iterator it = oFields.begin();
     124          52 :                  it != oFields.end(); ++it)
     125             :             {
     126          31 :                 if (*it == nullptr)
     127           0 :                     continue;
     128          31 :                 if (CPLTestBool(
     129          31 :                         CPLGetXMLValue(*it, "EmbeddedTransfer", "FALSE")))
     130          14 :                     return true;
     131             :             }
     132         259 :         return false;
     133             :     }
     134             : 
     135             :     // Add additional Geometry table for Interlis 1
     136          14 :     void AddGeomTable(const CPLString &layerName, const char *psFieldName,
     137             :                       OGRwkbGeometryType eType, bool bRefTIDField = false)
     138             :     {
     139          14 :         OGRFeatureDefn *poGeomTableDefn = new OGRFeatureDefn(layerName);
     140          28 :         OGRFieldDefn fieldDef("_TID", OFTString);
     141          14 :         poGeomTableDefn->AddFieldDefn(&fieldDef);
     142          14 :         if (bRefTIDField)
     143             :         {
     144          18 :             OGRFieldDefn fieldDefRef("_RefTID", OFTString);
     145           9 :             poGeomTableDefn->AddFieldDefn(&fieldDefRef);
     146             :         }
     147          14 :         poGeomTableDefn->DeleteGeomFieldDefn(0);
     148          14 :         OGRGeomFieldDefn fieldDefGeom(psFieldName, eType);
     149          14 :         poGeomTableDefn->AddGeomFieldDefn(&fieldDefGeom);
     150          14 :         CPLDebug("OGR_ILI", "Adding geometry table %s for field %s",
     151          14 :                  poGeomTableDefn->GetName(), psFieldName);
     152          14 :         poGeomFieldInfos[psFieldName].SetGeomTableDefn(poGeomTableDefn);
     153          14 :     }
     154             : 
     155         666 :     void AddField(const char *psName, OGRFieldType fieldType) const
     156             :     {
     157        1332 :         OGRFieldDefn fieldDef(psName, fieldType);
     158         666 :         poTableDefn->AddFieldDefn(&fieldDef);
     159         666 :         CPLDebug("OGR_ILI", "Adding field '%s' to Class %s", psName, GetName());
     160         666 :     }
     161             : 
     162         117 :     void AddGeomField(const char *psName, OGRwkbGeometryType geomType) const
     163             :     {
     164         234 :         OGRGeomFieldDefn fieldDef(psName, geomType);
     165             :         // oGFld.SetSpatialRef(geomlayer->GetSpatialRef());
     166         117 :         poTableDefn->AddGeomFieldDefn(&fieldDef);
     167         117 :         CPLDebug("OGR_ILI", "Adding geometry field '%s' to Class %s", psName,
     168             :                  GetName());
     169         117 :     }
     170             : 
     171          77 :     void AddCoord(const char *psName, const CPLXMLNode *psTypeNode) const
     172             :     {
     173          77 :         auto oIter = oAxisCount.find(psTypeNode);
     174          77 :         int dim = (oIter == oAxisCount.end()) ? 0 : oIter->second;
     175          77 :         if (dim == 0)
     176           5 :             dim = 2;  // Area center points have no Axis spec
     177          77 :         if (iliVersion == 1)
     178             :         {
     179         196 :             for (int i = 0; i < dim; i++)
     180             :             {
     181         131 :                 AddField(CPLSPrintf("%s_%d", psName, i), OFTReal);
     182             :             }
     183             :         }
     184          77 :         OGRwkbGeometryType geomType = (dim > 2) ? wkbPoint25D : wkbPoint;
     185          77 :         AddGeomField(psName, geomType);
     186          77 :     }
     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         413 :     void InitFieldDefinitions()
     198             :     {
     199             :         // Delete default geometry field
     200         413 :         poTableDefn->DeleteGeomFieldDefn(0);
     201             : 
     202         413 :         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         413 :         if (EQUAL(psKind, "Structure"))
     208             :         {
     209             :             // add foreign_key field
     210         430 :             OGRFieldDefn ofieldDefn1("REF_NAME", OFTString);
     211         215 :             poTableDefn->AddFieldDefn(&ofieldDefn1);
     212         430 :             OGRFieldDefn ofieldDefn2("REF_ID", OFTString);
     213         215 :             poTableDefn->AddFieldDefn(&ofieldDefn2);
     214             :         }
     215             :         else
     216             :         {  // Class
     217             :             // add TID field
     218         198 :             const char *psTidColName = (iliVersion == 1) ? "_TID" : "TID";
     219         396 :             OGRFieldDefn ofieldDefn(psTidColName, OFTString);
     220         198 :             poTableDefn->AddFieldDefn(&ofieldDefn);
     221             :         }
     222         413 :         if (CPLTestBool(CPLGetXMLValue(node, "Abstract", "FALSE")))
     223         121 :             hasDerivedClasses = true;
     224         413 :     }
     225             : 
     226         670 :     const CPLXMLNode *TidLookup(const char *pszKey) const
     227             :     {
     228         670 :         if (pszKey == nullptr)
     229             :         {
     230           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     231             :                      "Null key passed to TidLookup");
     232           0 :             return nullptr;
     233             :         }
     234         670 :         auto oIter = oTidLookup.find(pszKey);
     235         670 :         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         670 :         return oIter->second;
     242             :     }
     243             : 
     244         413 :     void AddFieldDefinitions(NodeVector oArcLineTypes)
     245             :     {
     246        1135 :         for (NodeVector::const_iterator it = oFields.begin();
     247        1857 :              it != oFields.end(); ++it)
     248             :         {
     249         722 :             if (*it == nullptr)
     250           0 :                 continue;
     251         722 :             const char *psName = CPLGetXMLValue(*it, "Name", nullptr);
     252         722 :             if (psName == nullptr)
     253           0 :                 continue;
     254         722 :             const char *psTypeRef = CPLGetXMLValue(*it, "Type.REF", nullptr);
     255         722 :             if (psTypeRef == nullptr)         // Assoc Role
     256          52 :                 AddField(psName, OFTString);  // FIXME: numeric?
     257             :             else
     258             :             {
     259         670 :                 const CPLXMLNode *psElementNode = TidLookup(psTypeRef);
     260         670 :                 if (psElementNode == nullptr)
     261           0 :                     continue;
     262         670 :                 const char *typeName = psElementNode->pszValue;
     263         670 :                 if (EQUAL(typeName, "IlisMeta07.ModelData.TextType"))
     264             :                 {  // Kind Text,MText
     265         172 :                     AddField(psName, OFTString);
     266             :                 }
     267         498 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.EnumType"))
     268             :                 {
     269          32 :                     AddField(psName,
     270          32 :                              (iliVersion == 1) ? OFTInteger : OFTString);
     271             :                 }
     272         466 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.BooleanType"))
     273             :                 {
     274           0 :                     AddField(psName, OFTString);  //??
     275             :                 }
     276         466 :                 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         270 :                     AddField(psName, OFTReal);
     280             :                 }
     281         196 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.BlackboxType"))
     282             :                 {
     283           2 :                     AddField(psName, OFTString);
     284             :                 }
     285         194 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.FormattedType"))
     286             :                 {
     287           7 :                     AddField(psName, GetFormattedType(*it));
     288             :                 }
     289         187 :                 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          75 :                         CPLGetXMLValue(psElementNode, "BaseType.REF", nullptr);
     295          75 :                     if (psClassRef)
     296             :                     {
     297             :                         IliClass *psParentClass =
     298          75 :                             oClasses[oTidLookup[psClassRef]];
     299          75 :                         poStructFieldInfos[psName] = psParentClass->GetName();
     300          75 :                         CPLDebug("OGR_ILI",
     301             :                                  "Register table %s for struct field '%s'",
     302         150 :                                  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         112 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.CoordType"))
     312             :                 {
     313          72 :                     AddCoord(psName, psElementNode);
     314             :                 }
     315          40 :                 else if (EQUAL(typeName, "IlisMeta07.ModelData.LineType"))
     316             :                 {
     317             :                     const char *psKind =
     318          40 :                         CPLGetXMLValue(psElementNode, "Kind", "");
     319          40 :                     poGeomFieldInfos[psName].iliGeomType = psKind;
     320             :                     bool isLinearType =
     321          40 :                         (std::find(oArcLineTypes.begin(), oArcLineTypes.end(),
     322          40 :                                    psElementNode) == oArcLineTypes.end());
     323             :                     bool linearGeom =
     324          40 :                         isLinearType || CPLTestBool(CPLGetConfigOption(
     325          40 :                                             "OGR_STROKE_CURVE", "FALSE"));
     326          40 :                     OGRwkbGeometryType multiLineType =
     327          40 :                         linearGeom ? wkbMultiLineString : wkbMultiCurve;
     328          40 :                     OGRwkbGeometryType polyType =
     329          40 :                         linearGeom ? wkbPolygon : wkbCurvePolygon;
     330          40 :                     if (iliVersion == 1)
     331             :                     {
     332          33 :                         if (EQUAL(psKind, "Area"))
     333             :                         {
     334             :                             CPLString lineLayerName =
     335          15 :                                 GetName() + CPLString("_") + psName;
     336           5 :                             AddGeomTable(lineLayerName, psName, multiLineType);
     337             : 
     338             :                             // Add geometry field for polygonized areas
     339           5 :                             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          15 :                                 psName + CPLString("__Point");
     346           5 :                             AddCoord(areaPointGeomName, psElementNode);
     347             :                         }
     348          28 :                         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          19 :                             AddGeomField(psName, multiLineType);
     359             :                         }
     360             :                     }
     361             :                     else
     362             :                     {
     363           7 :                         if (EQUAL(psKind, "Area") || EQUAL(psKind, "Surface"))
     364             :                         {
     365           2 :                             AddGeomField(psName, polyType);
     366             :                         }
     367             :                         else
     368             :                         {  // Polyline, DirectedPolyline
     369           5 :                             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         413 :     }
     383             : 
     384         413 :     FeatureDefnInfo tableDefs()
     385             :     {
     386         413 :         FeatureDefnInfo poLayerInfo;
     387         413 :         if (!hasDerivedClasses && !isEmbedded())
     388             :         {
     389         259 :             poLayerInfo.SetTableDefn(poTableDefn);
     390         259 :             poLayerInfo.poGeomFieldInfos = poGeomFieldInfos;
     391             :         }
     392         413 :         return poLayerInfo;
     393             :     }
     394             : 
     395             :   private:
     396             :     CPL_DISALLOW_COPY_ASSIGN(IliClass)
     397             : };
     398             : 
     399         122 : 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         122 :       codeUndefined('@'), codeContinue('\\')
     405             : {
     406         122 : }
     407             : 
     408         122 : ImdReader::~ImdReader()
     409             : {
     410         122 : }
     411             : 
     412          15 : void ImdReader::ReadModel(const char *pszFilename)
     413             : {
     414          15 :     CPLDebug("OGR_ILI", "Reading model '%s'", pszFilename);
     415             : 
     416          15 :     CPLXMLNode *psRootNode = CPLParseXMLFile(pszFilename);
     417          15 :     if (psRootNode == nullptr)
     418           0 :         return;
     419             :     CPLXMLNode *psSectionNode =
     420          15 :         CPLGetXMLNode(psRootNode, "=TRANSFER.DATASECTION");
     421          15 :     if (psSectionNode == nullptr)
     422             :     {
     423           0 :         CPLDestroyXMLNode(psRootNode);
     424           0 :         return;
     425             :     }
     426             : 
     427          30 :     StrNodeMap oTidLookup; /* for fast lookup of REF relations */
     428          30 :     ClassesMap oClasses;
     429          30 :     NodeCountMap oAxisCount;
     430          30 :     NodeVector oArcLineTypes;
     431             : 
     432        5562 :     const auto TidLookup = [&oTidLookup](const char *pszKey)
     433             :     {
     434        1854 :         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        1854 :         auto oIter = oTidLookup.find(pszKey);
     441        1854 :         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        1854 :         return static_cast<CPLXMLNode *>(oIter->second);
     448          15 :     };
     449             : 
     450             :     /* Fill TID lookup map and IliClasses lookup map */
     451          15 :     CPLXMLNode *psModel = psSectionNode->psChild;
     452          51 :     while (psModel != nullptr)
     453             :     {
     454          36 :         const char *modelName = CPLGetXMLValue(psModel, "BID", nullptr);
     455             : #ifdef DEBUG_VERBOSE
     456             :         CPLDebug("OGR_ILI", "Model: '%s'", modelName);
     457             : #endif
     458             : 
     459        6258 :         for (CPLXMLNode *psEntry = psModel->psChild; psEntry != nullptr;
     460        6222 :              psEntry = psEntry->psNext)
     461             :         {
     462        6222 :             if (psEntry->eType != CXT_Attribute)  // ignore BID
     463             :             {
     464             : #ifdef DEBUG_VERBOSE
     465             :                 CPLDebug("OGR_ILI", "Node tag: '%s'", psEntry->pszValue);
     466             : #endif
     467        6186 :                 const char *psTID = CPLGetXMLValue(psEntry, "TID", nullptr);
     468        6186 :                 if (psTID != nullptr)
     469        4915 :                     oTidLookup[psTID] = psEntry;
     470             : 
     471        6186 :                 if (EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.Model") &&
     472          36 :                     !EQUAL(modelName, "MODEL.INTERLIS"))
     473             :                 {
     474          42 :                     IliModelInfo modelInfo;
     475          21 :                     modelInfo.name = CPLGetXMLValue(psEntry, "Name", "OGR");
     476          21 :                     modelInfo.version = CPLGetXMLValue(psEntry, "Version", "");
     477          21 :                     modelInfo.uri = CPLGetXMLValue(psEntry, "At", "");
     478          21 :                     modelInfos.push_back(modelInfo);
     479             :                     mainModelName =
     480          21 :                         modelInfo.name;  // FIXME: check model inheritance
     481             :                     // version = CPLGetXMLValue(psEntry, "iliVersion", "0"); //1
     482             :                     // or 2.3
     483             : 
     484             :                     CPLXMLNode *psFormatNode =
     485          21 :                         CPLGetXMLNode(psEntry, "ili1Format");
     486          21 :                     if (psFormatNode != nullptr)
     487             :                     {
     488          13 :                         psFormatNode = psFormatNode->psChild;
     489          13 :                         codeBlank = static_cast<char>(atoi(
     490             :                             CPLGetXMLValue(psFormatNode, "blankCode", "95")));
     491          13 :                         codeUndefined = static_cast<char>(atoi(CPLGetXMLValue(
     492             :                             psFormatNode, "undefinedCode", "64")));
     493          13 :                         codeContinue = static_cast<char>(atoi(CPLGetXMLValue(
     494             :                             psFormatNode, "continueCode", "92")));
     495          21 :                     }
     496             :                 }
     497        6165 :                 else if (EQUAL(psEntry->pszValue,
     498             :                                "IlisMeta07.ModelData.SubModel"))
     499             :                 {
     500          33 :                     mainBasketName = CPLGetXMLValue(psEntry, "TID", "OGR");
     501          33 :                     mainTopicName = CPLGetXMLValue(psEntry, "Name", "OGR");
     502             :                 }
     503        6132 :                 else if (EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.Class"))
     504             :                 {
     505         413 :                     CPLDebug("OGR_ILI", "Class name: '%s'", psTID);
     506         413 :                     oClasses[psEntry] = new IliClass(
     507         413 :                         psEntry, iliVersion, oTidLookup, oClasses, oAxisCount);
     508             :                 }
     509             :             }
     510             :         }
     511             : 
     512             :         // 2nd pass: add fields via TransferElement entries & role associations
     513        6258 :         for (CPLXMLNode *psEntry = psModel->psChild; psEntry != nullptr;
     514        6222 :              psEntry = psEntry->psNext)
     515             :         {
     516        6222 :             if (psEntry->eType != CXT_Attribute)  // ignore BID
     517             :             {
     518             : #ifdef DEBUG_VERBOSE
     519             :                 CPLDebug("OGR_ILI", "Node tag: '%s'", psEntry->pszValue);
     520             : #endif
     521        6186 :                 if (iliVersion == 1 &&
     522        3925 :                     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        6036 :                 else if (EQUAL(psEntry->pszValue,
     548             :                                "IlisMeta07.ModelData.TransferElement"))
     549             :                 {
     550             :                     const char *psClassRef =
     551         694 :                         CPLGetXMLValue(psEntry, "TransferClass.REF", nullptr);
     552             :                     const char *psElementRef =
     553         694 :                         CPLGetXMLValue(psEntry, "TransferElement.REF", nullptr);
     554         694 :                     if (psClassRef == nullptr || psElementRef == nullptr)
     555           0 :                         continue;
     556             :                     int iOrderPos =
     557         694 :                         atoi(CPLGetXMLValue(psEntry,
     558             :                                             "TransferElement.ORDER_POS", "0")) -
     559         694 :                         1;
     560         694 :                     auto tidClassRef = TidLookup(psClassRef);
     561         694 :                     if (tidClassRef == nullptr)
     562           0 :                         continue;
     563         694 :                     auto classesIter = oClasses.find(tidClassRef);
     564         694 :                     if (classesIter == oClasses.end())
     565           0 :                         continue;
     566         694 :                     IliClass *psParentClass = classesIter->second;
     567         694 :                     CPLXMLNode *psElementNode = TidLookup(psElementRef);
     568         694 :                     if (psElementNode == nullptr)
     569           0 :                         continue;
     570         694 :                     psParentClass->AddFieldNode(psElementNode, iOrderPos);
     571             :                 }
     572        5342 :                 else if (EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.Role"))
     573             :                 {
     574             :                     const char *psRefParent =
     575          36 :                         CPLGetXMLValue(psEntry, "Association.REF", nullptr);
     576          36 :                     if (psRefParent == nullptr)
     577           0 :                         continue;
     578             :                     int iOrderPos =
     579          36 :                         atoi(CPLGetXMLValue(psEntry, "Association.ORDER_POS",
     580             :                                             "0")) -
     581          36 :                         1;
     582          36 :                     auto tidClassRef = TidLookup(psRefParent);
     583          36 :                     if (tidClassRef == nullptr)
     584           0 :                         continue;
     585          36 :                     auto classesIter = oClasses.find(tidClassRef);
     586          36 :                     if (classesIter == oClasses.end())
     587           0 :                         continue;
     588          36 :                     IliClass *psParentClass = classesIter->second;
     589          36 :                     if (psParentClass)
     590          36 :                         psParentClass->AddRoleNode(psEntry, iOrderPos);
     591             :                 }
     592        5306 :                 else if (EQUAL(psEntry->pszValue,
     593             :                                "IlisMeta07.ModelData.AxisSpec"))
     594             :                 {
     595             :                     const char *psClassRef =
     596         108 :                         CPLGetXMLValue(psEntry, "CoordType.REF", nullptr);
     597         108 :                     if (psClassRef == nullptr)
     598           0 :                         continue;
     599             :                     // int iOrderPos = atoi(
     600             :                     //     CPLGetXMLValue( psEntry, "Axis.ORDER_POS", "0" ))-1;
     601         108 :                     CPLXMLNode *psCoordTypeNode = TidLookup(psClassRef);
     602         108 :                     if (psCoordTypeNode == nullptr)
     603           0 :                         continue;
     604         108 :                     oAxisCount[psCoordTypeNode] += 1;
     605             :                 }
     606        5198 :                 else if (EQUAL(psEntry->pszValue,
     607             :                                "IlisMeta07.ModelData.LinesForm"))
     608             :                 {
     609             :                     const char *psLineForm =
     610          46 :                         CPLGetXMLValue(psEntry, "LineForm.REF", nullptr);
     611          46 :                     if (psLineForm != nullptr &&
     612          46 :                         EQUAL(psLineForm, "INTERLIS.ARCS"))
     613             :                     {
     614             :                         const char *psElementRef =
     615          22 :                             CPLGetXMLValue(psEntry, "LineType.REF", nullptr);
     616          22 :                         CPLXMLNode *psElementNode = TidLookup(psElementRef);
     617          22 :                         if (psElementNode == nullptr)
     618           0 :                             continue;
     619          22 :                         oArcLineTypes.push_back(psElementNode);
     620             :                     }
     621             :                 }
     622             :             }
     623             :         }
     624             : 
     625          36 :         psModel = psModel->psNext;
     626             :     }
     627             : 
     628             :     /* Analyze class inheritance & add fields to class table defn */
     629         428 :     for (ClassesMap::const_iterator it = oClasses.begin(); it != oClasses.end();
     630         413 :          ++it)
     631             :     {
     632             : #ifdef DEBUG_VERBOSE
     633             :         CPLDebug("OGR_ILI", "Class: '%s'", it->second->GetName());
     634             : #endif
     635             :         const char *psRefSuper =
     636         413 :             CPLGetXMLValue(it->first, "Super.REF", nullptr);
     637         413 :         if (psRefSuper)
     638             :         {
     639         513 :             if (oTidLookup.find(psRefSuper) != oTidLookup.end() &&
     640         342 :                 oClasses.find(oTidLookup[psRefSuper]) != oClasses.end())
     641             :             {
     642         171 :                 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         413 :         it->second->InitFieldDefinitions();
     651         413 :         it->second->AddFieldDefinitions(oArcLineTypes);
     652             :     }
     653             : 
     654             :     /* Filter relevant classes */
     655         428 :     for (ClassesMap::const_iterator it = oClasses.begin(); it != oClasses.end();
     656         413 :          ++it)
     657             :     {
     658         413 :         const char *className = it->second->GetIliName();
     659         826 :         FeatureDefnInfo oClassInfo = it->second->tableDefs();
     660         496 :         if (!STARTS_WITH_CI(className, "INTERLIS.") &&
     661          83 :             oClassInfo.GetTableDefnRef())
     662          64 :             featureDefnInfos.push_back(oClassInfo);
     663             :     }
     664             : 
     665         428 :     for (ClassesMap::iterator it = oClasses.begin(); it != oClasses.end(); ++it)
     666             :     {
     667         413 :         delete it->second;
     668             :     }
     669             : 
     670          15 :     CPLDestroyXMLNode(psRootNode);
     671             : }
     672             : 
     673           0 : FeatureDefnInfo ImdReader::GetFeatureDefnInfo(const char *pszLayerName)
     674             : {
     675           0 :     FeatureDefnInfo featureDefnInfo;
     676           0 :     for (FeatureDefnInfos::const_iterator it = featureDefnInfos.begin();
     677           0 :          it != featureDefnInfos.end(); ++it)
     678             :     {
     679           0 :         OGRFeatureDefn *fdefn = it->GetTableDefnRef();
     680           0 :         if (EQUAL(fdefn->GetName(), pszLayerName))
     681           0 :             featureDefnInfo = *it;
     682             :     }
     683           0 :     return featureDefnInfo;
     684             : }

Generated by: LCOV version 1.14