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