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 CPL_CVSID("$Id: imdreader.cpp f0237483886cb50fd93f6295263546017ab95d41 2021-03-11 11:42:22 +0100 Even Rouault $")
39
40 typedef std::map<CPLString,CPLXMLNode*> StrNodeMap;
41 typedef std::vector<CPLXMLNode*> NodeVector;
42 typedef std::map<CPLXMLNode*,int> NodeCountMap;
43 class IliClass;
44 // All classes with XML node for lookup.
45 typedef std::map<CPLXMLNode*,IliClass*> ClassesMap;
46
47 /* Helper class for collection class infos */
48 class IliClass
49 {
50 public:
51 CPLXMLNode* node;
52 int iliVersion;
53 OGRFeatureDefn* poTableDefn;
54 StrNodeMap& oTidLookup;
55 ClassesMap& oClasses;
56 NodeCountMap& oAxisCount;
57 GeomFieldInfos poGeomFieldInfos;
58 StructFieldInfos poStructFieldInfos;
59 NodeVector oFields;
60 bool isAssocClass;
61 bool hasDerivedClasses;
62
IliClass(CPLXMLNode * node_,int iliVersion_,StrNodeMap & oTidLookup_,ClassesMap & oClasses_,NodeCountMap & oAxisCount_)63 IliClass( CPLXMLNode* node_, int iliVersion_, StrNodeMap& oTidLookup_,
64 ClassesMap& oClasses_, NodeCountMap& oAxisCount_) :
65 node(node_), iliVersion(iliVersion_), oTidLookup(oTidLookup_),
66 oClasses(oClasses_), oAxisCount(oAxisCount_),
67 poGeomFieldInfos(), poStructFieldInfos(), oFields(),
68 isAssocClass(false), hasDerivedClasses(false)
69 {
70 char* layerName = LayerName();
71 poTableDefn = new OGRFeatureDefn(layerName);
72 poTableDefn->Reference();
73 CPLFree(layerName);
74 }
75
~IliClass()76 ~IliClass()
77 {
78 poTableDefn->Release();
79 }
80
GetName()81 const char* GetName() {
82 return poTableDefn->GetName();
83 }
GetIliName()84 const char* GetIliName() {
85 return CPLGetXMLValue( node, "TID", nullptr );
86 }
LayerName()87 char* LayerName() {
88 const char* psClassTID = GetIliName();
89 if (iliVersion == 1)
90 {
91 //Skip topic and replace . with __
92 char **papszTokens =
93 CSLTokenizeString2( psClassTID, ".", CSLT_ALLOWEMPTYTOKENS );
94
95 CPLString layername;
96 for(int i = 1; papszTokens != nullptr && papszTokens[i] != nullptr; i++)
97 {
98 if (i>1) layername += "__";
99 layername += papszTokens[i];
100 }
101 CSLDestroy( papszTokens );
102 return CPLStrdup(layername);
103 }
104
105 return CPLStrdup(psClassTID);
106 }
AddFieldNode(CPLXMLNode * nodeIn,int iOrderPos)107 void AddFieldNode(CPLXMLNode* nodeIn, int iOrderPos)
108 {
109 if (iOrderPos >= (int)oFields.size())
110 oFields.resize(iOrderPos+1);
111 #ifdef DEBUG_VERBOSE
112 CPLDebug( "OGR_ILI", "Register field with OrderPos %d to Class %s",
113 iOrderPos, GetName() );
114 #endif
115 oFields[iOrderPos] = nodeIn;
116 }
AddRoleNode(CPLXMLNode * nodeIn,int iOrderPos)117 void AddRoleNode(CPLXMLNode* nodeIn, int iOrderPos)
118 {
119 isAssocClass = true;
120 AddFieldNode(nodeIn, iOrderPos);
121 }
isEmbedded()122 bool isEmbedded()
123 {
124 if (isAssocClass)
125 for( NodeVector::const_iterator it = oFields.begin();
126 it != oFields.end();
127 ++it )
128 {
129 if (*it == nullptr) continue;
130 if( CPLTestBool(
131 CPLGetXMLValue( *it, "EmbeddedTransfer", "FALSE" ) ) )
132 return true;
133 }
134 return false;
135 }
136 // Add additional Geometry table for Interlis 1
AddGeomTable(CPLString layerName,const char * psFieldName,OGRwkbGeometryType eType,bool bRefTIDField=false)137 void AddGeomTable( CPLString layerName, const char* psFieldName,
138 OGRwkbGeometryType eType, bool bRefTIDField = false )
139 {
140 OGRFeatureDefn* poGeomTableDefn = new OGRFeatureDefn(layerName);
141 OGRFieldDefn fieldDef("_TID", OFTString);
142 poGeomTableDefn->AddFieldDefn(&fieldDef);
143 if (bRefTIDField)
144 {
145 OGRFieldDefn fieldDefRef("_RefTID", OFTString);
146 poGeomTableDefn->AddFieldDefn(&fieldDefRef);
147 }
148 poGeomTableDefn->DeleteGeomFieldDefn(0);
149 OGRGeomFieldDefn fieldDefGeom(psFieldName, eType);
150 poGeomTableDefn->AddGeomFieldDefn(&fieldDefGeom);
151 CPLDebug( "OGR_ILI", "Adding geometry table %s for field %s",
152 poGeomTableDefn->GetName(), psFieldName);
153 poGeomFieldInfos[psFieldName].SetGeomTableDefn(poGeomTableDefn);
154 }
AddField(const char * psName,OGRFieldType fieldType)155 void AddField(const char* psName, OGRFieldType fieldType)
156 {
157 OGRFieldDefn fieldDef(psName, fieldType);
158 poTableDefn->AddFieldDefn(&fieldDef);
159 CPLDebug( "OGR_ILI", "Adding field '%s' to Class %s", psName, GetName());
160 }
AddGeomField(const char * psName,OGRwkbGeometryType geomType)161 void AddGeomField(const char* psName, OGRwkbGeometryType geomType)
162 {
163 OGRGeomFieldDefn fieldDef(psName, geomType);
164 //oGFld.SetSpatialRef(geomlayer->GetSpatialRef());
165 poTableDefn->AddGeomFieldDefn(&fieldDef);
166 CPLDebug( "OGR_ILI", "Adding geometry field '%s' to Class %s",
167 psName, GetName());
168 }
AddCoord(const char * psName,CPLXMLNode * psTypeNode)169 void AddCoord(const char* psName, CPLXMLNode* psTypeNode)
170 {
171 int dim = oAxisCount[psTypeNode];
172 if (dim == 0) dim = 2; //Area center points have no Axis spec
173 if (iliVersion == 1)
174 {
175 for (int i=0; i<dim; i++)
176 {
177 AddField(CPLSPrintf("%s_%d", psName, i), OFTReal);
178 }
179 }
180 OGRwkbGeometryType geomType = (dim > 2) ? wkbPoint25D : wkbPoint;
181 AddGeomField(psName, geomType);
182 }
GetFormattedType(CPLXMLNode * nodeIn)183 OGRFieldType GetFormattedType(CPLXMLNode* nodeIn)
184 {
185 const char* psRefSuper = CPLGetXMLValue( nodeIn, "Super.REF", nullptr );
186 if (psRefSuper)
187 return GetFormattedType(oTidLookup[psRefSuper]);
188
189 return OFTString; //TODO: Time, Date, etc. if possible
190 }
InitFieldDefinitions()191 void InitFieldDefinitions()
192 {
193 // Delete default geometry field
194 poTableDefn->DeleteGeomFieldDefn(0);
195
196 const char* psKind = CPLGetXMLValue( node, "Kind", "" );
197 #ifdef DEBUG_VERBOSE
198 CPLDebug( "OGR_ILI", "InitFieldDefinitions of '%s' kind: %s",
199 GetName(), psKind );
200 #endif
201 if (EQUAL(psKind, "Structure"))
202 {
203 // add foreign_key field
204 OGRFieldDefn ofieldDefn1("REF_NAME", OFTString);
205 poTableDefn->AddFieldDefn(&ofieldDefn1);
206 OGRFieldDefn ofieldDefn2("REF_ID", OFTString);
207 poTableDefn->AddFieldDefn(&ofieldDefn2);
208 } else { // Class
209 // add TID field
210 const char* psTidColName = (iliVersion == 1) ? "_TID" : "TID";
211 OGRFieldDefn ofieldDefn(psTidColName, OFTString);
212 poTableDefn->AddFieldDefn(&ofieldDefn);
213 }
214 if (CPLTestBool(CPLGetXMLValue( node, "Abstract", "FALSE" )))
215 hasDerivedClasses = true;
216 }
AddFieldDefinitions(NodeVector oArcLineTypes)217 void AddFieldDefinitions(NodeVector oArcLineTypes)
218 {
219 for( NodeVector::const_iterator it = oFields.begin();
220 it != oFields.end();
221 ++it)
222 {
223 if (*it == nullptr) continue;
224 const char* psName = CPLGetXMLValue( *it, "Name", nullptr );
225 if( psName == nullptr )
226 continue;
227 const char* psTypeRef = CPLGetXMLValue( *it, "Type.REF", nullptr );
228 if (psTypeRef == nullptr) //Assoc Role
229 AddField(psName, OFTString); //FIXME: numeric?
230 else
231 {
232 CPLXMLNode* psElementNode = oTidLookup[psTypeRef];
233 const char* typeName = psElementNode->pszValue;
234 if (EQUAL(typeName, "IlisMeta07.ModelData.TextType"))
235 { //Kind Text,MText
236 AddField(psName, OFTString);
237 }
238 else if (EQUAL(typeName, "IlisMeta07.ModelData.EnumType"))
239 {
240 AddField(psName, (iliVersion == 1) ? OFTInteger : OFTString);
241 }
242 else if (EQUAL(typeName, "IlisMeta07.ModelData.BooleanType"))
243 {
244 AddField(psName, OFTString); //??
245 }
246 else if (EQUAL(typeName, "IlisMeta07.ModelData.NumType"))
247 { //// Unit INTERLIS.ANYUNIT, INTERLIS.TIME, INTERLIS.h, INTERLIS.min, INTERLIS.s, INTERLIS.M, INTERLIS.d
248 AddField(psName, OFTReal);
249 }
250 else if (EQUAL(typeName, "IlisMeta07.ModelData.BlackboxType"))
251 {
252 AddField(psName, OFTString);
253 }
254 else if (EQUAL(typeName, "IlisMeta07.ModelData.FormattedType"))
255 {
256 AddField(psName, GetFormattedType(*it));
257 }
258 else if (EQUAL(typeName, "IlisMeta07.ModelData.MultiValue"))
259 {
260 //min -> Multiplicity/IlisMeta07.ModelData.Multiplicity/Min
261 //max -> Multiplicity/IlisMeta07.ModelData.Multiplicity/Max
262 const char* psClassRef = CPLGetXMLValue( psElementNode, "BaseType.REF", nullptr );
263 if (psClassRef)
264 {
265 IliClass* psParentClass = oClasses[oTidLookup[psClassRef]];
266 poStructFieldInfos[psName] = psParentClass->GetName();
267 CPLDebug( "OGR_ILI", "Register table %s for struct field '%s'", poStructFieldInfos[psName].c_str(), psName);
268 /* Option: Embed fields if max == 1
269 CPLDebug( "OGR_ILI", "Adding embedded struct members of MultiValue field '%s' from Class %s", psName, psClassRef);
270 AddFieldDefinitions(psParentClass->oFields);
271 */
272 }
273 }
274 else if (EQUAL(typeName, "IlisMeta07.ModelData.CoordType"))
275 {
276 AddCoord(psName, psElementNode);
277 }
278 else if (EQUAL(typeName, "IlisMeta07.ModelData.LineType"))
279 {
280 const char* psKind = CPLGetXMLValue( psElementNode, "Kind", "" );
281 poGeomFieldInfos[psName].iliGeomType = psKind;
282 bool isLinearType = (std::find(oArcLineTypes.begin(), oArcLineTypes.end(), psElementNode) == oArcLineTypes.end());
283 bool linearGeom = isLinearType || CPLTestBool(CPLGetConfigOption("OGR_STROKE_CURVE", "FALSE"));
284 OGRwkbGeometryType multiLineType = linearGeom ? wkbMultiLineString : wkbMultiCurve;
285 OGRwkbGeometryType polyType = linearGeom ? wkbPolygon : wkbCurvePolygon;
286 if (iliVersion == 1)
287 {
288 if (EQUAL(psKind, "Area"))
289 {
290 CPLString lineLayerName = GetName() + CPLString("_") + psName;
291 AddGeomTable(lineLayerName, psName, multiLineType);
292
293 //Add geometry field for polygonized areas
294 AddGeomField(psName, wkbPolygon);
295
296 //We add the area helper point geometry after polygon
297 //for better behavior of clients with limited multi geometry support
298 CPLString areaPointGeomName = psName + CPLString("__Point");
299 AddCoord(areaPointGeomName, psElementNode);
300 } else if (EQUAL(psKind, "Surface"))
301 {
302 CPLString geomLayerName = GetName() + CPLString("_") + psName;
303 AddGeomTable(geomLayerName, psName, multiLineType, true);
304 AddGeomField(psName, polyType);
305 } else { // Polyline, DirectedPolyline
306 AddGeomField(psName, multiLineType);
307 }
308 } else {
309 if (EQUAL(psKind, "Area") || EQUAL(psKind, "Surface"))
310 {
311 AddGeomField(psName, polyType);
312 } else { // Polyline, DirectedPolyline
313 AddGeomField(psName, multiLineType);
314 }
315 }
316 }
317 else
318 {
319 //ClassRefType
320 CPLError(CE_Warning, CPLE_NotSupported,
321 "Field '%s' of class %s has unsupported type %s", psName, GetName(), typeName);
322 }
323 }
324 }
325 }
tableDefs()326 FeatureDefnInfo tableDefs()
327 {
328 FeatureDefnInfo poLayerInfo;
329 if (!hasDerivedClasses && !isEmbedded())
330 {
331 poLayerInfo.SetTableDefn(poTableDefn);
332 poLayerInfo.poGeomFieldInfos = poGeomFieldInfos;
333 }
334 return poLayerInfo;
335 }
336
337 private:
338 CPL_DISALLOW_COPY_ASSIGN(IliClass)
339 };
340
ImdReader(int iliVersionIn)341 ImdReader::ImdReader(int iliVersionIn) :
342 iliVersion(iliVersionIn),
343 modelInfos(), // TODO(schwehr): Remove. No need for default ctor, correct?
344 mainModelName("OGR"),
345 mainTopicName("OGR"),
346 codeBlank('_'),
347 codeUndefined('@'),
348 codeContinue('\\')
349 {}
350
~ImdReader()351 ImdReader::~ImdReader() {}
352
ReadModel(const char * pszFilename)353 void ImdReader::ReadModel(const char *pszFilename) {
354 CPLDebug( "OGR_ILI", "Reading model '%s'", pszFilename);
355
356 CPLXMLNode* psRootNode = CPLParseXMLFile(pszFilename);
357 if( psRootNode == nullptr )
358 return;
359 CPLXMLNode *psSectionNode
360 = CPLGetXMLNode( psRootNode, "=TRANSFER.DATASECTION" );
361 if( psSectionNode == nullptr )
362 {
363 CPLDestroyXMLNode(psRootNode);
364 return;
365 }
366
367 StrNodeMap oTidLookup; /* for fast lookup of REF relations */
368 ClassesMap oClasses;
369 NodeCountMap oAxisCount;
370 NodeVector oArcLineTypes;
371
372 /* Fill TID lookup map and IliClasses lookup map */
373 CPLXMLNode* psModel = psSectionNode->psChild;
374 while( psModel != nullptr )
375 {
376 const char *modelName = CPLGetXMLValue( psModel, "BID", nullptr );
377 #ifdef DEBUG_VERBOSE
378 CPLDebug( "OGR_ILI", "Model: '%s'", modelName);
379 #endif
380
381 CPLXMLNode* psEntry = psModel->psChild;
382 while( psEntry != nullptr )
383 {
384 if (psEntry->eType != CXT_Attribute) //ignore BID
385 {
386 #ifdef DEBUG_VERBOSE
387 CPLDebug( "OGR_ILI", "Node tag: '%s'", psEntry->pszValue);
388 #endif
389 const char* psTID = CPLGetXMLValue( psEntry, "TID", nullptr );
390 if( psTID != nullptr )
391 oTidLookup[psTID] = psEntry;
392
393 if( EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.Model") &&
394 !EQUAL(modelName, "MODEL.INTERLIS"))
395 {
396 IliModelInfo modelInfo;
397 modelInfo.name = CPLGetXMLValue( psEntry, "Name", "OGR" );
398 modelInfo.version = CPLGetXMLValue( psEntry, "Version", "" );
399 modelInfo.uri = CPLGetXMLValue( psEntry, "At", "" );
400 modelInfos.push_back(modelInfo);
401 mainModelName = modelInfo.name; // FIXME: check model inheritance
402 //version = CPLGetXMLValue(psEntry, "iliVersion", "0"); //1 or 2.3
403
404 CPLXMLNode *psFormatNode
405 = CPLGetXMLNode( psEntry, "ili1Format" );
406 if (psFormatNode != nullptr)
407 {
408 psFormatNode = psFormatNode->psChild;
409 codeBlank = static_cast<char>(
410 atoi( CPLGetXMLValue(
411 psFormatNode, "blankCode", "95")));
412 codeUndefined = static_cast<char>(
413 atoi( CPLGetXMLValue(
414 psFormatNode, "undefinedCode", "64")));
415 codeContinue = static_cast<char>(
416 atoi( CPLGetXMLValue(
417 psFormatNode, "continueCode", "92")));
418 }
419 }
420 else if( EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.SubModel"))
421 {
422 mainBasketName = CPLGetXMLValue(psEntry, "TID", "OGR");
423 mainTopicName = CPLGetXMLValue(psEntry, "Name", "OGR");
424 }
425 else if( EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.Class") )
426 {
427 CPLDebug( "OGR_ILI", "Class name: '%s'", psTID);
428 oClasses[psEntry] = new IliClass(
429 psEntry, iliVersion, oTidLookup, oClasses, oAxisCount);
430 }
431 }
432 psEntry = psEntry->psNext;
433 }
434
435 // 2nd pass: add fields via TransferElement entries & role associations
436 psEntry = psModel->psChild;
437 while( psEntry != nullptr )
438 {
439 if (psEntry->eType != CXT_Attribute) //ignore BID
440 {
441 #ifdef DEBUG_VERBOSE
442 CPLDebug( "OGR_ILI", "Node tag: '%s'", psEntry->pszValue);
443 #endif
444 if( iliVersion == 1 &&
445 EQUAL( psEntry->pszValue,
446 "IlisMeta07.ModelData.Ili1TransferElement"))
447 {
448 const char* psClassRef = CPLGetXMLValue(
449 psEntry, "Ili1TransferClass.REF", nullptr );
450 const char* psElementRef
451 = CPLGetXMLValue( psEntry, "Ili1RefAttr.REF", nullptr );
452 int iOrderPos = atoi(CPLGetXMLValue(
453 psEntry, "Ili1RefAttr.ORDER_POS", "0" ))-1;
454 IliClass* psParentClass = oClasses[oTidLookup[psClassRef]];
455 CPLXMLNode* psElementNode = oTidLookup[psElementRef];
456 psParentClass->AddFieldNode(psElementNode, iOrderPos);
457 }
458 else if( EQUAL( psEntry->pszValue,
459 "IlisMeta07.ModelData.TransferElement"))
460 {
461 const char* psClassRef
462 = CPLGetXMLValue( psEntry, "TransferClass.REF", nullptr );
463 const char* psElementRef = CPLGetXMLValue(
464 psEntry, "TransferElement.REF", nullptr );
465 int iOrderPos = atoi(CPLGetXMLValue(
466 psEntry, "TransferElement.ORDER_POS", "0" ))-1;
467 IliClass* psParentClass = oClasses[oTidLookup[psClassRef]];
468 CPLXMLNode* psElementNode = oTidLookup[psElementRef];
469 psParentClass->AddFieldNode(psElementNode, iOrderPos);
470 }
471 else if( EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.Role"))
472 {
473 const char* psRefParent
474 = CPLGetXMLValue( psEntry, "Association.REF", nullptr );
475 int iOrderPos = atoi(
476 CPLGetXMLValue( psEntry,
477 "Association.ORDER_POS", "0" ))-1;
478 IliClass* psParentClass = oClasses[oTidLookup[psRefParent]];
479 if (psParentClass)
480 psParentClass->AddRoleNode(psEntry, iOrderPos);
481 }
482 else if( EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.AxisSpec"))
483 {
484 const char* psClassRef
485 = CPLGetXMLValue( psEntry, "CoordType.REF", nullptr );
486 // int iOrderPos = atoi(
487 // CPLGetXMLValue( psEntry, "Axis.ORDER_POS", "0" ))-1;
488 CPLXMLNode* psCoordTypeNode = oTidLookup[psClassRef];
489 oAxisCount[psCoordTypeNode] += 1;
490 }
491 else if( EQUAL( psEntry->pszValue,
492 "IlisMeta07.ModelData.LinesForm"))
493 {
494 const char* psLineForm
495 = CPLGetXMLValue( psEntry, "LineForm.REF", nullptr );
496 if (EQUAL(psLineForm, "INTERLIS.ARCS")) {
497 const char* psElementRef
498 = CPLGetXMLValue( psEntry, "LineType.REF", nullptr );
499 CPLXMLNode* psElementNode = oTidLookup[psElementRef];
500 oArcLineTypes.push_back(psElementNode);
501 }
502 }
503 }
504 psEntry = psEntry->psNext;
505 }
506
507 psModel = psModel->psNext;
508 }
509
510 /* Analyze class inheritance & add fields to class table defn */
511 for( ClassesMap::const_iterator it = oClasses.begin();
512 it != oClasses.end();
513 ++it )
514 {
515 #ifdef DEBUG_VERBOSE
516 CPLDebug( "OGR_ILI", "Class: '%s'", it->second->GetName());
517 #endif
518 const char* psRefSuper = CPLGetXMLValue( it->first, "Super.REF", nullptr );
519 if (psRefSuper) {
520 if (oTidLookup.find(psRefSuper) != oTidLookup.end() &&
521 oClasses.find(oTidLookup[psRefSuper]) != oClasses.end()) {
522 oClasses[oTidLookup[psRefSuper]]->hasDerivedClasses = true;
523 } else {
524 CPLError(CE_Warning, CPLE_AppDefined,
525 "Couldn't reference super class '%s'", psRefSuper);
526 }
527 }
528 it->second->InitFieldDefinitions();
529 it->second->AddFieldDefinitions(oArcLineTypes);
530 }
531
532 /* Filter relevant classes */
533 for( ClassesMap::const_iterator it = oClasses.begin();
534 it != oClasses.end();
535 ++it)
536 {
537 const char* className = it->second->GetIliName();
538 FeatureDefnInfo oClassInfo = it->second->tableDefs();
539 if (!STARTS_WITH_CI(className, "INTERLIS.") &&
540 oClassInfo.GetTableDefnRef())
541 featureDefnInfos.push_back(oClassInfo);
542 }
543
544 for (ClassesMap::iterator it = oClasses.begin(); it != oClasses.end(); ++it)
545 {
546 delete it->second;
547 }
548
549 CPLDestroyXMLNode(psRootNode);
550 }
551
GetFeatureDefnInfo(const char * pszLayerName)552 FeatureDefnInfo ImdReader::GetFeatureDefnInfo(const char *pszLayerName) {
553 FeatureDefnInfo featureDefnInfo;
554 for( FeatureDefnInfos::const_iterator it = featureDefnInfos.begin();
555 it != featureDefnInfos.end();
556 ++it )
557 {
558 OGRFeatureDefn* fdefn = it->GetTableDefnRef();
559 if (EQUAL(fdefn->GetName(), pszLayerName)) featureDefnInfo = *it;
560 }
561 return featureDefnInfo;
562 }
563