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