Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: JML Translator
4 : * Purpose: Implements OGRJMLLayer class.
5 : *
6 : ******************************************************************************
7 : * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
8 : *
9 : * SPDX-License-Identifier: MIT
10 : ****************************************************************************/
11 :
12 : #include "cpl_conv.h"
13 : #include "ogr_jml.h"
14 : #include "ogr_p.h"
15 :
16 : #ifdef HAVE_EXPAT
17 :
18 : constexpr int PARSER_BUF_SIZE = 8192;
19 :
20 : /************************************************************************/
21 : /* OGRJMLLayer() */
22 : /************************************************************************/
23 :
24 42 : OGRJMLLayer::OGRJMLLayer(const char *pszLayerName, OGRJMLDataset *poDSIn,
25 42 : VSILFILE *fpIn)
26 42 : : m_poDS(poDSIn), poFeatureDefn(new OGRFeatureDefn(pszLayerName)),
27 : nNextFID(0), fp(fpIn), bHasReadSchema(false), oParser(nullptr),
28 : currentDepth(0), bStopParsing(false), nWithoutEventCounter(0),
29 : nDataHandlerCounter(0), bAccumulateElementValue(false),
30 84 : pszElementValue(static_cast<char *>(CPLCalloc(1024, 1))),
31 : nElementValueLen(0), nElementValueAlloc(1024), poFeature(nullptr),
32 : ppoFeatureTab(nullptr), nFeatureTabLength(0), nFeatureTabIndex(0),
33 : bSchemaFinished(false), nJCSGMLInputTemplateDepth(0),
34 : nCollectionElementDepth(0), nFeatureCollectionDepth(0),
35 : nFeatureElementDepth(0), nGeometryElementDepth(0), nColumnDepth(0),
36 : nNameDepth(0), nTypeDepth(0), nAttributeElementDepth(0), iAttr(-1),
37 84 : iRGBField(-1)
38 : {
39 42 : SetDescription(poFeatureDefn->GetName());
40 42 : poFeatureDefn->Reference();
41 42 : }
42 :
43 : /************************************************************************/
44 : /* ~OGRJMLLayer() */
45 : /************************************************************************/
46 :
47 84 : OGRJMLLayer::~OGRJMLLayer()
48 :
49 : {
50 42 : if (oParser)
51 8 : XML_ParserFree(oParser);
52 42 : poFeatureDefn->Release();
53 :
54 42 : CPLFree(pszElementValue);
55 :
56 42 : for (int i = nFeatureTabIndex; i < nFeatureTabLength; i++)
57 0 : delete ppoFeatureTab[i];
58 42 : CPLFree(ppoFeatureTab);
59 :
60 42 : if (poFeature)
61 0 : delete poFeature;
62 84 : }
63 :
64 : /************************************************************************/
65 : /* GetLayerDefn() */
66 : /************************************************************************/
67 :
68 364 : OGRFeatureDefn *OGRJMLLayer::GetLayerDefn()
69 : {
70 364 : if (!bHasReadSchema)
71 8 : LoadSchema();
72 :
73 364 : return poFeatureDefn;
74 : }
75 :
76 5316 : static void XMLCALL startElementCbk(void *pUserData, const char *pszName,
77 : const char **ppszAttr)
78 : {
79 5316 : static_cast<OGRJMLLayer *>(pUserData)->startElementCbk(pszName, ppszAttr);
80 5316 : }
81 :
82 5316 : static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
83 : {
84 5316 : static_cast<OGRJMLLayer *>(pUserData)->endElementCbk(pszName);
85 5316 : }
86 :
87 16297 : static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
88 : {
89 16297 : static_cast<OGRJMLLayer *>(pUserData)->dataHandlerCbk(data, nLen);
90 16297 : }
91 :
92 : /************************************************************************/
93 : /* ResetReading() */
94 : /************************************************************************/
95 :
96 122 : void OGRJMLLayer::ResetReading()
97 :
98 : {
99 122 : nNextFID = 0;
100 :
101 122 : VSIFSeekL(fp, 0, SEEK_SET);
102 122 : VSIFClearErrL(fp);
103 122 : if (oParser)
104 114 : XML_ParserFree(oParser);
105 :
106 122 : oParser = OGRCreateExpatXMLParser();
107 122 : XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk);
108 122 : XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
109 122 : XML_SetUserData(oParser, this);
110 :
111 144 : for (int i = nFeatureTabIndex; i < nFeatureTabLength; i++)
112 22 : delete ppoFeatureTab[i];
113 122 : nFeatureTabIndex = 0;
114 122 : nFeatureTabLength = 0;
115 122 : delete poFeature;
116 122 : poFeature = nullptr;
117 :
118 122 : currentDepth = 0;
119 :
120 122 : nCollectionElementDepth = 0;
121 122 : nFeatureElementDepth = 0;
122 122 : nGeometryElementDepth = 0;
123 122 : nAttributeElementDepth = 0;
124 122 : iAttr = -1;
125 :
126 122 : bAccumulateElementValue = false;
127 122 : nElementValueLen = 0;
128 122 : pszElementValue[0] = '\0';
129 122 : }
130 :
131 : /************************************************************************/
132 : /* startElementCbk() */
133 : /************************************************************************/
134 :
135 5316 : void OGRJMLLayer::startElementCbk(const char *pszName, const char **ppszAttr)
136 : {
137 5316 : if (bStopParsing)
138 0 : return;
139 :
140 5316 : nWithoutEventCounter = 0;
141 :
142 1356 : if (nFeatureElementDepth > 0 && nAttributeElementDepth == 0 &&
143 6672 : nGeometryElementDepth == 0 && osGeometryElement.compare(pszName) == 0)
144 : {
145 157 : nGeometryElementDepth = currentDepth;
146 157 : bAccumulateElementValue = true;
147 : }
148 5159 : else if (nFeatureElementDepth > 0 && nAttributeElementDepth == 0 &&
149 1199 : nGeometryElementDepth == 0)
150 : {
151 : /* We assume that attributes are present in the order they are */
152 : /* declared, so as a first guess, we can try the aoColumns[iAttr + 1] */
153 885 : int i = (iAttr + 1 < poFeatureDefn->GetFieldCount()) ? -1 : 0;
154 4629 : for (; i < static_cast<int>(aoColumns.size()); i++)
155 : {
156 : const OGRJMLColumn &oColumn =
157 4420 : (i < 0) ? aoColumns[iAttr + 1] : aoColumns[i];
158 4420 : if (oColumn.osElementName != pszName)
159 3328 : continue;
160 :
161 1092 : if (oColumn.bIsBody)
162 : {
163 2028 : if (!oColumn.osAttributeName.empty() && ppszAttr != nullptr &&
164 1976 : ppszAttr[0] != nullptr && ppszAttr[1] != nullptr &&
165 3016 : oColumn.osAttributeName.compare(ppszAttr[0]) == 0 &&
166 988 : oColumn.osAttributeValue.compare(ppszAttr[1]) == 0)
167 : {
168 : /* <osElementName
169 : * osAttributeName="osAttributeValue">value</osElementName>
170 : */
171 :
172 572 : bAccumulateElementValue = true;
173 572 : nAttributeElementDepth = currentDepth;
174 572 : iAttr = (i < 0) ? iAttr + 1 : i;
175 572 : break;
176 : }
177 468 : else if (oColumn.osAttributeName.empty())
178 : {
179 : /* <osElementName>value</osElementName> */
180 :
181 52 : bAccumulateElementValue = true;
182 52 : nAttributeElementDepth = currentDepth;
183 52 : iAttr = (i < 0) ? iAttr + 1 : i;
184 52 : break;
185 : }
186 : }
187 104 : else if (!oColumn.osAttributeName.empty() && ppszAttr != nullptr &&
188 156 : ppszAttr[0] != nullptr && ppszAttr[1] != nullptr &&
189 52 : oColumn.osAttributeName.compare(ppszAttr[0]) == 0)
190 : {
191 : /* <osElementName osAttributeName="value"></osElementName> */
192 :
193 52 : AddStringToElementValue(ppszAttr[1], (int)strlen(ppszAttr[1]));
194 :
195 52 : nAttributeElementDepth = currentDepth;
196 52 : iAttr = (i < 0) ? iAttr + 1 : i;
197 52 : break;
198 : }
199 885 : }
200 : }
201 4274 : else if (nGeometryElementDepth > 0)
202 : {
203 314 : AddStringToElementValue("<", 1);
204 314 : AddStringToElementValue(pszName, (int)strlen(pszName));
205 :
206 314 : const char **papszIter = ppszAttr;
207 366 : while (papszIter && *papszIter != nullptr)
208 : {
209 52 : AddStringToElementValue(" ", 1);
210 52 : AddStringToElementValue(papszIter[0], (int)strlen(papszIter[0]));
211 52 : AddStringToElementValue("=\"", 2);
212 52 : AddStringToElementValue(papszIter[1], (int)strlen(papszIter[1]));
213 52 : AddStringToElementValue("\"", 1);
214 52 : papszIter += 2;
215 : }
216 :
217 314 : AddStringToElementValue(">", 1);
218 : }
219 4277 : else if (nFeatureCollectionDepth > 0 && nFeatureElementDepth == 0 &&
220 317 : osFeatureElement.compare(pszName) == 0)
221 : {
222 158 : nFeatureElementDepth = currentDepth;
223 158 : poFeature = new OGRFeature(poFeatureDefn);
224 : }
225 7445 : else if (nFeatureCollectionDepth == 0 &&
226 3643 : osCollectionElement.compare(pszName) == 0)
227 : {
228 54 : nFeatureCollectionDepth = currentDepth;
229 : }
230 :
231 5316 : currentDepth++;
232 : }
233 :
234 : /************************************************************************/
235 : /* StopAccumulate() */
236 : /************************************************************************/
237 :
238 970 : void OGRJMLLayer::StopAccumulate()
239 : {
240 970 : bAccumulateElementValue = false;
241 970 : nElementValueLen = 0;
242 970 : pszElementValue[0] = '\0';
243 970 : }
244 :
245 : /************************************************************************/
246 : /* endElementCbk() */
247 : /************************************************************************/
248 :
249 5316 : void OGRJMLLayer::endElementCbk(const char *pszName)
250 : {
251 5316 : if (bStopParsing)
252 0 : return;
253 :
254 5316 : nWithoutEventCounter = 0;
255 :
256 5316 : currentDepth--;
257 :
258 5316 : if (nAttributeElementDepth == currentDepth)
259 : {
260 730 : if (nElementValueLen)
261 624 : poFeature->SetField(iAttr, pszElementValue);
262 106 : else if (iAttr >= 0)
263 52 : poFeature->SetFieldNull(iAttr);
264 730 : nAttributeElementDepth = 0;
265 730 : StopAccumulate();
266 : }
267 4586 : else if (nGeometryElementDepth > 0 && currentDepth > nGeometryElementDepth)
268 : {
269 314 : AddStringToElementValue("</", 2);
270 314 : AddStringToElementValue(pszName, static_cast<int>(strlen(pszName)));
271 314 : AddStringToElementValue(">", 1);
272 : }
273 4272 : else if (nGeometryElementDepth == currentDepth)
274 : {
275 157 : if (nElementValueLen)
276 : {
277 : OGRGeometry *poGeom =
278 105 : OGRGeometry::FromHandle(OGR_G_CreateFromGML(pszElementValue));
279 210 : if (poGeom != nullptr &&
280 105 : poGeom->getGeometryType() == wkbGeometryCollection &&
281 0 : poGeom->IsEmpty())
282 : {
283 0 : delete poGeom;
284 : }
285 : else
286 105 : poFeature->SetGeometryDirectly(poGeom);
287 : }
288 :
289 157 : nGeometryElementDepth = 0;
290 157 : StopAccumulate();
291 : }
292 4115 : else if (nFeatureElementDepth == currentDepth)
293 : {
294 : /* Builds a style string from R_G_B if we don't already have a */
295 : /* style string */
296 158 : OGRGeometry *poGeom = poFeature->GetGeometryRef();
297 158 : unsigned int R = 0;
298 158 : unsigned int G = 0;
299 158 : unsigned int B = 0;
300 156 : if (iRGBField >= 0 && poFeature->IsFieldSetAndNotNull(iRGBField) &&
301 418 : poFeature->GetStyleString() == nullptr && poGeom != nullptr &&
302 104 : sscanf(poFeature->GetFieldAsString(iRGBField), "%02X%02X%02X", &R,
303 : &G, &B) == 3)
304 : {
305 : const OGRwkbGeometryType eGeomType =
306 104 : wkbFlatten(poGeom->getGeometryType());
307 104 : if (eGeomType == wkbPoint || eGeomType == wkbMultiPoint ||
308 52 : eGeomType == wkbLineString || eGeomType == wkbMultiLineString)
309 : {
310 52 : poFeature->SetStyleString(
311 52 : CPLSPrintf("PEN(c:#%02X%02X%02X)", R, G, B));
312 : }
313 52 : else if (eGeomType == wkbPolygon || eGeomType == wkbMultiPolygon)
314 : {
315 52 : poFeature->SetStyleString(
316 52 : CPLSPrintf("BRUSH(fc:#%02X%02X%02X)", R, G, B));
317 : }
318 : }
319 :
320 158 : poFeature->SetFID(nNextFID++);
321 :
322 298 : if ((m_poFilterGeom == nullptr || FilterGeometry(poGeom)) &&
323 140 : (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
324 : {
325 226 : ppoFeatureTab = static_cast<OGRFeature **>(CPLRealloc(
326 113 : ppoFeatureTab, sizeof(OGRFeature *) * (nFeatureTabLength + 1)));
327 113 : ppoFeatureTab[nFeatureTabLength] = poFeature;
328 113 : nFeatureTabLength++;
329 : }
330 : else
331 : {
332 45 : delete poFeature;
333 : }
334 158 : poFeature = nullptr;
335 158 : iAttr = -1;
336 :
337 158 : nFeatureElementDepth = 0;
338 : }
339 3957 : else if (nFeatureCollectionDepth == currentDepth)
340 : {
341 54 : nFeatureCollectionDepth = 0;
342 : }
343 : }
344 :
345 : /************************************************************************/
346 : /* AddStringToElementValue() */
347 : /************************************************************************/
348 :
349 3851 : void OGRJMLLayer::AddStringToElementValue(const char *data, int nLen)
350 : {
351 3851 : if (nLen > INT_MAX - nElementValueLen - 1 - 1000)
352 : {
353 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
354 : "Too much data in a single element");
355 0 : XML_StopParser(oParser, XML_FALSE);
356 0 : bStopParsing = true;
357 0 : return;
358 : }
359 3851 : if (nElementValueLen + nLen + 1 > nElementValueAlloc)
360 : {
361 0 : char *pszNewElementValue = static_cast<char *>(VSI_REALLOC_VERBOSE(
362 : pszElementValue, nElementValueLen + nLen + 1 + 1000));
363 0 : if (pszNewElementValue == nullptr)
364 : {
365 0 : XML_StopParser(oParser, XML_FALSE);
366 0 : bStopParsing = true;
367 0 : return;
368 : }
369 0 : nElementValueAlloc = nElementValueLen + nLen + 1 + 1000;
370 0 : pszElementValue = pszNewElementValue;
371 : }
372 3851 : memcpy(pszElementValue + nElementValueLen, data, nLen);
373 3851 : nElementValueLen += nLen;
374 3851 : pszElementValue[nElementValueLen] = '\0';
375 : }
376 :
377 : /************************************************************************/
378 : /* dataHandlerCbk() */
379 : /************************************************************************/
380 :
381 16297 : void OGRJMLLayer::dataHandlerCbk(const char *data, int nLen)
382 : {
383 16297 : if (bStopParsing)
384 0 : return;
385 :
386 16297 : nDataHandlerCounter++;
387 16297 : if (nDataHandlerCounter >= PARSER_BUF_SIZE)
388 : {
389 0 : CPLError(CE_Failure, CPLE_AppDefined,
390 : "File probably corrupted (million laugh pattern)");
391 0 : XML_StopParser(oParser, XML_FALSE);
392 0 : bStopParsing = true;
393 0 : return;
394 : }
395 :
396 16297 : nWithoutEventCounter = 0;
397 :
398 16297 : if (bAccumulateElementValue)
399 : {
400 1655 : AddStringToElementValue(data, nLen);
401 : }
402 : }
403 :
404 : /************************************************************************/
405 : /* GetNextFeature() */
406 : /************************************************************************/
407 :
408 131 : OGRFeature *OGRJMLLayer::GetNextFeature()
409 : {
410 131 : if (!bHasReadSchema)
411 0 : LoadSchema();
412 :
413 131 : if (bStopParsing)
414 0 : return nullptr;
415 :
416 131 : if (nFeatureTabIndex < nFeatureTabLength)
417 : {
418 48 : return ppoFeatureTab[nFeatureTabIndex++];
419 : }
420 :
421 83 : if (VSIFEofL(fp) || VSIFErrorL(fp))
422 29 : return nullptr;
423 :
424 54 : std::vector<char> aBuf(PARSER_BUF_SIZE);
425 :
426 54 : nFeatureTabLength = 0;
427 54 : nFeatureTabIndex = 0;
428 :
429 54 : nWithoutEventCounter = 0;
430 :
431 54 : int nDone = 0;
432 0 : do
433 : {
434 54 : nDataHandlerCounter = 0;
435 : unsigned int nLen =
436 54 : (unsigned int)VSIFReadL(aBuf.data(), 1, aBuf.size(), fp);
437 54 : nDone = (nLen < aBuf.size());
438 54 : if (XML_Parse(oParser, aBuf.data(), nLen, nDone) == XML_STATUS_ERROR)
439 : {
440 0 : CPLError(CE_Failure, CPLE_AppDefined,
441 : "XML parsing of JML file failed : %s "
442 : "at line %d, column %d",
443 : XML_ErrorString(XML_GetErrorCode(oParser)),
444 0 : (int)XML_GetCurrentLineNumber(oParser),
445 0 : (int)XML_GetCurrentColumnNumber(oParser));
446 0 : bStopParsing = true;
447 : }
448 54 : nWithoutEventCounter++;
449 54 : } while (!nDone && !bStopParsing && nFeatureTabLength == 0 &&
450 0 : nWithoutEventCounter < 10);
451 :
452 54 : if (nWithoutEventCounter == 10)
453 : {
454 0 : CPLError(CE_Failure, CPLE_AppDefined,
455 : "Too much data inside one element. File probably corrupted");
456 0 : bStopParsing = true;
457 : }
458 :
459 54 : return (nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++] : nullptr;
460 : }
461 :
462 304 : static void XMLCALL startElementLoadSchemaCbk(void *pUserData,
463 : const char *pszName,
464 : const char **ppszAttr)
465 : {
466 304 : static_cast<OGRJMLLayer *>(pUserData)->startElementLoadSchemaCbk(pszName,
467 : ppszAttr);
468 304 : }
469 :
470 296 : static void XMLCALL endElementLoadSchemaCbk(void *pUserData,
471 : const char *pszName)
472 : {
473 296 : static_cast<OGRJMLLayer *>(pUserData)->endElementLoadSchemaCbk(pszName);
474 296 : }
475 :
476 : /************************************************************************/
477 : /* LoadSchema() */
478 : /************************************************************************/
479 :
480 : /** This function parses the beginning of the file to detect the fields */
481 8 : void OGRJMLLayer::LoadSchema()
482 : {
483 8 : if (bHasReadSchema)
484 0 : return;
485 :
486 8 : bHasReadSchema = true;
487 :
488 8 : oParser = OGRCreateExpatXMLParser();
489 8 : XML_SetElementHandler(oParser, ::startElementLoadSchemaCbk,
490 : ::endElementLoadSchemaCbk);
491 8 : XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
492 8 : XML_SetUserData(oParser, this);
493 :
494 8 : VSIFSeekL(fp, 0, SEEK_SET);
495 :
496 16 : std::vector<char> aBuf(PARSER_BUF_SIZE);
497 8 : int nDone = 0;
498 0 : do
499 : {
500 8 : nDataHandlerCounter = 0;
501 : const unsigned int nLen = static_cast<unsigned int>(
502 8 : VSIFReadL(aBuf.data(), 1, aBuf.size(), fp));
503 8 : nDone = (nLen < aBuf.size());
504 8 : if (XML_Parse(oParser, aBuf.data(), nLen, nDone) == XML_STATUS_ERROR)
505 : {
506 3 : CPLError(CE_Failure, CPLE_AppDefined,
507 : "XML parsing of JML file failed : %s at line %d, "
508 : "column %d",
509 : XML_ErrorString(XML_GetErrorCode(oParser)),
510 3 : static_cast<int>(XML_GetCurrentLineNumber(oParser)),
511 3 : static_cast<int>(XML_GetCurrentColumnNumber(oParser)));
512 3 : bStopParsing = true;
513 : }
514 8 : nWithoutEventCounter++;
515 8 : } while (!nDone && !bStopParsing && !bSchemaFinished &&
516 0 : nWithoutEventCounter < 10);
517 :
518 8 : XML_ParserFree(oParser);
519 8 : oParser = nullptr;
520 :
521 8 : if (nWithoutEventCounter == 10)
522 : {
523 0 : CPLError(CE_Failure, CPLE_AppDefined,
524 : "Too much data inside one element. File probably corrupted");
525 0 : bStopParsing = true;
526 : }
527 :
528 15 : if (osCollectionElement.empty() || osFeatureElement.empty() ||
529 7 : osGeometryElement.empty())
530 : {
531 1 : CPLError(CE_Failure, CPLE_AppDefined,
532 : "Missing CollectionElement, FeatureElement or "
533 : "GeometryElement");
534 1 : bStopParsing = true;
535 : }
536 :
537 8 : if (!osSRSName.empty())
538 : {
539 1 : if (osSRSName.find("http://www.opengis.net/gml/srs/epsg.xml#") == 0)
540 : {
541 1 : OGRSpatialReference *poSRS = new OGRSpatialReference();
542 1 : poSRS->importFromEPSG(atoi(
543 : osSRSName
544 2 : .substr(strlen("http://www.opengis.net/gml/srs/epsg.xml#"))
545 : .c_str()));
546 1 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
547 1 : poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
548 1 : poSRS->Release();
549 : }
550 : }
551 :
552 8 : nJCSGMLInputTemplateDepth = 0;
553 8 : nCollectionElementDepth = 0;
554 8 : nFeatureCollectionDepth = 0;
555 8 : nFeatureElementDepth = 0;
556 8 : nGeometryElementDepth = 0;
557 8 : nColumnDepth = 0;
558 8 : nNameDepth = 0;
559 8 : nTypeDepth = 0;
560 8 : nAttributeElementDepth = 0;
561 :
562 8 : ResetReading();
563 : }
564 :
565 : /************************************************************************/
566 : /* startElementLoadSchemaCbk() */
567 : /************************************************************************/
568 :
569 304 : void OGRJMLLayer::startElementLoadSchemaCbk(const char *pszName,
570 : const char **ppszAttr)
571 : {
572 304 : if (bStopParsing)
573 0 : return;
574 :
575 304 : nWithoutEventCounter = 0;
576 :
577 304 : if (nJCSGMLInputTemplateDepth == 0 &&
578 111 : strcmp(pszName, "JCSGMLInputTemplate") == 0)
579 8 : nJCSGMLInputTemplateDepth = currentDepth;
580 296 : else if (nJCSGMLInputTemplateDepth > 0)
581 : {
582 193 : if (nCollectionElementDepth == 0 &&
583 193 : strcmp(pszName, "CollectionElement") == 0)
584 : {
585 7 : nCollectionElementDepth = currentDepth;
586 7 : bAccumulateElementValue = true;
587 : }
588 186 : else if (nFeatureElementDepth == 0 &&
589 186 : strcmp(pszName, "FeatureElement") == 0)
590 : {
591 7 : nFeatureElementDepth = currentDepth;
592 7 : bAccumulateElementValue = true;
593 : }
594 179 : else if (nGeometryElementDepth == 0 &&
595 179 : strcmp(pszName, "GeometryElement") == 0)
596 : {
597 7 : nGeometryElementDepth = currentDepth;
598 7 : bAccumulateElementValue = true;
599 : }
600 172 : else if (nColumnDepth == 0 && strcmp(pszName, "column") == 0)
601 : {
602 32 : nColumnDepth = currentDepth;
603 32 : oCurColumn.osName = "";
604 32 : oCurColumn.osType = "";
605 32 : oCurColumn.osElementName = "";
606 32 : oCurColumn.osAttributeName = "";
607 32 : oCurColumn.osAttributeValue = "";
608 32 : oCurColumn.bIsBody = false;
609 : }
610 140 : else if (nColumnDepth > 0)
611 : {
612 128 : if (nNameDepth == 0 && strcmp(pszName, "name") == 0)
613 : {
614 31 : nNameDepth = currentDepth;
615 31 : bAccumulateElementValue = true;
616 : }
617 97 : else if (nTypeDepth == 0 && strcmp(pszName, "type") == 0)
618 : {
619 31 : nTypeDepth = currentDepth;
620 31 : bAccumulateElementValue = true;
621 : }
622 66 : else if (strcmp(pszName, "valueElement") == 0)
623 : {
624 31 : const char **papszIter = ppszAttr;
625 115 : while (papszIter && *papszIter != nullptr)
626 : {
627 84 : if (strcmp(*papszIter, "elementName") == 0)
628 30 : oCurColumn.osElementName = papszIter[1];
629 54 : else if (strcmp(*papszIter, "attributeName") == 0)
630 25 : oCurColumn.osAttributeName = papszIter[1];
631 29 : else if (strcmp(*papszIter, "attributeValue") == 0)
632 25 : oCurColumn.osAttributeValue = papszIter[1];
633 84 : papszIter += 2;
634 : }
635 : }
636 35 : else if (strcmp(pszName, "valueLocation") == 0)
637 : {
638 31 : const char **papszIter = ppszAttr;
639 64 : while (papszIter && *papszIter != nullptr)
640 : {
641 33 : if (strcmp(*papszIter, "position") == 0)
642 31 : oCurColumn.bIsBody = strcmp(papszIter[1], "body") == 0;
643 2 : else if (strcmp(*papszIter, "attributeName") == 0)
644 2 : oCurColumn.osAttributeName = papszIter[1];
645 33 : papszIter += 2;
646 : }
647 : }
648 : }
649 : }
650 132 : else if (nFeatureCollectionDepth == 0 &&
651 29 : osCollectionElement.compare(pszName) == 0)
652 : {
653 6 : nFeatureCollectionDepth = currentDepth;
654 : }
655 97 : else if (nFeatureCollectionDepth > 0 &&
656 74 : currentDepth == nFeatureCollectionDepth + 2 &&
657 15 : strcmp(pszName, "gml:Box") == 0)
658 : {
659 1 : const char **papszIter = ppszAttr;
660 2 : while (papszIter && *papszIter != nullptr)
661 : {
662 1 : if (strcmp(*papszIter, "srsName") == 0)
663 1 : osSRSName = papszIter[1];
664 1 : papszIter += 2;
665 : }
666 1 : bSchemaFinished = true;
667 : }
668 288 : else if (nFeatureCollectionDepth >= 0 &&
669 184 : currentDepth >= nFeatureCollectionDepth + 1 &&
670 88 : osFeatureElement.compare(pszName) == 0)
671 : {
672 11 : bSchemaFinished = true;
673 : }
674 :
675 304 : currentDepth++;
676 : }
677 :
678 : /************************************************************************/
679 : /* endElementLoadSchemaCbk() */
680 : /************************************************************************/
681 :
682 296 : void OGRJMLLayer::endElementLoadSchemaCbk(const char * /* pszName */)
683 : {
684 296 : if (bStopParsing)
685 0 : return;
686 :
687 296 : nWithoutEventCounter = 0;
688 :
689 296 : currentDepth--;
690 :
691 296 : if (nJCSGMLInputTemplateDepth == currentDepth)
692 : {
693 12 : nJCSGMLInputTemplateDepth = 0;
694 : }
695 284 : else if (nCollectionElementDepth == currentDepth)
696 : {
697 7 : nCollectionElementDepth = 0;
698 7 : osCollectionElement = pszElementValue;
699 : #ifdef DEBUG_VERBOSE
700 : CPLDebug("JML", "osCollectionElement = %s",
701 : osCollectionElement.c_str());
702 : #endif
703 7 : StopAccumulate();
704 : }
705 277 : else if (nFeatureElementDepth == currentDepth)
706 : {
707 7 : nFeatureElementDepth = 0;
708 7 : osFeatureElement = pszElementValue;
709 : #ifdef DEBUG_VERBOSE
710 : CPLDebug("JML", "osFeatureElement = %s", osFeatureElement.c_str());
711 : #endif
712 7 : StopAccumulate();
713 : }
714 270 : else if (nGeometryElementDepth == currentDepth)
715 : {
716 7 : nGeometryElementDepth = 0;
717 7 : osGeometryElement = pszElementValue;
718 : #ifdef DEBUG_VERBOSE
719 : CPLDebug("JML", "osGeometryElement = %s", osGeometryElement.c_str());
720 : #endif
721 7 : StopAccumulate();
722 : }
723 263 : else if (nColumnDepth == currentDepth)
724 : {
725 32 : bool bIsOK = true;
726 32 : if (oCurColumn.osName.empty())
727 1 : bIsOK = false;
728 32 : if (oCurColumn.osType.empty())
729 1 : bIsOK = false;
730 32 : if (oCurColumn.osElementName.empty())
731 2 : bIsOK = false;
732 32 : if (oCurColumn.bIsBody)
733 : {
734 32 : if (oCurColumn.osAttributeName.empty() &&
735 4 : !oCurColumn.osAttributeValue.empty())
736 1 : bIsOK = false;
737 52 : if (!oCurColumn.osAttributeName.empty() &&
738 24 : oCurColumn.osAttributeValue.empty())
739 1 : bIsOK = false;
740 : /* Only 2 valid possibilities : */
741 : /* <osElementName
742 : * osAttributeName="osAttributeValue">value</osElementName> */
743 : /* <osElementName>value</osElementName> */
744 : }
745 : else
746 : {
747 : /* <osElementName osAttributeName="value"></osElementName> */
748 4 : if (oCurColumn.osAttributeName.empty())
749 1 : bIsOK = false;
750 4 : if (!oCurColumn.osAttributeValue.empty())
751 1 : bIsOK = false;
752 : }
753 :
754 32 : if (bIsOK)
755 : {
756 24 : OGRFieldType eType = OFTString;
757 24 : if (EQUAL(oCurColumn.osType, "INTEGER"))
758 2 : eType = OFTInteger;
759 22 : else if (EQUAL(oCurColumn.osType, "DOUBLE"))
760 2 : eType = OFTReal;
761 20 : else if (EQUAL(oCurColumn.osType, "DATE"))
762 4 : eType = OFTDateTime;
763 48 : OGRFieldDefn oField(oCurColumn.osName, eType);
764 :
765 24 : if (oCurColumn.osName == "R_G_B" && eType == OFTString)
766 2 : iRGBField = poFeatureDefn->GetFieldCount();
767 :
768 24 : poFeatureDefn->AddFieldDefn(&oField);
769 24 : aoColumns.push_back(oCurColumn);
770 : }
771 : else
772 : {
773 8 : CPLDebug("JML",
774 : "Invalid column definition: name = %s, type = %s, "
775 : "elementName = %s, attributeName = %s, "
776 : "attributeValue = %s, bIsBody = %d",
777 : oCurColumn.osName.c_str(), oCurColumn.osType.c_str(),
778 : oCurColumn.osElementName.c_str(),
779 : oCurColumn.osAttributeName.c_str(),
780 : oCurColumn.osAttributeValue.c_str(),
781 8 : static_cast<int>(oCurColumn.bIsBody));
782 : }
783 :
784 32 : nColumnDepth = 0;
785 : }
786 231 : else if (nNameDepth == currentDepth)
787 : {
788 31 : nNameDepth = 0;
789 31 : oCurColumn.osName = pszElementValue;
790 : #ifdef DEBUG_VERBOSE
791 : CPLDebug("JML", "oCurColumn.osName = %s", oCurColumn.osName.c_str());
792 : #endif
793 31 : StopAccumulate();
794 : }
795 200 : else if (nTypeDepth == currentDepth)
796 : {
797 31 : nTypeDepth = 0;
798 31 : oCurColumn.osType = pszElementValue;
799 : #ifdef DEBUG_VERBOSE
800 : CPLDebug("JML", "oCurColumn.osType = %s", oCurColumn.osType.c_str());
801 : #endif
802 31 : StopAccumulate();
803 : }
804 : }
805 :
806 : /************************************************************************/
807 : /* TestCapability() */
808 : /************************************************************************/
809 :
810 36 : int OGRJMLLayer::TestCapability(const char *pszCap)
811 :
812 : {
813 36 : if (EQUAL(pszCap, OLCStringsAsUTF8))
814 13 : return true;
815 23 : else if (EQUAL(pszCap, OLCZGeometries))
816 3 : return true;
817 :
818 20 : return false;
819 : }
820 :
821 : #endif /* HAVE_EXPAT */
|