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