1 : /******************************************************************************
2 : * $Id: ili2reader.cpp 15947 2008-12-13 22:53:24Z rouault $
3 : *
4 : * Project: Interlis 2 Reader
5 : * Purpose: Implementation of ILI2Reader class.
6 : * Author: Markus Schnider, Sourcepole AG
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2004, Pirmin Kalberer, Sourcepole AG
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 "ogr_ili2.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 :
34 : #include "ilihelper.h"
35 : #include "iomhelper.h"
36 : #include "ili2reader.h"
37 : #include "ili2readerp.h"
38 :
39 : using namespace std;
40 :
41 : CPL_CVSID("$Id: ili2reader.cpp 15947 2008-12-13 22:53:24Z rouault $");
42 :
43 : //
44 : // constants
45 : //
46 : static const char *ILI2_TID = "TID";
47 : static const char *ILI2_REF = "REF";
48 :
49 : static const int ILI2_STRING_TYPE = 0;
50 : static const int ILI2_COORD_TYPE = 1;
51 : static const int ILI2_ARC_TYPE = 2;
52 : static const int ILI2_POLYLINE_TYPE = 4;
53 : static const int ILI2_BOUNDARY_TYPE = 8;
54 : static const int ILI2_AREA_TYPE = 16; // also SURFACE
55 : static const int ILI2_GEOMCOLL_TYPE = 32;
56 :
57 : static const char *ILI2_COORD = "COORD";
58 : static const char *ILI2_ARC = "ARC";
59 : static const char *ILI2_POLYLINE = "POLYLINE";
60 : static const char *ILI2_BOUNDARY = "BOUNDARY";
61 : static const char *ILI2_AREA = "AREA";
62 : static const char *ILI2_SURFACE = "SURFACE";
63 :
64 :
65 : //
66 : // helper functions
67 : //
68 0 : int cmpStr(string s1, string s2) {
69 :
70 0 : string::const_iterator p1 = s1.begin();
71 0 : string::const_iterator p2 = s2.begin();
72 :
73 0 : while (p1 != s1.end() && p2 != s2.end()) {
74 0 : if (toupper(*p1) != toupper(*p2))
75 0 : return (toupper(*p1) < toupper(*p2)) ? -1 : 1;
76 0 : ++p1;
77 0 : ++p2;
78 : }
79 :
80 : return (s2.size() == s1.size()) ? 0 :
81 0 : (s1.size() < s2.size()) ? -1 : 1;
82 : }
83 :
84 0 : string ltrim(string tmpstr) {
85 0 : unsigned int i = 0;
86 0 : while (i < tmpstr.length() && (tmpstr[i] == ' ' || tmpstr[i] == '\t' || tmpstr[i] == '\r' || tmpstr[i] == '\n')) ++i;
87 0 : return i > 0 ? tmpstr.substr(i, tmpstr.length()-i) : tmpstr;
88 : }
89 :
90 0 : string rtrim(string tmpstr) {
91 0 : unsigned int i = tmpstr.length() - 1;
92 0 : while (i >= 0 && (tmpstr[i] == ' ' || tmpstr[i] == '\t' || tmpstr[i] == '\r' || tmpstr[i] == '\n')) --i;
93 0 : return i < tmpstr.length() - 1 ? tmpstr.substr(0, i+1) : tmpstr;
94 : }
95 :
96 0 : string trim(string tmpstr) {
97 0 : tmpstr = ltrim(tmpstr);
98 0 : tmpstr = rtrim(tmpstr);
99 0 : return tmpstr;
100 : }
101 :
102 0 : int getGeometryTypeOfElem(DOMElement* elem) {
103 0 : int type = ILI2_STRING_TYPE;
104 0 : char* pszTagName = XMLString::transcode(elem->getTagName());
105 :
106 0 : if (elem && elem->getNodeType() == DOMNode::ELEMENT_NODE) {
107 0 : if (cmpStr(ILI2_COORD, pszTagName) == 0) {
108 0 : type = ILI2_COORD_TYPE;
109 0 : } else if (cmpStr(ILI2_ARC, pszTagName) == 0) {
110 0 : type = ILI2_ARC_TYPE;
111 0 : } else if (cmpStr(ILI2_POLYLINE, pszTagName) == 0) {
112 0 : type = ILI2_POLYLINE_TYPE;
113 0 : } else if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0) {
114 0 : type = ILI2_BOUNDARY_TYPE;
115 0 : } else if (cmpStr(ILI2_AREA, pszTagName) == 0) {
116 0 : type = ILI2_AREA_TYPE;
117 0 : } else if (cmpStr(ILI2_SURFACE, pszTagName) == 0) {
118 0 : type = ILI2_AREA_TYPE;
119 : }
120 : }
121 0 : XMLString::release(&pszTagName);
122 0 : return type;
123 : }
124 :
125 0 : char *getObjValue(DOMElement *elem) {
126 0 : DOMElement *textElem = (DOMElement *)elem->getFirstChild();
127 :
128 0 : if ((textElem != NULL) && (textElem->getNodeType() == DOMNode::TEXT_NODE))
129 : {
130 0 : char* pszNodeValue = XMLString::transcode(textElem->getNodeValue());
131 0 : char* pszRet = CPLStrdup(pszNodeValue);
132 0 : XMLString::release(&pszNodeValue);
133 0 : return pszRet;
134 : }
135 :
136 0 : return NULL;
137 : }
138 :
139 0 : char *getREFValue(DOMElement *elem) {
140 0 : XMLCh* pszIli2_ref = XMLString::transcode(ILI2_REF);
141 0 : char* pszREFValue = XMLString::transcode(elem->getAttribute(pszIli2_ref));
142 0 : char* pszRet = CPLStrdup(pszREFValue);
143 0 : XMLString::release(&pszIli2_ref);
144 0 : XMLString::release(&pszREFValue);
145 0 : return pszRet;
146 : }
147 :
148 0 : OGRPoint *getPoint(DOMElement *elem) {
149 : // elem -> COORD (or ARC)
150 0 : OGRPoint *pt = new OGRPoint();
151 :
152 0 : DOMElement *coordElem = (DOMElement *)elem->getFirstChild();
153 0 : while (coordElem != NULL) {
154 0 : char* pszTagName = XMLString::transcode(coordElem->getTagName());
155 0 : char* pszObjValue = getObjValue(coordElem);
156 0 : if (cmpStr("C1", pszTagName) == 0)
157 0 : pt->setX(atof(pszObjValue));
158 0 : else if (cmpStr("C2", pszTagName) == 0)
159 0 : pt->setY(atof(pszObjValue));
160 0 : else if (cmpStr("C3", pszTagName) == 0)
161 0 : pt->setZ(atof(pszObjValue));
162 0 : CPLFree(pszObjValue);
163 0 : XMLString::release(&pszTagName);
164 0 : coordElem = (DOMElement *)coordElem->getNextSibling();
165 : }
166 0 : pt->flattenTo2D();
167 0 : return pt;
168 : }
169 :
170 0 : OGRLineString *ILI2Reader::getArc(DOMElement *elem) {
171 : // elem -> ARC
172 0 : OGRLineString *ls = new OGRLineString();
173 : // previous point -> start point
174 0 : OGRPoint *ptStart = getPoint((DOMElement *)elem->getPreviousSibling()); // COORD or ARC
175 : // end point
176 0 : OGRPoint *ptEnd = new OGRPoint();
177 : // point on the arc
178 0 : OGRPoint *ptOnArc = new OGRPoint();
179 0 : double radius = 0; // radius
180 :
181 0 : DOMElement *arcElem = (DOMElement *)elem->getFirstChild();
182 0 : while (arcElem != NULL) {
183 0 : char* pszTagName = XMLString::transcode(arcElem->getTagName());
184 0 : char* pszObjValue = getObjValue(arcElem);
185 0 : if (cmpStr("C1", pszTagName) == 0)
186 0 : ptEnd->setX(atof(pszObjValue));
187 0 : else if (cmpStr("C2", pszTagName) == 0)
188 0 : ptEnd->setY(atof(pszObjValue));
189 0 : else if (cmpStr("C3", pszTagName) == 0)
190 0 : ptEnd->setZ(atof(pszObjValue));
191 0 : else if (cmpStr("A1", pszTagName) == 0)
192 0 : ptOnArc->setX(atof(pszObjValue));
193 0 : else if (cmpStr("A2", pszTagName) == 0)
194 0 : ptOnArc->setY(atof(pszObjValue));
195 0 : else if (cmpStr("A3", pszTagName) == 0)
196 0 : ptOnArc->setZ(atof(pszObjValue));
197 0 : else if (cmpStr("R", pszTagName) == 0)
198 0 : radius = atof(pszObjValue);
199 0 : CPLFree(pszObjValue);
200 0 : XMLString::release(&pszTagName);
201 0 : arcElem = (DOMElement *)arcElem->getNextSibling();
202 : }
203 0 : ptEnd->flattenTo2D();
204 0 : ptOnArc->flattenTo2D();
205 0 : interpolateArc(ls, ptStart, ptOnArc, ptEnd, arcIncr);
206 0 : return ls;
207 : }
208 :
209 0 : OGRLineString *getLineString(DOMElement *elem) {
210 : // elem -> POLYLINE
211 0 : OGRLineString *ls = new OGRLineString();
212 :
213 0 : DOMElement *lineElem = (DOMElement *)elem->getFirstChild();
214 0 : while (lineElem != NULL) {
215 0 : char* pszTagName = XMLString::transcode(lineElem->getTagName());
216 0 : if (cmpStr(ILI2_COORD, pszTagName) == 0)
217 0 : ls->addPoint(getPoint(lineElem));
218 0 : else if (cmpStr(ILI2_ARC, pszTagName) == 0) {
219 : // end point
220 0 : OGRPoint *ptEnd = new OGRPoint();
221 : // point on the arc
222 0 : OGRPoint *ptOnArc = new OGRPoint();
223 : // radius
224 0 : double radius = 0;
225 :
226 0 : DOMElement *arcElem = (DOMElement *)lineElem->getFirstChild();
227 0 : while (arcElem != NULL) {
228 0 : char* pszTagName = XMLString::transcode(arcElem->getTagName());
229 0 : char* pszObjValue = getObjValue(arcElem);
230 0 : if (cmpStr("C1", pszTagName) == 0)
231 0 : ptEnd->setX(atof(pszObjValue));
232 0 : else if (cmpStr("C2", pszTagName) == 0)
233 0 : ptEnd->setY(atof(pszObjValue));
234 0 : else if (cmpStr("C3", pszTagName) == 0)
235 0 : ptEnd->setZ(atof(pszObjValue));
236 0 : else if (cmpStr("A1", pszTagName) == 0)
237 0 : ptOnArc->setX(atof(pszObjValue));
238 0 : else if (cmpStr("A2", pszTagName) == 0)
239 0 : ptOnArc->setY(atof(pszObjValue));
240 0 : else if (cmpStr("A3", pszTagName) == 0)
241 0 : ptOnArc->setZ(atof(pszObjValue));
242 0 : else if (cmpStr("R", pszTagName) == 0)
243 0 : radius = atof(pszObjValue);
244 0 : CPLFree(pszObjValue);
245 0 : XMLString::release(&pszTagName);
246 :
247 0 : arcElem = (DOMElement *)arcElem->getNextSibling();
248 : }
249 :
250 0 : ptEnd->flattenTo2D();
251 0 : ptOnArc->flattenTo2D();
252 0 : OGRPoint *ptStart = getPoint((DOMElement *)lineElem->getPreviousSibling()); // COORD or ARC
253 0 : interpolateArc(ls, ptStart, ptOnArc, ptEnd, PI/180);
254 : } /* else { // FIXME StructureValue in Polyline not yet supported
255 : } */
256 0 : XMLString::release(&pszTagName);
257 :
258 0 : lineElem = (DOMElement *)lineElem->getNextSibling();
259 : }
260 :
261 0 : return ls;
262 : }
263 :
264 0 : OGRLineString *getBoundary(DOMElement *elem) {
265 :
266 0 : DOMElement *lineElem = (DOMElement *)elem->getFirstChild();
267 0 : if (lineElem != NULL)
268 : {
269 0 : char* pszTagName = XMLString::transcode(lineElem->getTagName());
270 0 : if (cmpStr(ILI2_POLYLINE, pszTagName) == 0)
271 : {
272 0 : XMLString::release(&pszTagName);
273 0 : return getLineString(lineElem);
274 : }
275 0 : XMLString::release(&pszTagName);
276 : }
277 :
278 0 : return new OGRLineString;
279 : }
280 :
281 0 : OGRPolygon *getPolygon(DOMElement *elem) {
282 0 : OGRPolygon *pg = new OGRPolygon();
283 :
284 0 : DOMElement *boundaryElem = (DOMElement *)elem->getFirstChild(); // outer boundary
285 0 : while (boundaryElem != NULL) {
286 0 : char* pszTagName = XMLString::transcode(boundaryElem->getTagName());
287 0 : if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0)
288 0 : pg->addRing((OGRLinearRing *)getBoundary(boundaryElem));
289 0 : XMLString::release(&pszTagName);
290 0 : boundaryElem = (DOMElement *)boundaryElem->getNextSibling(); // inner boundaries
291 : }
292 :
293 0 : return pg;
294 : }
295 :
296 0 : OGRGeometry *ILI2Reader::getGeometry(DOMElement *elem, int type) {
297 0 : OGRGeometryCollection *gm = new OGRGeometryCollection();
298 :
299 0 : DOMElement *childElem = elem;
300 0 : while (childElem != NULL) {
301 0 : char* pszTagName = XMLString::transcode(childElem->getTagName());
302 0 : switch (type) {
303 : case ILI2_COORD_TYPE :
304 0 : if (cmpStr(ILI2_COORD, pszTagName) == 0)
305 : {
306 0 : delete gm;
307 0 : XMLString::release(&pszTagName);
308 0 : return getPoint(childElem);
309 : }
310 0 : break;
311 : case ILI2_ARC_TYPE :
312 : // is it possible here? It have to be a ARC or COORD before (getPreviousSibling)
313 0 : if (cmpStr(ILI2_ARC, pszTagName) == 0)
314 : {
315 0 : delete gm;
316 0 : XMLString::release(&pszTagName);
317 0 : return getArc(childElem);
318 : }
319 0 : break;
320 : case ILI2_POLYLINE_TYPE :
321 0 : if (cmpStr(ILI2_POLYLINE, pszTagName) == 0)
322 : {
323 0 : delete gm;
324 0 : XMLString::release(&pszTagName);
325 0 : return getLineString(childElem);
326 : }
327 0 : break;
328 : case ILI2_BOUNDARY_TYPE :
329 0 : if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0)
330 : {
331 0 : delete gm;
332 0 : XMLString::release(&pszTagName);
333 0 : return getLineString(childElem);
334 : }
335 0 : break;
336 : case ILI2_AREA_TYPE :
337 0 : if ((cmpStr(ILI2_AREA, pszTagName) == 0) ||
338 : (cmpStr(ILI2_SURFACE, pszTagName) == 0))
339 : {
340 0 : delete gm;
341 0 : XMLString::release(&pszTagName);
342 0 : return getPolygon(childElem);
343 : }
344 0 : break;
345 : default :
346 0 : if (type >= ILI2_GEOMCOLL_TYPE) {
347 0 : int subType = getGeometryTypeOfElem(childElem); //????
348 0 : gm->addGeometryDirectly(getGeometry(childElem, subType));
349 : }
350 : break;
351 : }
352 0 : XMLString::release(&pszTagName);
353 :
354 : // GEOMCOLL
355 0 : childElem = (DOMElement *)childElem->getNextSibling();
356 : }
357 :
358 0 : return gm;
359 : }
360 :
361 0 : const char* ILI2Reader::GetLayerName(IOM_BASKET model, IOM_OBJECT table) {
362 : static char layername[512];
363 0 : IOM_OBJECT topic = GetAttrObj(model, table, "container");
364 0 : layername[0] = '\0';
365 0 : strcat(layername, iom_getattrvalue(GetAttrObj(model, topic, "container"), "name"));
366 0 : strcat(layername, ".");
367 0 : strcat(layername, iom_getattrvalue(topic, "name"));
368 0 : strcat(layername, ".");
369 0 : strcat(layername, iom_getattrvalue(table, "name"));
370 0 : return layername;
371 : }
372 :
373 0 : void ILI2Reader::AddField(OGRLayer* layer, IOM_BASKET model, IOM_OBJECT obj) {
374 0 : const char* typenam = "Reference";
375 0 : if (EQUAL(iom_getobjecttag(obj),"iom04.metamodel.LocalAttribute")) typenam = GetTypeName(model, obj);
376 0 : if (EQUAL(typenam, "iom04.metamodel.SurfaceType")) {
377 0 : } else if (EQUAL(typenam, "iom04.metamodel.AreaType")) {
378 0 : } else if (EQUAL(typenam, "iom04.metamodel.PolylineType") ) {
379 0 : } else if (EQUAL(typenam, "iom04.metamodel.CoordType")) {
380 : } else {
381 0 : OGRFieldDefn fieldDef(iom_getattrvalue(obj, "name"), OFTString);
382 0 : layer->GetLayerDefn()->AddFieldDefn(&fieldDef);
383 0 : CPLDebug( "OGR_ILI", "Field %s: %s", fieldDef.GetNameRef(), typenam);
384 : }
385 0 : }
386 :
387 0 : int ILI2Reader::ReadModel(char **modelFilenames) {
388 :
389 : IOM_BASKET model;
390 : IOM_ITERATOR modelelei;
391 : IOM_OBJECT modelele;
392 :
393 0 : iom_init();
394 :
395 : // set error listener to a iom provided one, that just
396 : // dumps all errors to stderr
397 0 : iom_seterrlistener(iom_stderrlistener);
398 :
399 : // compile ili models
400 0 : model=iom_compileIli(CSLCount(modelFilenames), modelFilenames);
401 0 : if(!model){
402 0 : CPLError( CE_Failure, CPLE_FileIO, "iom_compileIli failed." );
403 0 : iom_end();
404 0 : return FALSE;
405 : }
406 :
407 : // read tables
408 0 : modelelei=iom_iteratorobject(model);
409 0 : modelele=iom_nextobject(modelelei);
410 0 : while(modelele){
411 0 : const char *tag=iom_getobjecttag(modelele);
412 0 : if (tag && EQUAL(tag,"iom04.metamodel.Table")) {
413 0 : const char* topic = iom_getattrvalue(GetAttrObj(model, modelele, "container"), "name");
414 0 : if (!EQUAL(topic, "INTERLIS")) {
415 0 : const char* layername = GetLayerName(model, modelele);
416 0 : OGRLayer* layer = new OGRILI2Layer(layername, NULL, 0, wkbUnknown, NULL);
417 0 : m_listLayer.push_back(layer);
418 0 : CPLDebug( "OGR_ILI", "Reading table model '%s'", layername );
419 :
420 : // read fields
421 : IOM_OBJECT fields[255];
422 : IOM_OBJECT roledefs[255];
423 0 : memset(fields, 0, 255);
424 0 : memset(roledefs, 0, 255);
425 0 : int maxIdx = -1;
426 0 : IOM_ITERATOR fieldit=iom_iteratorobject(model);
427 0 : for (IOM_OBJECT fieldele=iom_nextobject(fieldit); fieldele; fieldele=iom_nextobject(fieldit)){
428 0 : const char *etag=iom_getobjecttag(fieldele);
429 0 : if (etag && (EQUAL(etag,"iom04.metamodel.ViewableAttributesAndRoles"))) {
430 0 : IOM_OBJECT table = GetAttrObj(model, fieldele, "viewable");
431 0 : if (table == modelele) {
432 0 : IOM_OBJECT obj = GetAttrObj(model, fieldele, "attributesAndRoles");
433 0 : int ili1AttrIdx = GetAttrObjPos(fieldele, "attributesAndRoles")-1;
434 0 : if (EQUAL(iom_getobjecttag(obj),"iom04.metamodel.RoleDef")) {
435 : //??ili1AttrIdx = atoi(iom_getattrvalue(GetAttrObj(model, obj, "oppend"), "ili1AttrIdx"));
436 0 : roledefs[ili1AttrIdx] = obj;
437 : } else {
438 0 : fields[ili1AttrIdx] = obj;
439 : }
440 0 : if (ili1AttrIdx > maxIdx) maxIdx = ili1AttrIdx;
441 : //CPLDebug( "OGR_ILI", "Field %s Pos: %d", iom_getattrvalue(obj, "name"), ili1AttrIdx);
442 : }
443 : }
444 0 : iom_releaseobject(fieldele);
445 : }
446 0 : iom_releaseiterator(fieldit);
447 :
448 0 : for (int i=0; i<=maxIdx; i++) {
449 0 : IOM_OBJECT obj = fields[i];
450 0 : IOM_OBJECT roleobj = roledefs[i];
451 0 : if (roleobj) AddField(layer, model, roleobj);
452 0 : if (obj) AddField(layer, model, obj);
453 : }
454 : }
455 : }
456 0 : iom_releaseobject(modelele);
457 :
458 0 : modelele=iom_nextobject(modelelei);
459 : }
460 :
461 0 : iom_releaseiterator(modelelei);
462 :
463 0 : iom_releasebasket(model);
464 :
465 0 : iom_end();
466 :
467 0 : return 0;
468 : }
469 :
470 0 : char* fieldName(DOMElement* elem) {
471 0 : string fullname;
472 0 : int depth = 0;
473 : DOMNode *node;
474 0 : for (node = elem; node; node = node->getParentNode()) ++depth;
475 0 : depth-=3; //ignore root elements
476 :
477 : // We cannot do this sort of dynamic stack alloc on MSVC6.
478 : // DOMNode* elements[depth];
479 : DOMNode* elements[1000];
480 0 : CPLAssert( depth < (int)(sizeof(elements) / sizeof(DOMNode*)) );
481 :
482 0 : int d=0;
483 0 : for (node = elem; d<depth; node = node->getParentNode()) elements[d++] = node;
484 0 : for (d=depth-1; d>=0; --d) {
485 0 : if (d < depth-1) fullname += "_";
486 0 : char* pszNodeName = XMLString::transcode(elements[d]->getNodeName());
487 0 : fullname += pszNodeName;
488 0 : XMLString::release(&pszNodeName);
489 : }
490 0 : return CPLStrdup(fullname.c_str());
491 : }
492 :
493 0 : void ILI2Reader::setFieldDefn(OGRFeatureDefn *featureDef, DOMElement* elem) {
494 0 : int type = 0;
495 : //recursively search children
496 0 : for (DOMElement *childElem = (DOMElement *)elem->getFirstChild();
497 0 : type == 0 && childElem && childElem->getNodeType() == DOMNode::ELEMENT_NODE;
498 0 : childElem = (DOMElement*)childElem->getNextSibling()) {
499 0 : type = getGeometryTypeOfElem(childElem);
500 0 : if (type == 0) {
501 0 : if (childElem->getFirstChild() && childElem->getFirstChild()->getNodeType() == DOMNode::ELEMENT_NODE) {
502 0 : setFieldDefn(featureDef, childElem);
503 : } else {
504 0 : char *fName = fieldName(childElem);
505 0 : if (featureDef->GetFieldIndex(fName) == -1) {
506 0 : CPLDebug( "OGR_ILI", "AddFieldDefn: %s",fName );
507 0 : OGRFieldDefn oFieldDefn(fName, OFTString);
508 0 : featureDef->AddFieldDefn(&oFieldDefn);
509 : }
510 0 : CPLFree(fName);
511 : }
512 : }
513 : }
514 0 : }
515 :
516 0 : void ILI2Reader::SetFieldValues(OGRFeature *feature, DOMElement* elem) {
517 0 : int type = 0;
518 : //recursively search children
519 0 : for (DOMElement *childElem = (DOMElement *)elem->getFirstChild();
520 0 : type == 0 && childElem && childElem->getNodeType() == DOMNode::ELEMENT_NODE;
521 0 : childElem = (DOMElement*)childElem->getNextSibling()) {
522 0 : type = getGeometryTypeOfElem(childElem);
523 0 : if (type == 0) {
524 0 : if (childElem->getFirstChild() && childElem->getFirstChild()->getNodeType() == DOMNode::ELEMENT_NODE) {
525 0 : SetFieldValues(feature, childElem);
526 : } else {
527 0 : char *fName = fieldName(childElem);
528 0 : int fIndex = feature->GetFieldIndex(fName);
529 0 : if (fIndex != -1) {
530 0 : char * objVal = getObjValue(childElem);
531 0 : if (objVal == NULL)
532 0 : objVal = getREFValue(childElem); // only to try
533 0 : feature->SetField(fIndex, objVal);
534 0 : CPLFree(objVal);
535 : } else {
536 0 : m_missAttrs.push_back(fName);
537 : }
538 0 : CPLFree(fName);
539 : }
540 : } else {
541 0 : feature->SetGeometryDirectly(getGeometry(childElem, type));
542 : }
543 : }
544 0 : }
545 :
546 :
547 : //
548 : // ILI2Reader
549 : //
550 0 : IILI2Reader::~IILI2Reader() {
551 0 : }
552 :
553 0 : ILI2Reader::ILI2Reader() {
554 0 : m_poILI2Handler = NULL;
555 0 : m_poSAXReader = NULL;
556 0 : m_bReadStarted = FALSE;
557 :
558 0 : m_pszFilename = NULL;
559 :
560 0 : SetupParser();
561 0 : }
562 :
563 0 : ILI2Reader::~ILI2Reader() {
564 0 : CPLFree( m_pszFilename );
565 :
566 0 : CleanupParser();
567 :
568 0 : list<OGRLayer *>::const_iterator layerIt = m_listLayer.begin();
569 0 : while (layerIt != m_listLayer.end()) {
570 0 : OGRILI2Layer *tmpLayer = (OGRILI2Layer *)*layerIt;
571 0 : delete tmpLayer;
572 0 : layerIt++;
573 : }
574 0 : }
575 :
576 0 : void ILI2Reader::SetArcDegrees(double arcDegrees) {
577 0 : arcIncr = arcDegrees*PI/180;
578 0 : }
579 :
580 0 : void ILI2Reader::SetSourceFile( const char *pszFilename ) {
581 0 : CPLFree( m_pszFilename );
582 0 : m_pszFilename = CPLStrdup( pszFilename );
583 0 : }
584 :
585 0 : int ILI2Reader::SetupParser() {
586 :
587 : static int bXercesInitialized = FALSE;
588 :
589 0 : if( !bXercesInitialized )
590 : {
591 : try
592 : {
593 0 : XMLPlatformUtils::Initialize();
594 : }
595 :
596 0 : catch (const XMLException& toCatch)
597 : {
598 0 : char* msg = XMLString::transcode(toCatch.getMessage());
599 : CPLError( CE_Failure, CPLE_AppDefined,
600 : "Unable to initalize Xerces C++ based ILI2 reader. "
601 0 : "Error message:\n%s\n", msg );
602 0 : XMLString::release(&msg);
603 :
604 0 : return FALSE;
605 : }
606 0 : bXercesInitialized = TRUE;
607 : }
608 :
609 : // Cleanup any old parser.
610 0 : if( m_poSAXReader != NULL )
611 0 : CleanupParser();
612 :
613 : // Create and initialize parser.
614 0 : m_poSAXReader = XMLReaderFactory::createXMLReader();
615 :
616 0 : m_poILI2Handler = new ILI2Handler( this );
617 :
618 0 : m_poSAXReader->setContentHandler( m_poILI2Handler );
619 0 : m_poSAXReader->setErrorHandler( m_poILI2Handler );
620 0 : m_poSAXReader->setLexicalHandler( m_poILI2Handler );
621 0 : m_poSAXReader->setEntityResolver( m_poILI2Handler );
622 0 : m_poSAXReader->setDTDHandler( m_poILI2Handler );
623 :
624 : /* No Validation
625 : #if (OGR_ILI2_VALIDATION)
626 : m_poSAXReader->setFeature(
627 : XMLString::transcode("http://xml.org/sax/features/validation"), true);
628 : m_poSAXReader->setFeature(
629 : XMLString::transcode("http://xml.org/sax/features/namespaces"), true);
630 :
631 : m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, true );
632 : m_poSAXReader->setFeature( XMLUni::fgXercesSchema, true );
633 :
634 : // m_poSAXReader->setDoSchema(true);
635 : // m_poSAXReader->setValidationSchemaFullChecking(true);
636 : #else
637 : */
638 0 : XMLCh *tmpCh = XMLString::transcode("http://xml.org/sax/features/validation");
639 0 : m_poSAXReader->setFeature(tmpCh, false);
640 0 : XMLString::release(&tmpCh);
641 0 : tmpCh = XMLString::transcode("http://xml.org/sax/features/namespaces");
642 0 : m_poSAXReader->setFeature(tmpCh, false);
643 0 : XMLString::release(&tmpCh);
644 : //#endif
645 :
646 0 : m_bReadStarted = FALSE;
647 :
648 0 : return TRUE;
649 : }
650 :
651 0 : void ILI2Reader::CleanupParser() {
652 0 : if( m_poSAXReader == NULL )
653 0 : return;
654 :
655 0 : delete m_poSAXReader;
656 0 : m_poSAXReader = NULL;
657 :
658 0 : delete m_poILI2Handler;
659 0 : m_poILI2Handler = NULL;
660 :
661 0 : m_bReadStarted = FALSE;
662 : }
663 :
664 0 : int ILI2Reader::SaveClasses( const char *pszFile = NULL ) {
665 :
666 : // Add logic later to determine reasonable default schema file.
667 0 : if( pszFile == NULL )
668 0 : return FALSE;
669 :
670 : // parse and create layers and features
671 : try
672 : {
673 0 : m_poSAXReader->parse(pszFile);
674 : }
675 0 : catch (const SAXException& toCatch)
676 : {
677 0 : char* msg = XMLString::transcode(toCatch.getMessage());
678 : CPLError( CE_Failure, CPLE_AppDefined,
679 0 : "Parsing failed: %s\n", msg );
680 0 : XMLString::release(&msg);
681 :
682 0 : return FALSE;
683 : }
684 :
685 0 : if (m_missAttrs.size() != 0) {
686 0 : m_missAttrs.sort();
687 0 : m_missAttrs.unique();
688 0 : string attrs = "";
689 0 : list<string>::const_iterator it = m_missAttrs.begin();
690 0 : for (it = m_missAttrs.begin(); it != m_missAttrs.end(); ++it)
691 0 : attrs += *it + ", ";
692 :
693 : CPLError( CE_Warning, CPLE_NotSupported,
694 0 : "Failed to add new definition to existing layers, attributes not saved: %s", attrs.c_str() );
695 : }
696 :
697 0 : return TRUE;
698 : }
699 :
700 0 : list<OGRLayer *> ILI2Reader::GetLayers() {
701 0 : return m_listLayer;
702 : }
703 :
704 0 : int ILI2Reader::GetLayerCount() {
705 0 : return m_listLayer.size();
706 : }
707 :
708 :
709 0 : int ILI2Reader::AddFeature(DOMElement *elem) {
710 0 : bool newLayer = true;
711 0 : OGRLayer *curLayer = 0;
712 0 : char *pszName = XMLString::transcode(elem->getTagName());
713 :
714 : // test if this layer exist
715 0 : for (list<OGRLayer *>::reverse_iterator layerIt = m_listLayer.rbegin();
716 : layerIt != m_listLayer.rend();
717 : ++layerIt) {
718 0 : OGRFeatureDefn *fDef = (*layerIt)->GetLayerDefn();
719 0 : if (cmpStr(fDef->GetName(), pszName) == 0) {
720 0 : newLayer = false;
721 0 : curLayer = *layerIt;
722 0 : break;
723 : }
724 : }
725 :
726 : // add a layer
727 0 : if (newLayer) { // FIXME in Layer: SRS Writer Type datasource
728 0 : CPLDebug( "OGR_ILI", "Adding layer: %s", pszName );
729 : // new layer data
730 0 : OGRSpatialReference *poSRSIn = NULL; // FIXME fix values for initial layer
731 0 : int bWriterIn = 0;
732 0 : OGRwkbGeometryType eReqType = wkbUnknown;
733 0 : OGRILI2DataSource *poDSIn = NULL;
734 0 : curLayer = new OGRILI2Layer(pszName, poSRSIn, bWriterIn, eReqType, poDSIn);
735 0 : m_listLayer.push_back(curLayer);
736 : }
737 :
738 : // the feature and field definition
739 0 : OGRFeatureDefn *featureDef = curLayer->GetLayerDefn();
740 0 : if (newLayer) {
741 : // the TID feature
742 0 : OGRFieldDefn ofieldDefn (ILI2_TID, OFTString);
743 0 : featureDef->AddFieldDefn(&ofieldDefn);
744 :
745 0 : setFieldDefn(featureDef, elem);
746 : }
747 :
748 : // add the features
749 0 : OGRFeature *feature = new OGRFeature(featureDef);
750 :
751 : // the TID feature
752 0 : int fIndex = feature->GetFieldIndex(ILI2_TID);
753 0 : XMLCh *pszIli2_tid = XMLString::transcode(ILI2_TID);
754 0 : char *fChVal = XMLString::transcode(elem->getAttribute(pszIli2_tid));
755 0 : feature->SetField(fIndex, fChVal);
756 0 : XMLString::release (&pszIli2_tid);
757 0 : XMLString::release (&fChVal);
758 :
759 0 : SetFieldValues(feature, elem);
760 0 : curLayer->SetFeature(feature);
761 :
762 0 : XMLString::release (&pszName);
763 :
764 0 : return 0;
765 : }
766 :
767 0 : IILI2Reader *CreateILI2Reader() {
768 0 : return new ILI2Reader();
769 : }
770 :
771 174 : void DestroyILI2Reader(IILI2Reader* reader)
772 : {
773 174 : if (reader)
774 0 : delete reader;
775 174 : }
|