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