Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Interlis 2 Reader
4 : * Purpose: Implementation of ILI2Reader class.
5 : * Author: Markus Schnider, Sourcepole AG
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2004, Pirmin Kalberer, Sourcepole AG
9 : * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "ili2readerp.h"
15 : #include "ogr_ili2.h"
16 : #include "cpl_conv.h"
17 : #include "cpl_string.h"
18 :
19 : #include "ili2reader.h"
20 :
21 : using namespace std;
22 :
23 : //
24 : // constants
25 : //
26 : static const char *const ILI2_TID = "TID";
27 : static const XMLCh xmlch_ILI2_TID[] = {'T', 'I', 'D', '\0'};
28 : static const XMLCh xmlch_ILI2_TID_NS[] = {'i', 'l', 'i', ':',
29 : 't', 'i', 'd', '\0'};
30 : static const XMLCh ILI2_REF[] = {'R', 'E', 'F', '\0'};
31 : static const XMLCh ILI2_REF_NS[] = {'i', 'l', 'i', ':', 'r', 'e', 'f', '\0'};
32 :
33 : constexpr int ILI2_STRING_TYPE = 0;
34 : constexpr int ILI2_COORD_TYPE = 1;
35 : constexpr int ILI2_ARC_TYPE = 2;
36 : constexpr int ILI2_POLYLINE_TYPE = 4;
37 : constexpr int ILI2_BOUNDARY_TYPE = 8;
38 : constexpr int ILI2_AREA_TYPE = 16; // also SURFACE
39 : constexpr int ILI2_GEOMCOLL_TYPE = 32;
40 :
41 : static const char *const ILI2_COORD = "COORD";
42 : static const char *const ILI2_ARC = "ARC";
43 : static const char *const ILI2_POLYLINE = "POLYLINE";
44 : static const char *const ILI2_BOUNDARY = "BOUNDARY";
45 : static const char *const ILI2_AREA = "AREA";
46 : static const char *const ILI2_SURFACE = "SURFACE";
47 :
48 : namespace gdal
49 : {
50 : namespace ili2
51 : {
52 : //
53 : // helper functions
54 : //
55 60501 : int cmpStr(const string &s1, const string &s2)
56 : {
57 60501 : string::const_iterator p1 = s1.begin();
58 60501 : string::const_iterator p2 = s2.begin();
59 :
60 155511 : while (p1 != s1.end() && p2 != s2.end())
61 : {
62 147402 : if (CPLToupper(static_cast<unsigned char>(*p1)) !=
63 147402 : CPLToupper(static_cast<unsigned char>(*p2)))
64 52392 : return (CPLToupper(static_cast<unsigned char>(*p1)) <
65 52392 : CPLToupper(static_cast<unsigned char>(*p2)))
66 52392 : ? -1
67 52392 : : 1;
68 95010 : ++p1;
69 95010 : ++p2;
70 : }
71 :
72 8109 : return (s2.size() == s1.size()) ? 0 : (s1.size() < s2.size()) ? -1 : 1;
73 : }
74 :
75 7579 : string ltrim(const string &tmpstr)
76 : {
77 7579 : size_t i = 0;
78 25848 : while (i < tmpstr.length() && (tmpstr[i] == ' ' || tmpstr[i] == '\t' ||
79 7579 : tmpstr[i] == '\r' || tmpstr[i] == '\n'))
80 10690 : ++i;
81 7579 : return i > 0 ? tmpstr.substr(i, tmpstr.length() - i) : tmpstr;
82 : }
83 :
84 7579 : string rtrim(const string &tmpstr)
85 : {
86 7579 : if (tmpstr.empty())
87 702 : return tmpstr;
88 6877 : size_t i = tmpstr.length() - 1U;
89 13756 : while (tmpstr[i] == ' ' || tmpstr[i] == '\t' || tmpstr[i] == '\r' ||
90 6877 : tmpstr[i] == '\n')
91 2 : --i;
92 6877 : return i < tmpstr.length() - 1 ? tmpstr.substr(0, i + 1) : tmpstr;
93 : }
94 :
95 7579 : string trim(const string &tmpstr)
96 : {
97 7579 : auto ret = ltrim(tmpstr);
98 7579 : ret = rtrim(ret);
99 7579 : return ret;
100 : }
101 : } // namespace ili2
102 : } // namespace gdal
103 :
104 : using namespace gdal::ili2;
105 :
106 7773 : static int getGeometryTypeOfElem(DOMElement *elem)
107 : {
108 7773 : int type = ILI2_STRING_TYPE;
109 7773 : if (elem == nullptr)
110 0 : return type;
111 7773 : char *pszTagName = XMLString::transcode(elem->getTagName());
112 :
113 7773 : if (elem->getNodeType() == DOMNode::ELEMENT_NODE)
114 : {
115 7773 : if (cmpStr(ILI2_COORD, pszTagName) == 0)
116 : {
117 48 : type = ILI2_COORD_TYPE;
118 : }
119 7725 : else if (cmpStr(ILI2_ARC, pszTagName) == 0)
120 : {
121 0 : type = ILI2_ARC_TYPE;
122 : }
123 7725 : else if (cmpStr(ILI2_POLYLINE, pszTagName) == 0)
124 : {
125 29 : type = ILI2_POLYLINE_TYPE;
126 : }
127 7696 : else if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0)
128 : {
129 0 : type = ILI2_BOUNDARY_TYPE;
130 : }
131 7696 : else if (cmpStr(ILI2_AREA, pszTagName) == 0)
132 : {
133 0 : type = ILI2_AREA_TYPE;
134 : }
135 7696 : else if (cmpStr(ILI2_SURFACE, pszTagName) == 0)
136 : {
137 121 : type = ILI2_AREA_TYPE;
138 : }
139 : }
140 7773 : XMLString::release(&pszTagName);
141 7773 : return type;
142 : }
143 :
144 7708 : static char *getObjValue(DOMElement *elem)
145 : {
146 7708 : DOMNode *child = elem->getFirstChild();
147 7708 : if ((child != nullptr) && (child->getNodeType() == DOMNode::TEXT_NODE))
148 : {
149 6549 : return CPLStrdup(transcode(child->getNodeValue()));
150 : }
151 :
152 1159 : return nullptr;
153 : }
154 :
155 1159 : static char *getREFValue(DOMElement *elem)
156 : {
157 1159 : const XMLCh *val = elem->hasAttribute(ILI2_REF)
158 1159 : ? elem->getAttribute(ILI2_REF)
159 370 : : elem->getAttribute(ILI2_REF_NS);
160 2318 : CPLString osREFValue(transcode(val));
161 2318 : return CPLStrdup(osREFValue);
162 : }
163 :
164 2226 : static OGRPoint *getPoint(DOMElement *elem)
165 : {
166 : // elem -> COORD (or ARC)
167 2226 : DOMElement *coordElem = dynamic_cast<DOMElement *>(elem->getFirstChild());
168 2226 : if (coordElem == nullptr)
169 0 : return nullptr;
170 2226 : OGRPoint *pt = new OGRPoint();
171 :
172 6678 : while (coordElem != nullptr)
173 : {
174 4452 : char *pszTagName = XMLString::transcode(coordElem->getTagName());
175 4452 : char *pszObjValue = getObjValue(coordElem);
176 4452 : if (pszObjValue)
177 : {
178 4452 : if (cmpStr("C1", pszTagName) == 0)
179 2226 : pt->setX(CPLAtof(pszObjValue));
180 2226 : else if (cmpStr("C2", pszTagName) == 0)
181 2226 : pt->setY(CPLAtof(pszObjValue));
182 0 : else if (cmpStr("C3", pszTagName) == 0)
183 0 : pt->setZ(CPLAtof(pszObjValue));
184 : }
185 4452 : CPLFree(pszObjValue);
186 4452 : XMLString::release(&pszTagName);
187 4452 : coordElem = dynamic_cast<DOMElement *>(coordElem->getNextSibling());
188 : }
189 2226 : pt->flattenTo2D();
190 2226 : return pt;
191 : }
192 :
193 0 : OGRCircularString *ILI2Reader::getArc(DOMElement *elem)
194 : {
195 : // previous point -> start point
196 0 : auto elemPrev = dynamic_cast<DOMElement *>(elem->getPreviousSibling());
197 0 : if (elemPrev == nullptr)
198 0 : return nullptr;
199 0 : OGRPoint *ptStart = getPoint(elemPrev); // COORD or ARC
200 0 : if (ptStart == nullptr)
201 0 : return nullptr;
202 :
203 : // elem -> ARC
204 0 : OGRCircularString *arc = new OGRCircularString();
205 : // end point
206 0 : OGRPoint *ptEnd = new OGRPoint();
207 : // point on the arc
208 0 : OGRPoint *ptOnArc = new OGRPoint();
209 : // double radius = 0; // radius
210 :
211 0 : DOMElement *arcElem = dynamic_cast<DOMElement *>(elem->getFirstChild());
212 0 : while (arcElem != nullptr)
213 : {
214 0 : char *pszTagName = XMLString::transcode(arcElem->getTagName());
215 0 : char *pszObjValue = getObjValue(arcElem);
216 0 : if (pszObjValue)
217 : {
218 0 : if (cmpStr("C1", pszTagName) == 0)
219 0 : ptEnd->setX(CPLAtof(pszObjValue));
220 0 : else if (cmpStr("C2", pszTagName) == 0)
221 0 : ptEnd->setY(CPLAtof(pszObjValue));
222 0 : else if (cmpStr("C3", pszTagName) == 0)
223 0 : ptEnd->setZ(CPLAtof(pszObjValue));
224 0 : else if (cmpStr("A1", pszTagName) == 0)
225 0 : ptOnArc->setX(CPLAtof(pszObjValue));
226 0 : else if (cmpStr("A2", pszTagName) == 0)
227 0 : ptOnArc->setY(CPLAtof(pszObjValue));
228 0 : else if (cmpStr("A3", pszTagName) == 0)
229 0 : ptOnArc->setZ(CPLAtof(pszObjValue));
230 0 : else if (cmpStr("R", pszTagName) == 0)
231 : {
232 : // radius = CPLAtof(pszObjValue);
233 : }
234 : }
235 0 : CPLFree(pszObjValue);
236 0 : XMLString::release(&pszTagName);
237 0 : arcElem = dynamic_cast<DOMElement *>(arcElem->getNextSibling());
238 : }
239 0 : arc->addPoint(ptStart);
240 0 : arc->addPoint(ptOnArc);
241 0 : arc->addPoint(ptEnd);
242 0 : delete ptStart;
243 0 : delete ptOnArc;
244 0 : delete ptEnd;
245 0 : return arc;
246 : }
247 :
248 81 : static OGRCompoundCurve *getPolyline(DOMElement *elem)
249 : {
250 : // elem -> POLYLINE
251 81 : OGRCompoundCurve *ogrCurve = new OGRCompoundCurve();
252 81 : OGRLineString *ls = new OGRLineString();
253 :
254 81 : DOMElement *lineElem = dynamic_cast<DOMElement *>(elem->getFirstChild());
255 2314 : while (lineElem != nullptr)
256 : {
257 2233 : char *pszTagName = XMLString::transcode(lineElem->getTagName());
258 2233 : if (cmpStr(ILI2_COORD, pszTagName) == 0)
259 : {
260 2203 : OGRPoint *poPoint = getPoint(lineElem);
261 2203 : if (poPoint)
262 : {
263 2203 : ls->addPoint(poPoint);
264 2203 : delete poPoint;
265 : }
266 : }
267 30 : else if (cmpStr(ILI2_ARC, pszTagName) == 0)
268 : {
269 : // Finish line and start arc
270 0 : if (ls->getNumPoints() > 1)
271 : {
272 0 : ogrCurve->addCurveDirectly(ls);
273 0 : ls = new OGRLineString();
274 : }
275 : else
276 : {
277 0 : ls->empty();
278 : }
279 0 : OGRCircularString *arc = new OGRCircularString();
280 : // end point
281 0 : OGRPoint *ptEnd = new OGRPoint();
282 : // point on the arc
283 0 : OGRPoint *ptOnArc = new OGRPoint();
284 : // radius
285 : // double radius = 0;
286 :
287 : DOMElement *arcElem =
288 0 : dynamic_cast<DOMElement *>(lineElem->getFirstChild());
289 0 : while (arcElem != nullptr)
290 : {
291 0 : char *pszTagName2 = XMLString::transcode(arcElem->getTagName());
292 0 : char *pszObjValue = getObjValue(arcElem);
293 0 : if (pszObjValue)
294 : {
295 0 : if (cmpStr("C1", pszTagName2) == 0)
296 0 : ptEnd->setX(CPLAtof(pszObjValue));
297 0 : else if (cmpStr("C2", pszTagName2) == 0)
298 0 : ptEnd->setY(CPLAtof(pszObjValue));
299 0 : else if (cmpStr("C3", pszTagName2) == 0)
300 0 : ptEnd->setZ(CPLAtof(pszObjValue));
301 0 : else if (cmpStr("A1", pszTagName2) == 0)
302 0 : ptOnArc->setX(CPLAtof(pszObjValue));
303 0 : else if (cmpStr("A2", pszTagName2) == 0)
304 0 : ptOnArc->setY(CPLAtof(pszObjValue));
305 0 : else if (cmpStr("A3", pszTagName2) == 0)
306 0 : ptOnArc->setZ(CPLAtof(pszObjValue));
307 0 : else if (cmpStr("R", pszTagName2) == 0)
308 : {
309 : // radius = CPLAtof(pszObjValue);
310 : }
311 : }
312 0 : CPLFree(pszObjValue);
313 0 : XMLString::release(&pszTagName2);
314 :
315 0 : arcElem = dynamic_cast<DOMElement *>(arcElem->getNextSibling());
316 : }
317 :
318 : auto elemPrev =
319 0 : dynamic_cast<DOMElement *>(lineElem->getPreviousSibling());
320 0 : if (elemPrev)
321 : {
322 0 : OGRPoint *ptStart = getPoint(elemPrev); // COORD or ARC
323 0 : if (ptStart)
324 0 : arc->addPoint(ptStart);
325 0 : delete ptStart;
326 : }
327 0 : arc->addPoint(ptOnArc);
328 0 : arc->addPoint(ptEnd);
329 0 : ogrCurve->addCurveDirectly(arc);
330 :
331 : // Add arc endpoint as next start point, if COORD sequence follows.
332 : DOMElement *nextElem =
333 0 : dynamic_cast<DOMElement *>(lineElem->getNextSibling());
334 0 : if (nextElem)
335 : {
336 : char *nextTagName =
337 0 : XMLString::transcode(nextElem->getTagName());
338 0 : if (cmpStr(ILI2_COORD, nextTagName) == 0)
339 : {
340 0 : ls->addPoint(ptEnd);
341 : }
342 0 : XMLString::release(&nextTagName);
343 : }
344 :
345 0 : delete ptEnd;
346 0 : delete ptOnArc;
347 : } /* else { // TODO: StructureValue in Polyline not yet supported
348 : } */
349 2233 : XMLString::release(&pszTagName);
350 :
351 2233 : lineElem = dynamic_cast<DOMElement *>(lineElem->getNextSibling());
352 : }
353 :
354 81 : if (ls->getNumPoints() > 1)
355 : {
356 81 : ogrCurve->addCurveDirectly(ls);
357 : }
358 : else
359 : {
360 0 : delete ls;
361 : }
362 81 : return ogrCurve;
363 : }
364 :
365 67 : static OGRCompoundCurve *getBoundary(DOMElement *elem)
366 : {
367 :
368 67 : DOMElement *lineElem = dynamic_cast<DOMElement *>(elem->getFirstChild());
369 67 : if (lineElem != nullptr)
370 : {
371 67 : char *pszTagName = XMLString::transcode(lineElem->getTagName());
372 67 : if (cmpStr(ILI2_POLYLINE, pszTagName) == 0)
373 : {
374 67 : XMLString::release(&pszTagName);
375 67 : return getPolyline(lineElem);
376 : }
377 0 : XMLString::release(&pszTagName);
378 : }
379 :
380 0 : return new OGRCompoundCurve();
381 : }
382 :
383 60 : static OGRCurvePolygon *getPolygon(DOMElement *elem)
384 : {
385 60 : OGRCurvePolygon *pg = new OGRCurvePolygon();
386 :
387 : DOMElement *boundaryElem =
388 60 : dynamic_cast<DOMElement *>(elem->getFirstChild()); // outer boundary
389 127 : while (boundaryElem != nullptr)
390 : {
391 67 : char *pszTagName = XMLString::transcode(boundaryElem->getTagName());
392 67 : if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0)
393 : {
394 67 : OGRCompoundCurve *poCC = getBoundary(boundaryElem);
395 67 : if (pg->addRingDirectly(poCC) != OGRERR_NONE)
396 : {
397 0 : delete poCC;
398 : }
399 : }
400 67 : XMLString::release(&pszTagName);
401 67 : boundaryElem = dynamic_cast<DOMElement *>(
402 67 : boundaryElem->getNextSibling()); // inner boundaries
403 : }
404 :
405 60 : return pg;
406 : }
407 :
408 97 : OGRGeometry *ILI2Reader::getGeometry(DOMElement *elem, int type)
409 : {
410 97 : OGRGeometryCollection *gm = new OGRGeometryCollection();
411 :
412 97 : DOMElement *childElem = elem;
413 97 : while (childElem != nullptr)
414 : {
415 97 : char *pszTagName = XMLString::transcode(childElem->getTagName());
416 97 : switch (type)
417 : {
418 23 : case ILI2_COORD_TYPE:
419 23 : if (cmpStr(ILI2_COORD, pszTagName) == 0)
420 : {
421 23 : delete gm;
422 23 : XMLString::release(&pszTagName);
423 97 : return getPoint(childElem);
424 : }
425 0 : break;
426 0 : case ILI2_ARC_TYPE:
427 : // is it possible here? It have to be a ARC or COORD before
428 : // (getPreviousSibling)
429 0 : if (cmpStr(ILI2_ARC, pszTagName) == 0)
430 : {
431 0 : delete gm;
432 0 : XMLString::release(&pszTagName);
433 0 : return getArc(childElem);
434 : }
435 0 : break;
436 14 : case ILI2_POLYLINE_TYPE:
437 14 : if (cmpStr(ILI2_POLYLINE, pszTagName) == 0)
438 : {
439 14 : delete gm;
440 14 : XMLString::release(&pszTagName);
441 14 : return getPolyline(childElem);
442 : }
443 0 : break;
444 0 : case ILI2_BOUNDARY_TYPE:
445 0 : if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0)
446 : {
447 0 : delete gm;
448 0 : XMLString::release(&pszTagName);
449 0 : return getPolyline(childElem);
450 : }
451 0 : break;
452 60 : case ILI2_AREA_TYPE:
453 180 : if ((cmpStr(ILI2_AREA, pszTagName) == 0) ||
454 120 : (cmpStr(ILI2_SURFACE, pszTagName) == 0))
455 : {
456 60 : delete gm;
457 60 : XMLString::release(&pszTagName);
458 60 : return getPolygon(childElem);
459 : }
460 0 : break;
461 0 : default:
462 0 : if (type >= ILI2_GEOMCOLL_TYPE)
463 : {
464 0 : int subType = getGeometryTypeOfElem(childElem); //????
465 0 : OGRGeometry *poSubGeom = getGeometry(childElem, subType);
466 0 : if (poSubGeom)
467 0 : gm->addGeometryDirectly(poSubGeom);
468 : }
469 0 : break;
470 : }
471 0 : XMLString::release(&pszTagName);
472 :
473 : // GEOMCOLL
474 0 : childElem = dynamic_cast<DOMElement *>(childElem->getNextSibling());
475 : }
476 :
477 0 : return gm;
478 : }
479 :
480 3 : int ILI2Reader::ReadModel(OGRILI2DataSource *poDS, ImdReader *poImdReader,
481 : const char *modelFilename)
482 : {
483 3 : poImdReader->ReadModel(modelFilename);
484 39 : for (FeatureDefnInfos::const_iterator it =
485 3 : poImdReader->featureDefnInfos.begin();
486 42 : it != poImdReader->featureDefnInfos.end(); ++it)
487 : {
488 39 : m_listLayer.push_back(std::make_unique<OGRILI2Layer>(
489 78 : it->GetTableDefnRef(), it->poGeomFieldInfos, poDS));
490 : }
491 3 : return 0;
492 : }
493 :
494 : // Detect field name of value element
495 3604 : static char *fieldName(DOMElement *elem)
496 : {
497 3604 : DOMNode *node = elem;
498 3604 : if (getGeometryTypeOfElem(elem))
499 : {
500 97 : int depth = 0; // Depth of value elem node
501 582 : for (node = elem; node; node = node->getParentNode())
502 485 : ++depth;
503 : // Field name is on level 4
504 97 : node = elem;
505 194 : for (int d = 0; d < depth - 4; ++d)
506 97 : node = node->getParentNode();
507 : }
508 3604 : if (node == nullptr)
509 : {
510 0 : CPLError(CE_Failure, CPLE_AssertionFailed, "node == NULL");
511 0 : return CPLStrdup("***bug***");
512 : }
513 3604 : return CPLStrdup(transcode(node->getNodeName()));
514 : }
515 :
516 14 : void ILI2Reader::setFieldDefn(OGRFeatureDefn *featureDef, DOMElement *elem)
517 : {
518 14 : int type = 0;
519 : // recursively search children
520 14 : for (DOMNode *childNode = elem->getFirstChild();
521 64 : type == 0 && childNode &&
522 25 : childNode->getNodeType() == DOMNode::ELEMENT_NODE;
523 25 : childNode = childNode->getNextSibling())
524 : {
525 25 : DOMElement *childElem = dynamic_cast<DOMElement *>(childNode);
526 25 : CPLAssert(childElem);
527 25 : type = getGeometryTypeOfElem(childElem);
528 25 : if (type == 0)
529 : {
530 39 : if (childElem->getFirstChild() &&
531 18 : childElem->getFirstChild()->getNodeType() ==
532 : DOMNode::ELEMENT_NODE)
533 : {
534 8 : setFieldDefn(featureDef, childElem);
535 : }
536 : else
537 : {
538 13 : char *fName = fieldName(childElem);
539 13 : if (featureDef->GetFieldIndex(fName) == -1)
540 : {
541 13 : CPLDebug("OGR_ILI", "AddFieldDefn: %s", fName);
542 26 : OGRFieldDefn oFieldDefn(fName, OFTString);
543 13 : featureDef->AddFieldDefn(&oFieldDefn);
544 : }
545 13 : CPLFree(fName);
546 : }
547 : }
548 : }
549 14 : }
550 :
551 1239 : void ILI2Reader::SetFieldValues(OGRFeature *feature, DOMElement *elem)
552 : {
553 1239 : int type = 0;
554 : // recursively search children
555 1239 : for (DOMNode *childNode = elem->getFirstChild();
556 9527 : type == 0 && childNode &&
557 4144 : childNode->getNodeType() == DOMNode::ELEMENT_NODE;
558 4144 : childNode = childNode->getNextSibling())
559 : {
560 4144 : DOMElement *childElem = dynamic_cast<DOMElement *>(childNode);
561 4144 : CPLAssert(childElem);
562 4144 : type = getGeometryTypeOfElem(childElem);
563 4144 : if (type == 0)
564 : {
565 6935 : if (childElem->getFirstChild() &&
566 2888 : childElem->getFirstChild()->getNodeType() ==
567 : DOMNode::ELEMENT_NODE)
568 : {
569 553 : SetFieldValues(feature, childElem);
570 : }
571 : else
572 : {
573 3494 : char *fName = fieldName(childElem);
574 3494 : int fIndex = feature->GetFieldIndex(fName);
575 3494 : if (fIndex != -1)
576 : {
577 3256 : char *objVal = getObjValue(childElem);
578 3256 : if (objVal == nullptr)
579 1159 : objVal = getREFValue(childElem); // only to try
580 3256 : feature->SetField(fIndex, objVal);
581 3256 : CPLFree(objVal);
582 : }
583 : else
584 : {
585 238 : CPLDebug("OGR_ILI", "Attribute '%s' not found", fName);
586 238 : m_missAttrs.push_back(fName);
587 : }
588 3494 : CPLFree(fName);
589 : }
590 : }
591 : else
592 : {
593 97 : char *fName = fieldName(childElem);
594 97 : int fIndex = feature->GetGeomFieldIndex(fName);
595 97 : OGRGeometry *geom = getGeometry(childElem, type);
596 97 : if (geom)
597 : {
598 97 : if (fIndex == -1)
599 : { // Unknown model
600 27 : feature->SetGeometryDirectly(geom);
601 : }
602 : else
603 : {
604 : OGRwkbGeometryType geomType =
605 70 : feature->GetGeomFieldDefnRef(fIndex)->GetType();
606 70 : if (geomType == wkbMultiLineString ||
607 : geomType == wkbPolygon)
608 : {
609 19 : feature->SetGeomFieldDirectly(
610 19 : fIndex, geom->getLinearGeometry());
611 19 : delete geom;
612 : }
613 : else
614 : {
615 51 : feature->SetGeomFieldDirectly(fIndex, geom);
616 : }
617 : }
618 : }
619 97 : CPLFree(fName);
620 : }
621 : }
622 1239 : }
623 :
624 : //
625 : // ILI2Reader
626 : //
627 4 : IILI2Reader::~IILI2Reader()
628 : {
629 4 : }
630 :
631 4 : ILI2Reader::ILI2Reader()
632 : : m_pszFilename(nullptr), m_poILI2Handler(nullptr), m_poSAXReader(nullptr),
633 4 : m_bReadStarted(FALSE), m_bXercesInitialized(false)
634 : {
635 4 : SetupParser();
636 4 : }
637 :
638 8 : ILI2Reader::~ILI2Reader()
639 : {
640 4 : CPLFree(m_pszFilename);
641 :
642 4 : CleanupParser();
643 :
644 4 : if (m_bXercesInitialized)
645 4 : OGRDeinitializeXerces();
646 8 : }
647 :
648 4 : void ILI2Reader::SetSourceFile(const char *pszFilename)
649 : {
650 4 : CPLFree(m_pszFilename);
651 4 : m_pszFilename = CPLStrdup(pszFilename);
652 4 : }
653 :
654 4 : int ILI2Reader::SetupParser()
655 : {
656 :
657 4 : if (!m_bXercesInitialized)
658 : {
659 4 : if (!OGRInitializeXerces())
660 0 : return FALSE;
661 4 : m_bXercesInitialized = true;
662 : }
663 :
664 : // Cleanup any old parser.
665 4 : if (m_poSAXReader != nullptr)
666 0 : CleanupParser();
667 :
668 : // Create and initialize parser.
669 4 : m_poSAXReader = XMLReaderFactory::createXMLReader();
670 :
671 4 : m_poILI2Handler = new ILI2Handler(this);
672 :
673 4 : m_poSAXReader->setContentHandler(m_poILI2Handler);
674 4 : m_poSAXReader->setErrorHandler(m_poILI2Handler);
675 4 : m_poSAXReader->setLexicalHandler(m_poILI2Handler);
676 4 : m_poSAXReader->setEntityResolver(m_poILI2Handler);
677 4 : m_poSAXReader->setDTDHandler(m_poILI2Handler);
678 4 : m_poSAXReader->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution,
679 4 : true);
680 :
681 : // No Validation
682 4 : m_poSAXReader->setFeature(XMLUni::fgSAX2CoreValidation, false);
683 4 : m_poSAXReader->setFeature(XMLUni::fgXercesSchema, false);
684 :
685 4 : m_bReadStarted = FALSE;
686 :
687 4 : return TRUE;
688 : }
689 :
690 4 : void ILI2Reader::CleanupParser()
691 : {
692 4 : if (m_poSAXReader == nullptr)
693 0 : return;
694 :
695 4 : delete m_poSAXReader;
696 4 : m_poSAXReader = nullptr;
697 :
698 4 : delete m_poILI2Handler;
699 4 : m_poILI2Handler = nullptr;
700 :
701 4 : m_bReadStarted = FALSE;
702 : }
703 :
704 4 : int ILI2Reader::SaveClasses(const char *pszFile = nullptr)
705 : {
706 :
707 : // Add logic later to determine reasonable default schema file.
708 4 : if (pszFile == nullptr)
709 0 : return FALSE;
710 :
711 4 : VSILFILE *fp = VSIFOpenL(pszFile, "rb");
712 4 : if (fp == nullptr)
713 0 : return FALSE;
714 :
715 4 : InputSource *is = OGRCreateXercesInputSource(fp);
716 :
717 : // parse and create layers and features
718 : try
719 : {
720 4 : CPLDebug("OGR_ILI", "Parsing %s", pszFile);
721 4 : m_poSAXReader->parse(*is);
722 4 : VSIFCloseL(fp);
723 4 : OGRDestroyXercesInputSource(is);
724 : }
725 0 : catch (const DOMException &toCatch)
726 : {
727 : // Can happen with createElement() in ILI2Handler::startElement()
728 0 : CPLError(CE_Failure, CPLE_AppDefined, "DOMException: %s\n",
729 0 : transcode(toCatch.getMessage()).c_str());
730 0 : VSIFCloseL(fp);
731 0 : OGRDestroyXercesInputSource(is);
732 0 : return FALSE;
733 : }
734 0 : catch (const SAXException &toCatch)
735 : {
736 0 : CPLError(CE_Failure, CPLE_AppDefined, "Parsing failed: %s\n",
737 0 : transcode(toCatch.getMessage()).c_str());
738 0 : VSIFCloseL(fp);
739 0 : OGRDestroyXercesInputSource(is);
740 0 : return FALSE;
741 : }
742 :
743 4 : if (!m_missAttrs.empty())
744 : {
745 1 : m_missAttrs.sort();
746 1 : m_missAttrs.unique();
747 2 : string attrs = "";
748 1 : list<string>::const_iterator it;
749 3 : for (it = m_missAttrs.begin(); it != m_missAttrs.end(); ++it)
750 2 : attrs += *it + ", ";
751 :
752 1 : CPLError(CE_Warning, CPLE_NotSupported,
753 : "Failed to add new definition to existing layers, attributes "
754 : "not saved: %s",
755 : attrs.c_str());
756 : }
757 :
758 4 : return TRUE;
759 : }
760 :
761 87 : std::vector<std::unique_ptr<OGRLayer>> &ILI2Reader::GetLayers()
762 : {
763 87 : return m_listLayer;
764 : }
765 :
766 50 : int ILI2Reader::GetLayerCount() const
767 : {
768 50 : return static_cast<int>(m_listLayer.size());
769 : }
770 :
771 686 : OGRLayer *ILI2Reader::GetLayer(const char *pszName)
772 : {
773 4860 : for (auto it = m_listLayer.rbegin(); it != m_listLayer.rend(); ++it)
774 : {
775 4854 : const OGRFeatureDefn *fDef = (*it)->GetLayerDefn();
776 4854 : if (cmpStr(fDef->GetName(), pszName) == 0)
777 : {
778 680 : return it->get();
779 : }
780 : }
781 6 : return nullptr;
782 : }
783 :
784 686 : int ILI2Reader::AddFeature(DOMElement *elem)
785 : {
786 1372 : CPLString osName(transcode(elem->getTagName()));
787 : // CPLDebug( "OGR_ILI", "Reading layer: %s", osName.c_str() );
788 :
789 : // test if this layer exist
790 686 : OGRILI2Layer *curLayer = cpl::down_cast<OGRILI2Layer *>(GetLayer(osName));
791 686 : const bool needsNewLayer = (curLayer == nullptr);
792 0 : std::unique_ptr<OGRILI2Layer> newLayer;
793 :
794 : // add a layer
795 686 : if (needsNewLayer)
796 : {
797 6 : CPLDebug("OGR_ILI", "Adding layer: %s", osName.c_str());
798 6 : OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn(osName);
799 6 : poFeatureDefn->SetGeomType(wkbUnknown);
800 12 : GeomFieldInfos oGeomFieldInfos;
801 6 : newLayer = std::make_unique<OGRILI2Layer>(poFeatureDefn,
802 6 : oGeomFieldInfos, nullptr);
803 6 : curLayer = newLayer.get();
804 : }
805 :
806 : // the feature and field definition
807 686 : OGRFeatureDefn *featureDef = curLayer->GetLayerDefn();
808 686 : if (needsNewLayer)
809 : {
810 : // add TID field
811 12 : OGRFieldDefn ofieldDefn(ILI2_TID, OFTString);
812 6 : featureDef->AddFieldDefn(&ofieldDefn);
813 :
814 6 : setFieldDefn(featureDef, elem);
815 : }
816 :
817 : // add the features
818 686 : OGRFeature *feature = new OGRFeature(featureDef);
819 :
820 : // assign TID
821 686 : int fIndex = feature->GetFieldIndex(ILI2_TID);
822 686 : if (fIndex != -1)
823 : {
824 686 : const XMLCh *val = elem->hasAttribute(xmlch_ILI2_TID)
825 686 : ? elem->getAttribute(xmlch_ILI2_TID)
826 482 : : elem->getAttribute(xmlch_ILI2_TID_NS);
827 686 : feature->SetField(fIndex, transcode(val).c_str());
828 : }
829 : else
830 : {
831 0 : CPLDebug("OGR_ILI", "'%s' not found", ILI2_TID);
832 : }
833 :
834 686 : SetFieldValues(feature, elem);
835 686 : curLayer->AddFeature(feature);
836 :
837 686 : if (needsNewLayer)
838 6 : m_listLayer.push_back(std::move(newLayer));
839 :
840 1372 : return 0;
841 : }
842 :
843 4 : IILI2Reader *CreateILI2Reader()
844 : {
845 4 : return new ILI2Reader();
846 : }
847 :
848 26069 : void DestroyILI2Reader(IILI2Reader *reader)
849 : {
850 26069 : if (reader)
851 4 : delete reader;
852 26069 : }
|