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 : }
|