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

Generated by: LCOV version 1.14