Line data Source code
1 : /******************************************************************************
2 : * Project: OGR
3 : * Purpose: OGRGMLASDriver implementation
4 : * Author: Even Rouault, <even dot rouault at spatialys dot com>
5 : *
6 : * Initial development funded by the European Earth observation programme
7 : * Copernicus
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "ogr_gmlas.h"
16 :
17 : #include "ogr_p.h"
18 :
19 : #include "cpl_json_header.h"
20 :
21 : #include <algorithm>
22 :
23 : /************************************************************************/
24 : /* GMLASBinInputStream */
25 : /************************************************************************/
26 :
27 : class GMLASBinInputStream : public BinInputStream
28 : {
29 : VSILFILE *m_fp = nullptr;
30 :
31 : CPL_DISALLOW_COPY_ASSIGN(GMLASBinInputStream)
32 :
33 : public:
34 : explicit GMLASBinInputStream(VSILFILE *fp);
35 : virtual ~GMLASBinInputStream();
36 :
37 : virtual XMLFilePos curPos() const override;
38 : virtual XMLSize_t readBytes(XMLByte *const toFill,
39 : const XMLSize_t maxToRead) override;
40 : virtual const XMLCh *getContentType() const override;
41 : };
42 :
43 : /************************************************************************/
44 : /* GMLASBinInputStream() */
45 : /************************************************************************/
46 :
47 2894 : GMLASBinInputStream::GMLASBinInputStream(VSILFILE *fp)
48 : {
49 2894 : m_fp = fp;
50 2894 : VSIFSeekL(fp, 0, SEEK_SET);
51 2894 : }
52 :
53 : /************************************************************************/
54 : /* ~GMLASBinInputStream() */
55 : /************************************************************************/
56 :
57 5788 : GMLASBinInputStream::~GMLASBinInputStream()
58 : {
59 5788 : }
60 :
61 : /************************************************************************/
62 : /* curPos() */
63 : /************************************************************************/
64 :
65 0 : XMLFilePos GMLASBinInputStream::curPos() const
66 : {
67 0 : return static_cast<XMLFilePos>(VSIFTellL(m_fp));
68 : }
69 :
70 : /************************************************************************/
71 : /* readBytes() */
72 : /************************************************************************/
73 :
74 7973 : XMLSize_t GMLASBinInputStream::readBytes(XMLByte *const toFill,
75 : const XMLSize_t maxToRead)
76 : {
77 7973 : return static_cast<XMLSize_t>(VSIFReadL(toFill, 1, maxToRead, m_fp));
78 : }
79 :
80 : /************************************************************************/
81 : /* getContentType() */
82 : /************************************************************************/
83 :
84 0 : const XMLCh *GMLASBinInputStream::getContentType() const
85 : {
86 0 : return nullptr;
87 : }
88 :
89 : /************************************************************************/
90 : /* GMLASInputSource() */
91 : /************************************************************************/
92 :
93 3322 : GMLASInputSource::GMLASInputSource(const char *pszFilename,
94 : const std::shared_ptr<VSIVirtualHandle> &fp,
95 3322 : MemoryManager *const manager)
96 3322 : : InputSource(manager), m_fp(fp), m_pnCounter(&m_nCounter),
97 3322 : m_osFilename(pszFilename)
98 : {
99 : try
100 : {
101 3322 : XMLCh *pFilename = XMLString::transcode(pszFilename);
102 3322 : setPublicId(pFilename);
103 3322 : setSystemId(pFilename);
104 3322 : XMLString::release(&pFilename);
105 : }
106 0 : catch (const TranscodingException &e)
107 : {
108 0 : CPLError(CE_Failure, CPLE_AppDefined, "TranscodingException: %s",
109 0 : transcode(e.getMessage()).c_str());
110 : }
111 3322 : }
112 :
113 : /************************************************************************/
114 : /* SetClosingCallback() */
115 : /************************************************************************/
116 :
117 835 : void GMLASInputSource::SetClosingCallback(IGMLASInputSourceClosing *cbk)
118 : {
119 835 : m_cbk = cbk;
120 835 : }
121 :
122 : /************************************************************************/
123 : /* ~GMLASInputSource() */
124 : /************************************************************************/
125 :
126 5395 : GMLASInputSource::~GMLASInputSource()
127 : {
128 3322 : if (m_cbk)
129 835 : m_cbk->notifyClosing(m_osFilename);
130 5395 : }
131 :
132 : /************************************************************************/
133 : /* makeStream() */
134 : /************************************************************************/
135 :
136 2896 : BinInputStream *GMLASInputSource::makeStream() const
137 : {
138 : // This is a lovely cheating around the const qualifier of this method !
139 : // We cannot modify m_nCounter directly, but we can change the value
140 : // pointed by m_pnCounter...
141 2896 : if (*m_pnCounter != 0)
142 : {
143 0 : CPLError(CE_Failure, CPLE_AppDefined,
144 : "makeStream() called several times on same GMLASInputSource");
145 0 : return nullptr;
146 : }
147 2896 : (*m_pnCounter)++;
148 2896 : if (m_fp == nullptr)
149 2 : return nullptr;
150 2894 : return new GMLASBinInputStream(m_fp.get());
151 : }
152 :
153 : /************************************************************************/
154 : /* warning() */
155 : /************************************************************************/
156 :
157 2 : void GMLASErrorHandler::warning(const SAXParseException &e)
158 : {
159 2 : handle(e, CE_Warning);
160 2 : }
161 :
162 : /************************************************************************/
163 : /* error() */
164 : /************************************************************************/
165 :
166 226 : void GMLASErrorHandler::error(const SAXParseException &e)
167 : {
168 226 : m_bFailed = true;
169 226 : handle(e, CE_Failure);
170 226 : }
171 :
172 : /************************************************************************/
173 : /* fatalError() */
174 : /************************************************************************/
175 :
176 4 : void GMLASErrorHandler::fatalError(const SAXParseException &e)
177 : {
178 4 : m_bFailed = true;
179 4 : handle(e, CE_Failure);
180 4 : }
181 :
182 : /************************************************************************/
183 : /* handle() */
184 : /************************************************************************/
185 :
186 232 : void GMLASErrorHandler::handle(const SAXParseException &e, CPLErr eErr)
187 : {
188 232 : const XMLCh *resourceId(e.getPublicId());
189 :
190 232 : if (resourceId == nullptr || resourceId[0] == 0)
191 112 : resourceId = e.getSystemId();
192 :
193 464 : CPLString osErrorMsg(transcode(e.getMessage()));
194 464 : if (m_bSchemaFullChecking &&
195 232 : osErrorMsg.find("forbidden restriction of any particle") !=
196 : std::string::npos)
197 : {
198 0 : osErrorMsg += ". You may retry with the " +
199 0 : CPLString(szSCHEMA_FULL_CHECKING_OPTION) +
200 0 : "=NO open option";
201 : }
202 464 : else if (!m_bHandleMultipleImports &&
203 232 : osErrorMsg.find("not found") != std::string::npos)
204 : {
205 8 : osErrorMsg += ". You may retry with the " +
206 24 : CPLString(szHANDLE_MULTIPLE_IMPORTS_OPTION) +
207 8 : "=YES open option";
208 : }
209 :
210 464 : CPLString osFullErrorMsg;
211 232 : osFullErrorMsg.Printf("%s:%d:%d %s", transcode(resourceId).c_str(),
212 464 : static_cast<int>(e.getLineNumber()),
213 232 : static_cast<int>(e.getColumnNumber()),
214 464 : osErrorMsg.c_str());
215 :
216 445 : if (m_bHideGMLTypeNotFound && m_osGMLTypeNotFoundError.empty() &&
217 213 : osErrorMsg.find(
218 : "http://www.opengis.net/gml/3.2:AbstractCRS' not found") !=
219 : std::string::npos)
220 : {
221 2 : m_osGMLTypeNotFoundError = std::move(osFullErrorMsg);
222 : }
223 230 : else if (m_bHideGMLTypeNotFound && !m_osGMLTypeNotFoundError.empty())
224 : {
225 : // do nothing
226 : }
227 : else
228 : {
229 224 : CPLError(eErr, CPLE_AppDefined, "%s", osFullErrorMsg.c_str());
230 : }
231 232 : }
232 :
233 : /************************************************************************/
234 : /* GMLASBaseEntityResolver() */
235 : /************************************************************************/
236 :
237 234 : GMLASBaseEntityResolver::GMLASBaseEntityResolver(const CPLString &osBasePath,
238 234 : GMLASXSDCache &oCache)
239 234 : : m_oCache(oCache)
240 : {
241 234 : m_aosPathStack.push_back(osBasePath);
242 234 : }
243 :
244 : /************************************************************************/
245 : /* ~GMLASBaseEntityResolver() */
246 : /************************************************************************/
247 :
248 284 : GMLASBaseEntityResolver::~GMLASBaseEntityResolver()
249 : {
250 234 : CPLAssert(m_aosPathStack.size() == 1);
251 284 : }
252 :
253 : /************************************************************************/
254 : /* notifyClosing() */
255 : /************************************************************************/
256 :
257 : /* Called by GMLASInputSource destructor. This is useful for use to */
258 : /* know where a .xsd has been finished from processing. Note that we */
259 : /* strongly depend on Xerces behavior here... */
260 835 : void GMLASBaseEntityResolver::notifyClosing(const CPLString &osFilename)
261 : {
262 835 : CPLDebug("GMLAS", "Closing %s", osFilename.c_str());
263 :
264 835 : CPLAssert(m_aosPathStack.back() == CPLString(CPLGetDirname(osFilename)));
265 835 : m_aosPathStack.pop_back();
266 835 : }
267 :
268 : /************************************************************************/
269 : /* SetBasePath() */
270 : /************************************************************************/
271 :
272 259 : void GMLASBaseEntityResolver::SetBasePath(const CPLString &osBasePath)
273 : {
274 259 : CPLAssert(m_aosPathStack.size() == 1);
275 259 : m_aosPathStack[0] = osBasePath;
276 259 : }
277 :
278 : /************************************************************************/
279 : /* DoExtraSchemaProcessing() */
280 : /************************************************************************/
281 :
282 254 : void GMLASBaseEntityResolver::DoExtraSchemaProcessing(
283 : const CPLString & /*osFilename*/,
284 : const std::shared_ptr<VSIVirtualHandle> & /*fp*/)
285 : {
286 254 : }
287 :
288 : /************************************************************************/
289 : /* resolveEntity() */
290 : /************************************************************************/
291 :
292 : InputSource *
293 835 : GMLASBaseEntityResolver::resolveEntity(const XMLCh *const /*publicId*/,
294 : const XMLCh *const systemId)
295 : {
296 : // Can happen on things like <xs:import
297 : // namespace="http://www.w3.org/XML/1998/namespace"/>
298 835 : if (systemId == nullptr)
299 0 : return nullptr;
300 :
301 1670 : CPLString osSystemId(transcode(systemId));
302 :
303 835 : if (osSystemId.find("/gml/2.1.2/") != std::string::npos)
304 0 : m_osGMLVersionFound = "2.1.2";
305 835 : else if (osSystemId.find("/gml/3.1.1/") != std::string::npos)
306 0 : m_osGMLVersionFound = "3.1.1";
307 835 : else if (osSystemId.find("/gml/3.2.1/") != std::string::npos)
308 15 : m_osGMLVersionFound = "3.2.1";
309 :
310 835 : constexpr const char *GML_321_LOC_SUFFIX = "/gml/3.2.1/gml.xsd";
311 835 : constexpr const char *GML_321_OGC_SCHEMA_LOC =
312 : "http://schemas.opengis.net/gml/3.2.1/gml.xsd";
313 835 : if (osSystemId.size() > strlen(GML_321_LOC_SUFFIX) &&
314 640 : strcmp(osSystemId.c_str() + osSystemId.size() -
315 : strlen(GML_321_LOC_SUFFIX),
316 1475 : GML_321_LOC_SUFFIX) == 0 &&
317 15 : osSystemId != GML_321_OGC_SCHEMA_LOC)
318 : {
319 2 : m_bFoundNonOfficialGMLSchemaLocation = true;
320 2 : if (m_bSubstituteWithOGCSchemaLocation)
321 0 : osSystemId = GML_321_OGC_SCHEMA_LOC;
322 : }
323 :
324 1670 : CPLString osNewPath;
325 : auto fp = std::shared_ptr<VSIVirtualHandle>(
326 835 : m_oCache.Open(osSystemId, m_aosPathStack.back(), osNewPath),
327 835 : VSIVirtualHandleCloser{});
328 :
329 835 : if (fp != nullptr)
330 : {
331 833 : m_oSetSchemaURLs.insert(osNewPath);
332 :
333 833 : CPLDebug("GMLAS", "Opening %s", osNewPath.c_str());
334 833 : DoExtraSchemaProcessing(osNewPath, fp);
335 : }
336 :
337 835 : m_aosPathStack.push_back(CPLGetDirname(osNewPath));
338 835 : GMLASInputSource *poIS = new GMLASInputSource(osNewPath, fp);
339 835 : poIS->SetClosingCallback(this);
340 835 : return poIS;
341 : }
342 :
343 : /************************************************************************/
344 : /* Dump() */
345 : /************************************************************************/
346 :
347 3517 : void GMLASReader::Context::Dump() const
348 : {
349 3517 : CPLDebug("GMLAS", "Context");
350 3517 : CPLDebug("GMLAS", " m_nLevel = %d", m_nLevel);
351 3517 : CPLDebug("GMLAS", " m_poFeature = %p", m_poFeature);
352 3517 : const char *pszDebug = CPLGetConfigOption("CPL_DEBUG", "OFF");
353 3517 : if (EQUAL(pszDebug, "ON") || EQUAL(pszDebug, "GMLAS"))
354 : {
355 0 : if (m_poFeature)
356 0 : m_poFeature->DumpReadable(stderr);
357 : }
358 3517 : CPLDebug("GMLAS", " m_poLayer = %p (%s)", m_poLayer,
359 3517 : m_poLayer ? m_poLayer->GetName() : "");
360 3517 : CPLDebug("GMLAS", " m_poGroupLayer = %p (%s)", m_poGroupLayer,
361 3517 : m_poGroupLayer ? m_poGroupLayer->GetName() : "");
362 3517 : CPLDebug("GMLAS", " m_nGroupLayerLevel = %d", m_nGroupLayerLevel);
363 3517 : CPLDebug("GMLAS", " m_nLastFieldIdxGroupLayer = %d",
364 3517 : m_nLastFieldIdxGroupLayer);
365 3517 : CPLDebug("GMLAS", " m_osCurSubXPath = %s", m_osCurSubXPath.c_str());
366 3517 : }
367 :
368 : /************************************************************************/
369 : /* GMLASReader() */
370 : /************************************************************************/
371 :
372 1238 : GMLASReader::GMLASReader(GMLASXSDCache &oCache,
373 : const GMLASXPathMatcher &oIgnoredXPathMatcher,
374 1238 : GMLASXLinkResolver &oXLinkResolver)
375 : : m_oCache(oCache), m_oIgnoredXPathMatcher(oIgnoredXPathMatcher),
376 : m_oXLinkResolver(oXLinkResolver),
377 2476 : m_nMaxLevel(atoi(CPLGetConfigOption("GMLAS_XML_MAX_LEVEL", "100"))),
378 1238 : m_nMaxContentSize(static_cast<size_t>(
379 2476 : atoi(CPLGetConfigOption("GMLAS_XML_MAX_CONTENT_SIZE", "512000000")))),
380 : m_bWarnUnexpected(
381 1238 : CPLTestBool(CPLGetConfigOption("GMLAS_WARN_UNEXPECTED", "FALSE")))
382 : {
383 1238 : }
384 :
385 : /************************************************************************/
386 : /* ~GMLASReader() */
387 : /************************************************************************/
388 :
389 2476 : GMLASReader::~GMLASReader()
390 : {
391 1499 : if (m_oCurCtxt.m_poFeature != nullptr && !m_aoStackContext.empty() &&
392 261 : m_oCurCtxt.m_poFeature != m_aoStackContext.back().m_poFeature)
393 : {
394 10 : CPLDebug("GMLAS", "Delete feature m_oCurCtxt.m_poFeature=%p",
395 : m_oCurCtxt.m_poFeature);
396 10 : delete m_oCurCtxt.m_poFeature;
397 : }
398 1700 : for (size_t i = 0; i < m_aoStackContext.size(); i++)
399 : {
400 663 : if (i == 0 || m_aoStackContext[i].m_poFeature !=
401 201 : m_aoStackContext[i - 1].m_poFeature)
402 : {
403 462 : CPLDebug("GMLAS",
404 : "Delete feature m_aoStackContext[%d].m_poFeature=%p",
405 462 : static_cast<int>(i), m_aoStackContext[i].m_poFeature);
406 462 : delete m_aoStackContext[i].m_poFeature;
407 : }
408 : }
409 :
410 1238 : if (!m_apsXMLNodeStack.empty())
411 : {
412 0 : CPLDestroyXMLNode(m_apsXMLNodeStack[0].psNode);
413 : }
414 2476 : }
415 :
416 : /************************************************************************/
417 : /* SetLayerOfInterest() */
418 : /************************************************************************/
419 :
420 1109 : void GMLASReader::SetLayerOfInterest(OGRGMLASLayer *poLayer)
421 : {
422 1109 : m_poLayerOfInterest = poLayer;
423 1109 : }
424 :
425 : /************************************************************************/
426 : /* SetSWEDataArrayLayersRef() */
427 : /************************************************************************/
428 :
429 1118 : void GMLASReader::SetSWEDataArrayLayersRef(
430 : const std::vector<OGRGMLASLayer *> &ar)
431 : {
432 1118 : m_apoSWEDataArrayLayersRef = ar;
433 1118 : m_bProcessSWEDataArray = !ar.empty();
434 1118 : }
435 :
436 : /************************************************************************/
437 : /* LoadXSDInParser() */
438 : /************************************************************************/
439 :
440 262 : bool GMLASReader::LoadXSDInParser(
441 : SAX2XMLReader *poParser, GMLASXSDCache &oCache,
442 : GMLASBaseEntityResolver &oXSDEntityResolver, const CPLString &osBaseDirname,
443 : const CPLString &osXSDFilename, Grammar **ppoGrammar,
444 : bool bSchemaFullChecking, bool bHandleMultipleImports)
445 : {
446 262 : if (ppoGrammar != nullptr)
447 261 : *ppoGrammar = nullptr;
448 :
449 : const CPLString osModifXSDFilename(
450 511 : (osXSDFilename.find("http://") != 0 &&
451 249 : osXSDFilename.find("https://") != 0 &&
452 146 : CPLIsFilenameRelative(osXSDFilename))
453 262 : ? CPLString(CPLFormFilename(osBaseDirname, osXSDFilename, nullptr))
454 524 : : osXSDFilename);
455 :
456 264 : for (int iPass = 0; iPass <= 1; ++iPass)
457 : {
458 264 : CPLString osResolvedFilename;
459 : auto fpXSD = std::shared_ptr<VSIVirtualHandle>(
460 264 : oCache.Open(osModifXSDFilename, CPLString(), osResolvedFilename),
461 264 : VSIVirtualHandleCloser{});
462 264 : if (fpXSD == nullptr)
463 : {
464 5 : return false;
465 : }
466 :
467 259 : poParser->setFeature(XMLUni::fgXercesSchemaFullChecking,
468 259 : bSchemaFullChecking);
469 259 : poParser->setFeature(XMLUni::fgXercesHandleMultipleImports,
470 259 : bHandleMultipleImports);
471 :
472 : // Install a temporary entity resolved based on the current XSD
473 259 : CPLString osXSDDirname(CPLGetDirname(osModifXSDFilename));
474 508 : if (osXSDFilename.find("http://") == 0 ||
475 249 : osXSDFilename.find("https://") == 0)
476 : {
477 113 : osXSDDirname = osXSDFilename.substr(0, osXSDFilename.rfind('/'));
478 : }
479 259 : oXSDEntityResolver.SetBasePath(osXSDDirname);
480 259 : oXSDEntityResolver.DoExtraSchemaProcessing(osResolvedFilename, fpXSD);
481 259 : if (iPass == 1)
482 2 : oXSDEntityResolver.SetSubstituteWithOGCSchemaLocation(true);
483 :
484 259 : EntityResolver *poOldEntityResolver = poParser->getEntityResolver();
485 259 : poParser->setEntityResolver(&oXSDEntityResolver);
486 :
487 : // Install a temporary error handler
488 259 : GMLASErrorHandler oErrorHandler;
489 259 : oErrorHandler.SetSchemaFullCheckingEnabled(bSchemaFullChecking);
490 259 : oErrorHandler.SetHandleMultipleImportsEnabled(bHandleMultipleImports);
491 259 : if (iPass == 0)
492 257 : oErrorHandler.SetHideGMLTypeNotFound(true);
493 259 : ErrorHandler *poOldErrorHandler = poParser->getErrorHandler();
494 259 : poParser->setErrorHandler(&oErrorHandler);
495 :
496 259 : GMLASInputSource oSource(osResolvedFilename, fpXSD);
497 259 : const bool bCacheGrammar = true;
498 259 : Grammar *poGrammar = nullptr;
499 259 : std::string osLoadGrammarErrorMsg("loadGrammar failed");
500 :
501 : const int nMaxMem = std::min(
502 259 : 2048, std::max(0, atoi(CPLGetConfigOption(
503 259 : "OGR_GMLAS_XERCES_MAX_MEMORY", "500"))));
504 : const std::string osMsgMaxMem = CPLSPrintf(
505 : "Xerces-C memory allocation exceeds %d MB. "
506 : "This can happen on schemas with a big value for maxOccurs. "
507 : "Define the OGR_GMLAS_XERCES_MAX_MEMORY configuration option to a "
508 : "bigger value (in MB) to increase that limitation, "
509 : "or 0 to remove it completely.",
510 259 : nMaxMem);
511 : const double dfTimeout =
512 259 : CPLAtof(CPLGetConfigOption("OGR_GMLAS_XERCES_MAX_TIME", "2"));
513 : const std::string osMsgTimeout = CPLSPrintf(
514 : "Processing in Xerces exceeded maximum allowed of %.3f s. "
515 : "This can happen on schemas with a big value for maxOccurs. "
516 : "Define the OGR_GMLAS_XERCES_MAX_TIME configuration option to a "
517 : "bigger value (in second) to increase that limitation, "
518 : "or 0 to remove it completely.",
519 259 : dfTimeout);
520 259 : OGRStartXercesLimitsForThisThread(
521 259 : static_cast<size_t>(nMaxMem) * 1024 * 1024, osMsgMaxMem.c_str(),
522 : dfTimeout, osMsgTimeout.c_str());
523 : try
524 : {
525 256 : poGrammar = poParser->loadGrammar(
526 259 : oSource, Grammar::SchemaGrammarType, bCacheGrammar);
527 : }
528 0 : catch (const SAXException &e)
529 : {
530 0 : osLoadGrammarErrorMsg += ": " + transcode(e.getMessage());
531 : }
532 0 : catch (const XMLException &e)
533 : {
534 0 : osLoadGrammarErrorMsg += ": " + transcode(e.getMessage());
535 : }
536 4 : catch (const OutOfMemoryException &e)
537 : {
538 2 : if (strstr(CPLGetLastErrorMsg(), "configuration option") == nullptr)
539 : {
540 0 : osLoadGrammarErrorMsg += ": " + transcode(e.getMessage());
541 : }
542 : }
543 1 : catch (const DOMException &e)
544 : {
545 : // Can happen with a .xsd that has a bad <?xml version="
546 : // declaration.
547 1 : osLoadGrammarErrorMsg += ": " + transcode(e.getMessage());
548 : }
549 259 : OGRStopXercesLimitsForThisThread();
550 :
551 : // Restore previous handlers
552 259 : poParser->setEntityResolver(poOldEntityResolver);
553 259 : poParser->setErrorHandler(poOldErrorHandler);
554 :
555 259 : if (poGrammar == nullptr)
556 : {
557 3 : if (!osLoadGrammarErrorMsg.empty())
558 : {
559 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
560 : osLoadGrammarErrorMsg.c_str());
561 : }
562 3 : return false;
563 : }
564 256 : if (oErrorHandler.hasFailed())
565 : {
566 4 : if (iPass == 0 && !oErrorHandler.GetGMLTypeNotFoundError().empty())
567 : {
568 2 : if (oXSDEntityResolver.GetFoundNonOfficialGMLSchemaLocation())
569 : {
570 2 : CPLDebug(
571 : "GMLAS",
572 : "Error '%s' encountered, but non-official GML schema "
573 : "location has been imported. Retry with official one",
574 2 : oErrorHandler.GetGMLTypeNotFoundError().c_str());
575 2 : continue;
576 : }
577 : else
578 : {
579 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
580 0 : oErrorHandler.GetGMLTypeNotFoundError().c_str());
581 : }
582 : }
583 2 : return false;
584 : }
585 :
586 252 : if (ppoGrammar != nullptr)
587 251 : *ppoGrammar = poGrammar;
588 :
589 252 : break;
590 : }
591 :
592 252 : return true;
593 : }
594 :
595 : /************************************************************************/
596 : /* Init() */
597 : /************************************************************************/
598 :
599 1238 : bool GMLASReader::Init(const char *pszFilename,
600 : const std::shared_ptr<VSIVirtualHandle> &fp,
601 : const std::map<CPLString, CPLString> &oMapURIToPrefix,
602 : std::vector<std::unique_ptr<OGRGMLASLayer>> &apoLayers,
603 : bool bValidate,
604 : const std::vector<PairURIFilename> &aoXSDs,
605 : bool bSchemaFullChecking, bool bHandleMultipleImports)
606 : {
607 1238 : m_oMapURIToPrefix = oMapURIToPrefix;
608 1238 : m_apoLayers = &apoLayers;
609 1238 : m_bValidate = bValidate;
610 :
611 1238 : m_poSAXReader.reset(XMLReaderFactory::createXMLReader());
612 :
613 : // Commonly useful configuration.
614 : //
615 1238 : m_poSAXReader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
616 1238 : m_poSAXReader->setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes, true);
617 :
618 1238 : m_poSAXReader->setContentHandler(this);
619 1238 : m_poSAXReader->setLexicalHandler(this);
620 1238 : m_poSAXReader->setDTDHandler(this);
621 1238 : m_poSAXReader->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution,
622 1238 : true);
623 :
624 1238 : m_oErrorHandler.SetSchemaFullCheckingEnabled(bSchemaFullChecking);
625 1238 : m_oErrorHandler.SetHandleMultipleImportsEnabled(bHandleMultipleImports);
626 1238 : m_poSAXReader->setErrorHandler(&m_oErrorHandler);
627 :
628 1238 : m_poSAXReader->setFeature(XMLUni::fgXercesSchemaFullChecking,
629 1238 : bSchemaFullChecking);
630 1238 : m_poSAXReader->setFeature(XMLUni::fgXercesHandleMultipleImports,
631 1238 : bHandleMultipleImports);
632 :
633 1238 : if (bValidate)
634 : {
635 : // Enable validation.
636 50 : m_poSAXReader->setFeature(XMLUni::fgSAX2CoreValidation, true);
637 50 : m_poSAXReader->setFeature(XMLUni::fgXercesSchema, true);
638 :
639 : // We want all errors to be reported
640 : // coverity[unsafe_xml_parse_config]
641 50 : m_poSAXReader->setFeature(XMLUni::fgXercesValidationErrorAsFatal,
642 50 : false);
643 :
644 50 : CPLString osBaseDirname(CPLGetDirname(pszFilename));
645 :
646 : // In the case the schemas are explicitly passed, we must do special
647 : // processing
648 50 : if (!aoXSDs.empty())
649 : {
650 1 : GMLASBaseEntityResolver oXSDEntityResolver(CPLString(), m_oCache);
651 2 : for (size_t i = 0; i < aoXSDs.size(); i++)
652 : {
653 1 : const CPLString osXSDFilename(aoXSDs[i].second);
654 1 : if (!LoadXSDInParser(
655 : m_poSAXReader.get(), m_oCache, oXSDEntityResolver,
656 : osBaseDirname, osXSDFilename, nullptr,
657 : bSchemaFullChecking, bHandleMultipleImports))
658 : {
659 0 : return false;
660 : }
661 : }
662 :
663 : // Make sure our previously loaded schemas are used
664 1 : m_poSAXReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse,
665 1 : true);
666 :
667 : // Don't load schemas from any other source (e.g., from XML
668 : // document's xsi:schemaLocation attributes).
669 : //
670 1 : m_poSAXReader->setFeature(XMLUni::fgXercesLoadSchema, false);
671 : }
672 :
673 : // Install entity resolver based on XML file
674 : m_poEntityResolver =
675 50 : std::make_unique<GMLASBaseEntityResolver>(osBaseDirname, m_oCache);
676 50 : m_poSAXReader->setEntityResolver(m_poEntityResolver.get());
677 : }
678 : else
679 : {
680 : // Don't load schemas from any other source (e.g., from XML document's
681 : // xsi:schemaLocation attributes).
682 : //
683 1188 : m_poSAXReader->setFeature(XMLUni::fgXercesLoadSchema, false);
684 1188 : m_poSAXReader->setEntityResolver(this);
685 : }
686 :
687 1238 : m_fp = fp;
688 1238 : m_GMLInputSource = std::make_unique<GMLASInputSource>(pszFilename, m_fp);
689 :
690 1238 : return true;
691 : }
692 :
693 : /************************************************************************/
694 : /* IsArrayType() */
695 : /************************************************************************/
696 :
697 221072 : static bool IsArrayType(OGRFieldType eType)
698 : {
699 206442 : return eType == OFTIntegerList || eType == OFTInteger64List ||
700 427514 : eType == OFTRealList || eType == OFTStringList;
701 : }
702 :
703 : /************************************************************************/
704 : /* SetField() */
705 : /************************************************************************/
706 :
707 119709 : void GMLASReader::SetField(OGRFeature *poFeature, OGRGMLASLayer *poLayer,
708 : int nAttrIdx, const CPLString &osAttrValue)
709 : {
710 119709 : const OGRFieldType eType(poFeature->GetFieldDefnRef(nAttrIdx)->GetType());
711 119709 : if (osAttrValue.empty())
712 : {
713 4599 : if (eType == OFTString &&
714 1238 : !poFeature->GetFieldDefnRef(nAttrIdx)->IsNullable())
715 : {
716 36 : poFeature->SetField(nAttrIdx, "");
717 : }
718 : }
719 116348 : else if (eType == OFTDate || eType == OFTDateTime)
720 : {
721 : OGRField sField;
722 36016 : if (OGRParseXMLDateTime((m_bInitialPass) ? "1970-01-01T00:00:00"
723 17846 : : osAttrValue.c_str(),
724 18170 : &sField))
725 : {
726 18170 : poFeature->SetField(nAttrIdx, &sField);
727 18170 : }
728 : }
729 : // Transform boolean values to something that OGR understands
730 117810 : else if (eType == OFTInteger &&
731 19632 : poFeature->GetFieldDefnRef(nAttrIdx)->GetSubType() == OFSTBoolean)
732 : {
733 3200 : if (osAttrValue == "true")
734 3179 : poFeature->SetField(nAttrIdx, TRUE);
735 : else
736 21 : poFeature->SetField(nAttrIdx, FALSE);
737 : }
738 94978 : else if (eType == OFTBinary)
739 : {
740 : const int nFCFieldIdx =
741 2142 : poLayer->GetFCFieldIndexFromOGRFieldIdx(nAttrIdx);
742 2142 : if (nFCFieldIdx >= 0)
743 : {
744 : const GMLASField &oField(
745 2142 : poLayer->GetFeatureClass().GetFields()[nFCFieldIdx]);
746 2142 : if (m_bInitialPass)
747 : {
748 36 : GByte b = 'X';
749 36 : poFeature->SetField(nAttrIdx, 1, &b);
750 : }
751 2106 : else if (oField.GetType() == GMLAS_FT_BASE64BINARY)
752 : {
753 : GByte *pabyBuffer =
754 1053 : reinterpret_cast<GByte *>(CPLStrdup(osAttrValue));
755 1053 : int nBytes = CPLBase64DecodeInPlace(pabyBuffer);
756 1053 : poFeature->SetField(nAttrIdx, nBytes, pabyBuffer);
757 1053 : CPLFree(pabyBuffer);
758 : }
759 : else
760 : {
761 1053 : int nBytes = 0;
762 1053 : GByte *pabyBuffer = CPLHexToBinary(osAttrValue, &nBytes);
763 1053 : poFeature->SetField(nAttrIdx, nBytes, pabyBuffer);
764 1053 : CPLFree(pabyBuffer);
765 : }
766 : }
767 : }
768 92836 : else if (IsArrayType(eType))
769 : {
770 : const int nFCFieldIdx =
771 6420 : poLayer->GetFCFieldIndexFromOGRFieldIdx(nAttrIdx);
772 12840 : if (nFCFieldIdx >= 0 &&
773 6420 : poLayer->GetFeatureClass().GetFields()[nFCFieldIdx].IsList())
774 : {
775 : char **papszTokens =
776 6420 : CSLTokenizeString2(osAttrValue.c_str(), " ", 0);
777 9600 : if (eType == OFTIntegerList &&
778 3180 : poFeature->GetFieldDefnRef(nAttrIdx)->GetSubType() ==
779 : OFSTBoolean)
780 : {
781 3162 : for (char **papszIter = papszTokens; *papszIter != nullptr;
782 : ++papszIter)
783 : {
784 2102 : if (strcmp(*papszIter, "true") == 0)
785 : {
786 1042 : (*papszIter)[0] = '1';
787 1042 : (*papszIter)[1] = '\0';
788 : }
789 1060 : else if (strcmp(*papszIter, "false") == 0)
790 : {
791 1042 : (*papszIter)[0] = '0';
792 1042 : (*papszIter)[1] = '\0';
793 : }
794 : }
795 : }
796 6420 : poFeature->SetField(nAttrIdx, papszTokens);
797 6420 : CSLDestroy(papszTokens);
798 : }
799 : else
800 : {
801 0 : poFeature->SetField(nAttrIdx, osAttrValue.c_str());
802 : }
803 : }
804 : else
805 : {
806 86416 : poFeature->SetField(nAttrIdx, osAttrValue.c_str());
807 : }
808 119709 : }
809 :
810 : /************************************************************************/
811 : /* PushFeatureReady() */
812 : /************************************************************************/
813 :
814 56559 : void GMLASReader::PushFeatureReady(std::unique_ptr<OGRFeature> &&poFeature,
815 : OGRGMLASLayer *poLayer)
816 : {
817 : #ifdef DEBUG_VERBOSE
818 : CPLDebug("GMLAS", "PushFeatureReady(%p / %s / %s)", poFeature,
819 : poFeature->GetDefnRef()->GetName(), poLayer->GetName());
820 : #endif
821 :
822 : m_aoFeaturesReady.emplace_back(
823 56559 : std::make_pair(std::move(poFeature), poLayer));
824 56559 : }
825 :
826 : /************************************************************************/
827 : /* CreateNewFeature */
828 : /************************************************************************/
829 :
830 52417 : void GMLASReader::CreateNewFeature(const CPLString &osLocalname)
831 : {
832 52417 : m_oCurCtxt.m_poFeature =
833 52417 : new OGRFeature(m_oCurCtxt.m_poLayer->GetLayerDefn());
834 : #ifdef DEBUG_VERBOSE
835 : CPLDebug("GMLAS", "CreateNewFeature(element=%s / layer=%s) = %p",
836 : osLocalname.c_str(), m_oCurCtxt.m_poLayer->GetName(),
837 : m_oCurCtxt.m_poFeature);
838 : #endif
839 : // Assign FID (1, ...). Only for OGR compliance, but definitely
840 : // not a unique ID among datasets with the same schema
841 52417 : ++m_oMapGlobalCounter[m_oCurCtxt.m_poLayer];
842 52417 : const int nGlobalCounter = m_oMapGlobalCounter[m_oCurCtxt.m_poLayer];
843 52417 : m_oCurCtxt.m_poFeature->SetFID(nGlobalCounter);
844 :
845 : // Find parent ID
846 52417 : CPLString osParentId;
847 103577 : if (!m_aoStackContext.empty() &&
848 51160 : m_oCurCtxt.m_poLayer->GetParentIDFieldIdx() >= 0)
849 : {
850 39407 : CPLAssert(m_aoStackContext.back().m_poLayer->GetIDFieldIdx() >= 0);
851 39407 : osParentId = m_aoStackContext.back().m_poFeature->GetFieldAsString(
852 39407 : m_aoStackContext.back().m_poLayer->GetIDFieldIdx());
853 78814 : m_oCurCtxt.m_poFeature->SetField(
854 39407 : m_oCurCtxt.m_poLayer->GetParentIDFieldIdx(), osParentId.c_str());
855 : }
856 :
857 : // Should we generate a unique (child) ID from the parent ID ?
858 52417 : if (m_oCurCtxt.m_poLayer->IsGeneratedIDField())
859 : {
860 : // Local IDs (ie related to a parent feature are fine, but when
861 : // we might have cycles, that doesn't work anymore
862 : /*
863 : ++m_oCurCtxt.m_oMapCounter[m_oCurCtxt.m_poLayer];
864 : const int nCounter =
865 : m_oCurCtxt.m_oMapCounter[m_oCurCtxt.m_poLayer];*/
866 51329 : const int nCounter = nGlobalCounter;
867 :
868 51329 : CPLString osGeneratedID = (osParentId.empty() ? m_osHash : osParentId) +
869 153987 : "_" + osLocalname +
870 102658 : CPLSPrintf("_%d", nCounter);
871 51329 : m_oCurCtxt.m_poFeature->SetField(m_oCurCtxt.m_poLayer->GetIDFieldIdx(),
872 : osGeneratedID.c_str());
873 : }
874 :
875 52417 : m_nCurFieldIdx = -1;
876 52417 : }
877 :
878 : /************************************************************************/
879 : /* AttachAsLastChild() */
880 : /************************************************************************/
881 :
882 : /* Attach element as the last child of its parent */
883 2027 : void GMLASReader::AttachAsLastChild(CPLXMLNode *psNode)
884 : {
885 2027 : NodeLastChild &sNodeLastChild = m_apsXMLNodeStack.back();
886 2027 : CPLXMLNode *psLastChildParent = sNodeLastChild.psLastChild;
887 :
888 2027 : if (psLastChildParent == nullptr)
889 : {
890 774 : CPLAssert(sNodeLastChild.psNode);
891 774 : sNodeLastChild.psNode->psChild = psNode;
892 : }
893 : else
894 : {
895 1253 : psLastChildParent->psNext = psNode;
896 : }
897 2027 : sNodeLastChild.psLastChild = psNode;
898 2027 : }
899 :
900 : /************************************************************************/
901 : /* BuildXMLBlobStartElement() */
902 : /************************************************************************/
903 :
904 9607 : void GMLASReader::BuildXMLBlobStartElement(const CPLString &osXPath,
905 : const Attributes &attrs)
906 : {
907 9607 : if (FillTextContent())
908 : {
909 6357 : m_osTextContent += "<";
910 6357 : m_osTextContent += osXPath;
911 : }
912 :
913 9607 : CPLXMLNode *psNode = nullptr;
914 9607 : if (m_nCurGeomFieldIdx >= 0 || m_nSWEDataArrayLevel >= 0 ||
915 7909 : m_nSWEDataRecordLevel >= 0)
916 : {
917 1785 : psNode = CPLCreateXMLNode(nullptr, CXT_Element, osXPath);
918 1785 : if (!m_apsXMLNodeStack.empty())
919 : {
920 1348 : AttachAsLastChild(psNode);
921 : }
922 : }
923 :
924 9607 : CPLXMLNode *psLastChild = nullptr;
925 11993 : for (unsigned int i = 0; i < attrs.getLength(); i++)
926 : {
927 : const CPLString &osAttrNSPrefix(
928 : m_osAttrNSPrefix =
929 2386 : m_oMapURIToPrefix[transcode(attrs.getURI(i), m_osAttrNSUri)]);
930 : const CPLString &osAttrLocalname(
931 2386 : transcode(attrs.getLocalName(i), m_osAttrLocalName));
932 : const CPLString &osAttrValue(
933 2386 : transcode(attrs.getValue(i), m_osAttrValue));
934 2386 : CPLString &osAttrXPath(m_osAttrXPath);
935 2386 : if (!osAttrNSPrefix.empty())
936 : {
937 1210 : osAttrXPath.reserve(osAttrNSPrefix.size() + 1 +
938 605 : osAttrLocalname.size());
939 605 : osAttrXPath = osAttrNSPrefix;
940 605 : osAttrXPath += ":";
941 605 : osAttrXPath += osAttrLocalname;
942 : }
943 : else
944 : {
945 1781 : osAttrXPath = osAttrLocalname;
946 : }
947 :
948 2386 : if (psNode != nullptr)
949 : {
950 : CPLXMLNode *psAttrNode =
951 879 : CPLCreateXMLNode(nullptr, CXT_Attribute, osAttrXPath);
952 879 : CPLCreateXMLNode(psAttrNode, CXT_Text, osAttrValue);
953 :
954 879 : if (psLastChild == nullptr)
955 : {
956 773 : psNode->psChild = psAttrNode;
957 : }
958 : else
959 : {
960 106 : psLastChild->psNext = psAttrNode;
961 : }
962 879 : psLastChild = psAttrNode;
963 : }
964 :
965 2386 : if (FillTextContent())
966 : {
967 1054 : m_osTextContent += " ";
968 1054 : m_osTextContent += osAttrXPath;
969 1054 : m_osTextContent += "=\"";
970 1054 : char *pszEscaped = CPLEscapeString(
971 1054 : osAttrValue.c_str(), static_cast<int>(osAttrValue.size()),
972 : CPLES_XML);
973 1054 : m_osTextContent += pszEscaped;
974 1054 : CPLFree(pszEscaped);
975 1054 : m_osTextContent += '"';
976 : }
977 : }
978 9607 : if (FillTextContent())
979 6357 : m_osTextContent += ">";
980 :
981 9607 : if (psNode != nullptr)
982 : {
983 : /* Push the element on the stack */
984 1785 : NodeLastChild sNewNodeLastChild;
985 1785 : sNewNodeLastChild.psNode = psNode;
986 1785 : sNewNodeLastChild.psLastChild = psLastChild;
987 1785 : m_apsXMLNodeStack.push_back(sNewNodeLastChild);
988 : #ifdef DEBUG_VERBOSE
989 : CPLDebug("GMLAS", "m_apsXMLNodeStack.push_back()");
990 : #endif
991 : }
992 :
993 9607 : if (m_osTextContent.size() > m_nMaxContentSize)
994 : {
995 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
996 : "Too much data in a single element");
997 0 : m_bParsingError = true;
998 : }
999 9607 : }
1000 :
1001 : /************************************************************************/
1002 : /* GetLayerByXPath() */
1003 : /************************************************************************/
1004 :
1005 16349 : OGRGMLASLayer *GMLASReader::GetLayerByXPath(const CPLString &osXPath)
1006 : {
1007 331871 : for (const auto &poLayer : *m_apoLayers)
1008 : {
1009 331871 : if (poLayer->GetFeatureClass().GetXPath() == osXPath)
1010 : {
1011 16349 : return poLayer.get();
1012 : }
1013 : }
1014 0 : return nullptr;
1015 : }
1016 :
1017 : /************************************************************************/
1018 : /* PushContext() */
1019 : /************************************************************************/
1020 :
1021 60986 : void GMLASReader::PushContext(const Context &oContext)
1022 : {
1023 60986 : m_aoStackContext.push_back(oContext);
1024 : #ifdef DEBUG_VERBOSE
1025 : CPLDebug("GMLAS", "Pushing new context:");
1026 : oContext.Dump();
1027 : #endif
1028 60986 : }
1029 :
1030 : /************************************************************************/
1031 : /* PopContext() */
1032 : /************************************************************************/
1033 :
1034 60524 : void GMLASReader::PopContext()
1035 : {
1036 : #ifdef DEBUG_VERBOSE
1037 : if (!m_aoStackContext.empty())
1038 : {
1039 : CPLDebug("GMLAS", "Popping up context:");
1040 : m_aoStackContext.back().Dump();
1041 : }
1042 : #endif
1043 60524 : m_aoStackContext.pop_back();
1044 : #ifdef DEBUG_VERBOSE
1045 : if (!m_aoStackContext.empty())
1046 : {
1047 : CPLDebug("GMLAS", "New top of stack is:");
1048 : m_aoStackContext.back().Dump();
1049 : }
1050 : #endif
1051 60524 : }
1052 :
1053 : /************************************************************************/
1054 : /* startElement() */
1055 : /************************************************************************/
1056 :
1057 : /* <xs:group ref="somegroup" maxOccurs="unbounded"/> are particularly hard to
1058 : deal with since we cannot easily know when the corresponding subfeature
1059 : is exactly terminated.
1060 :
1061 : Let's consider:
1062 :
1063 : <xs:group name="somegroup">
1064 : <xs:choice>
1065 : <xs:element name="first_elt_of_group" type="xs:string"/>
1066 : <xs:element name="second_elt_of_group" type="xs:string"/>
1067 : </xs:choice>
1068 : </xs:group>
1069 :
1070 : <xs:group name="another_group">
1071 : <xs:choice>
1072 : <xs:element name="first_elt_of_another_group" type="xs:string"/>
1073 : </xs:choice>
1074 : </xs:group>
1075 :
1076 : There are different cases :
1077 : *
1078 : <first_elt_of_group>...</first_elt_of_group>
1079 : <second_elt_of_group>...</first_elt_of_group>
1080 : <first_elt_of_group> <!-- we are here at startElement() -->
1081 : ...
1082 : </first_elt_of_group>
1083 :
1084 : *
1085 : <first_elt_of_group>...</first_elt_of_group>
1086 : <first_elt_of_group> <!-- we are here at startElement() -->
1087 : ...</first_elt_of_group>
1088 :
1089 : *
1090 : <first_elt_of_group>...</first_elt_of_group>
1091 : <first_elt_of_another_group> <!-- we are here at startElement()
1092 : -->
1093 : ...</first_elt_of_another_group>
1094 :
1095 : *
1096 : <first_elt_of_group>...</first_elt_of_group>
1097 : <some_other_elt> <!-- we are here at startElement() -->
1098 : ...</some_other_elt>
1099 :
1100 : *
1101 : <first_elt>...</first_elt>
1102 : <second_elt><sub>...</sub></second_elt>
1103 : <first_elt> <-- here -->
1104 : ...</first_elt>
1105 : *
1106 : <first_elt_of_group>...</first_elt_of_group>
1107 : </end_of_enclosing_element> <!-- we are here at endElement() -->
1108 : */
1109 162810 : void GMLASReader::startElement(const XMLCh *const uri,
1110 : const XMLCh *const localname,
1111 : const XMLCh *const
1112 : #ifdef DEBUG_VERBOSE
1113 : qname
1114 : #endif
1115 : ,
1116 : const Attributes &attrs)
1117 : {
1118 162810 : m_nEntityCounter = 0;
1119 :
1120 162810 : const CPLString &osLocalname(transcode(localname, m_osLocalname));
1121 162810 : const CPLString &osNSURI(transcode(uri, m_osNSUri));
1122 162810 : const CPLString &osNSPrefix(m_osNSPrefix = m_oMapURIToPrefix[osNSURI]);
1123 162810 : if (osNSPrefix.empty())
1124 5653 : m_osXPath = osLocalname;
1125 : else
1126 : {
1127 157157 : m_osXPath.reserve(osNSPrefix.size() + 1 + osLocalname.size());
1128 157157 : m_osXPath = osNSPrefix;
1129 157157 : m_osXPath += ":";
1130 157157 : m_osXPath += osLocalname;
1131 : }
1132 162810 : const CPLString &osXPath(m_osXPath);
1133 : #ifdef DEBUG_VERBOSE
1134 : CPLDebug("GMLAS", "startElement(%s / %s)", transcode(qname).c_str(),
1135 : osXPath.c_str());
1136 : #endif
1137 162810 : m_anStackXPathLength.push_back(osXPath.size());
1138 162810 : if (!m_osCurXPath.empty())
1139 161581 : m_osCurXPath += "/";
1140 162810 : m_osCurXPath += osXPath;
1141 :
1142 : #if 0
1143 : CPLString osSubXPathBefore(m_osCurSubXPath);
1144 : #endif
1145 162810 : if (!m_osCurSubXPath.empty())
1146 : {
1147 161338 : m_osCurSubXPath += "/";
1148 161338 : m_osCurSubXPath += osXPath;
1149 : }
1150 :
1151 162810 : if (m_bProcessSWEDataArray && m_nSWEDataArrayLevel < 0 &&
1152 100 : m_nSWEDataRecordLevel < 0 && m_nCurGeomFieldIdx < 0)
1153 : {
1154 58 : if (osNSURI == szSWE_URI &&
1155 20 : (osLocalname == "DataArray" || osLocalname == "DataStream"))
1156 : {
1157 12 : if (m_nCurFieldIdx >= 0)
1158 : {
1159 : m_osSWEDataArrayParentField =
1160 12 : m_oCurCtxt.m_poFeature->GetFieldDefnRef(m_nCurFieldIdx)
1161 12 : ->GetNameRef();
1162 : }
1163 : else
1164 : {
1165 0 : m_osSWEDataArrayParentField.clear();
1166 : }
1167 12 : m_nSWEDataArrayLevel = m_nLevel;
1168 : }
1169 : }
1170 :
1171 : // Deal with XML content
1172 162810 : if (m_bIsXMLBlob || m_nSWEDataArrayLevel >= 0 || m_nSWEDataRecordLevel >= 0)
1173 : {
1174 7914 : BuildXMLBlobStartElement(osXPath, attrs);
1175 : }
1176 :
1177 162810 : if (m_bIsXMLBlob)
1178 : {
1179 7832 : m_nLevel++;
1180 7832 : return;
1181 : }
1182 :
1183 154978 : if (m_nLevel == m_nMaxLevel)
1184 : {
1185 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too deeply nested XML content");
1186 0 : m_bParsingError = true;
1187 0 : return;
1188 : }
1189 :
1190 154978 : if (m_bInitialPass)
1191 : {
1192 : // Collect the gml:boundedBy/gml:Envelope@srsDimension attribute
1193 6152 : if (m_bInGMLBoundedByLevel1 && m_nLevel == 2 &&
1194 1 : m_osXPath == "gml:Envelope")
1195 : {
1196 2 : for (unsigned int i = 0; i < attrs.getLength(); i++)
1197 : {
1198 : const CPLString &osAttrLocalname(
1199 1 : transcode(attrs.getLocalName(i), m_osAttrLocalName));
1200 1 : if (osAttrLocalname == "srsDimension")
1201 : {
1202 : const CPLString &osAttrValue(
1203 1 : transcode(attrs.getValue(i), m_osAttrValue));
1204 1 : m_nDefaultSrsDimension = atoi(osAttrValue.c_str());
1205 : }
1206 : }
1207 : }
1208 6151 : m_bInGMLBoundedByLevel1 =
1209 6151 : (m_nLevel == 1 && m_osXPath == "gml:boundedBy");
1210 : }
1211 :
1212 154978 : CPLAssert(m_aoFeaturesReady.empty());
1213 :
1214 : // Look which layer might match the current XPath
1215 4323570 : for (auto &poLayer : *m_apoLayers)
1216 : {
1217 : const CPLString *posLayerXPath =
1218 4223070 : &(poLayer->GetFeatureClass().GetXPath());
1219 4223070 : if (poLayer->GetFeatureClass().IsRepeatedSequence())
1220 : {
1221 642525 : size_t iPosExtra = posLayerXPath->find(szEXTRA_SUFFIX);
1222 642525 : if (iPosExtra != std::string::npos)
1223 : {
1224 369943 : m_osLayerXPath = *posLayerXPath;
1225 369943 : m_osLayerXPath.resize(iPosExtra);
1226 369943 : posLayerXPath = &m_osLayerXPath;
1227 : }
1228 : }
1229 :
1230 4223070 : const bool bIsGroup = poLayer->GetFeatureClass().IsGroup();
1231 :
1232 : // Are we entering or staying in a group ?
1233 : const bool bIsMatchingGroup =
1234 4463360 : (bIsGroup &&
1235 240290 : poLayer->GetOGRFieldIndexFromXPath(m_osCurSubXPath) != -1);
1236 :
1237 : const bool bIsMatchingRepeatedSequence =
1238 4223070 : (poLayer->GetFeatureClass().IsRepeatedSequence() &&
1239 1284460 : m_oCurCtxt.m_poLayer != nullptr &&
1240 1272770 : m_oCurCtxt.m_poLayer != poLayer.get() &&
1241 630836 : m_oCurCtxt.m_poLayer->GetFeatureClass().GetXPath() ==
1242 4865590 : *posLayerXPath &&
1243 171882 : poLayer->GetOGRFieldIndexFromXPath(m_osCurSubXPath) >= 0);
1244 :
1245 : int nTmpIdx;
1246 4223070 : if ( // Case where we haven't yet entered the top-level element, which
1247 : // may be in container elements
1248 4231890 : (m_osCurSubXPath.empty() && *posLayerXPath == osXPath &&
1249 1257 : !bIsGroup) ||
1250 :
1251 : // Case where we are a sub-element of a top-level feature
1252 4221810 : (!m_osCurSubXPath.empty() && *posLayerXPath == m_osCurSubXPath &&
1253 4221810 : !bIsGroup) ||
1254 :
1255 : // Case where we are a sub-element of a (repeated) group of a
1256 : // top-level feature
1257 4174310 : bIsMatchingGroup ||
1258 :
1259 : // Needed to handle sequence_1_unbounded_non_simplifiable.subelement
1260 : // case of data/gmlas_test1.xml
1261 8446130 : bIsMatchingRepeatedSequence ||
1262 :
1263 : // Case where we go back from a sub-element of a (repeated) group
1264 : // of a top-level feature to a regular sub-element of that top-level
1265 : // feature
1266 4170360 : (m_oCurCtxt.m_poGroupLayer != nullptr &&
1267 364865 : ((nTmpIdx = poLayer->GetOGRFieldIndexFromXPath(m_osCurSubXPath)) >=
1268 363103 : 0 ||
1269 : nTmpIdx == IDX_COMPOUND_FOLDED)))
1270 : {
1271 : #ifdef DEBUG_VERBOSE
1272 : CPLDebug("GMLAS", "Matches layer %s (%s)", poLayer->GetName(),
1273 : poLayer->GetFeatureClass().GetXPath().c_str());
1274 : #endif
1275 :
1276 105923 : if (poLayer->GetParent() != nullptr &&
1277 105923 : poLayer->GetParent()->GetFeatureClass().IsRepeatedSequence() &&
1278 3517 : m_oCurCtxt.m_poGroupLayer != poLayer->GetParent())
1279 : {
1280 : // Yuck! Simulate top-level element of a group if we directly
1281 : // jump into a nested class of it !
1282 : /* Something like
1283 : <xs:group name="group">
1284 : <xs:sequence>
1285 : <xs:element name="optional_elt" type="xs:string"
1286 : minOccurs="0"/> <xs:element name="elt"> <xs:complexType>
1287 : <xs:sequence>
1288 : <xs:element name="subelt"
1289 : type="xs:dateTime" maxOccurs="unbounded"/>
1290 : </xs:sequence>
1291 : </xs:complexType>
1292 : </xs:element>
1293 : </xs:sequence>
1294 : </xs:group>
1295 :
1296 : <top_element>
1297 : <elt><subelt>...</subelt></elt>
1298 : </top_element>
1299 : */
1300 1 : m_oCurCtxt.m_poLayer = poLayer->GetParent();
1301 1 : m_oCurCtxt.m_poGroupLayer = m_oCurCtxt.m_poLayer;
1302 1 : m_oCurCtxt.m_nLevel = m_nLevel;
1303 1 : m_oCurCtxt.m_nLastFieldIdxGroupLayer = -1;
1304 1 : CreateNewFeature(m_oCurCtxt.m_poLayer->GetName());
1305 : }
1306 :
1307 54471 : bool bPushNewState = true;
1308 54471 : if (bIsMatchingGroup)
1309 : {
1310 : int nFieldIdx =
1311 19416 : poLayer->GetOGRFieldIndexFromXPath(m_osCurSubXPath);
1312 19416 : bool bPushNewFeature = false;
1313 19416 : if (m_oCurCtxt.m_poGroupLayer == nullptr)
1314 : {
1315 1791 : m_oCurCtxt.m_poFeature = nullptr;
1316 : }
1317 17625 : else if (nFieldIdx < 0)
1318 : {
1319 6993 : bPushNewState = false;
1320 : }
1321 17739 : else if (m_oCurCtxt.m_nGroupLayerLevel == m_nLevel &&
1322 7107 : m_oCurCtxt.m_poGroupLayer != poLayer.get())
1323 : {
1324 : #ifdef DEBUG_VERBOSE
1325 : CPLDebug("GMLAS", "new feature: group case 1");
1326 : #endif
1327 : /* Case like:
1328 : <first_elt_of_group>...</first_elt_of_group>
1329 : <first_elt_of_another_group> <!-- we are here at
1330 : startElement() -->
1331 : ...</first_elt_of_group>
1332 : */
1333 1 : bPushNewFeature = true;
1334 : }
1335 7106 : else if (m_oCurCtxt.m_nGroupLayerLevel == m_nLevel &&
1336 7106 : m_oCurCtxt.m_poGroupLayer == poLayer.get() &&
1337 19510 : nFieldIdx == m_oCurCtxt.m_nLastFieldIdxGroupLayer &&
1338 1773 : !IsArrayType(
1339 1773 : m_oCurCtxt.m_poFeature->GetFieldDefnRef(nFieldIdx)
1340 : ->GetType()))
1341 : {
1342 : #ifdef DEBUG_VERBOSE
1343 : CPLDebug("GMLAS", "new feature: group case 2");
1344 : #endif
1345 : /* Case like:
1346 : <first_elt>...</first_elt>
1347 : <first_elt> <-- here -->
1348 : */
1349 873 : bPushNewFeature = true;
1350 : }
1351 9758 : else if (m_oCurCtxt.m_nGroupLayerLevel == m_nLevel &&
1352 6233 : nFieldIdx < m_oCurCtxt.m_nLastFieldIdxGroupLayer)
1353 : {
1354 : #ifdef DEBUG_VERBOSE
1355 : CPLDebug("GMLAS", "new feature: group case nFieldIdx < "
1356 : "m_oCurCtxt.m_nLastFieldIdxGroupLayer");
1357 : #endif
1358 : /* Case like:
1359 : <first_elt_of_group>...</first_elt_of_group>
1360 : <second_elt_of_group>...</first_elt_of_group>
1361 : <first_elt_of_group> <!-- we are here at
1362 : startElement() -->
1363 : ...
1364 : </first_elt_of_group>
1365 : */
1366 2652 : bPushNewFeature = true;
1367 : }
1368 7106 : else if (m_oCurCtxt.m_nGroupLayerLevel == m_nLevel + 1 &&
1369 0 : m_oCurCtxt.m_poGroupLayer == poLayer.get())
1370 : {
1371 : #ifdef DEBUG_VERBOSE
1372 : CPLDebug("GMLAS", "new feature: group case 3");
1373 : #endif
1374 : /* Case like:
1375 : <first_elt>...</first_elt>
1376 : <second_elt><sub>...</sub></second_elt>
1377 : <first_elt> <-- here -->
1378 : ...</first_elt>
1379 : */
1380 0 : bPushNewFeature = true;
1381 : }
1382 19416 : if (bPushNewFeature)
1383 : {
1384 3526 : CPLAssert(m_oCurCtxt.m_poFeature);
1385 3526 : CPLAssert(m_oCurCtxt.m_poGroupLayer);
1386 : // CPLDebug("GMLAS", "Feature ready");
1387 3526 : PushFeatureReady(
1388 7052 : std::unique_ptr<OGRFeature>(m_oCurCtxt.m_poFeature),
1389 : m_oCurCtxt.m_poGroupLayer);
1390 3526 : m_oCurCtxt.m_poFeature = nullptr;
1391 3526 : m_nCurFieldIdx = -1;
1392 : }
1393 19416 : m_oCurCtxt.m_poLayer = poLayer.get();
1394 19416 : m_oCurCtxt.m_poGroupLayer = poLayer.get();
1395 19416 : m_oCurCtxt.m_nGroupLayerLevel = m_nLevel;
1396 19416 : if (nFieldIdx >= 0)
1397 12423 : m_oCurCtxt.m_nLastFieldIdxGroupLayer = nFieldIdx;
1398 : }
1399 : else
1400 : {
1401 36818 : if (m_oCurCtxt.m_nGroupLayerLevel == m_nLevel &&
1402 1763 : poLayer.get() == m_aoStackContext.back().m_poLayer)
1403 : {
1404 : // This is the case where we switch from an element that was
1405 : // in a group to a regular element of the same level
1406 :
1407 : // Push group feature as ready
1408 1762 : CPLAssert(m_oCurCtxt.m_poFeature);
1409 :
1410 : // CPLDebug("GMLAS", "Feature ready");
1411 1762 : PushFeatureReady(
1412 3524 : std::unique_ptr<OGRFeature>(m_oCurCtxt.m_poFeature),
1413 : m_oCurCtxt.m_poGroupLayer);
1414 :
1415 : // Restore "top-level" context
1416 1762 : CPLAssert(!m_aoStackContext.empty());
1417 1762 : m_oCurCtxt = m_aoStackContext.back();
1418 1762 : bPushNewState = false;
1419 : }
1420 : else
1421 : {
1422 33293 : if (m_oCurCtxt.m_poGroupLayer)
1423 : {
1424 7034 : Context oContext;
1425 3517 : oContext = m_oCurCtxt;
1426 3517 : oContext.m_nLevel = -1;
1427 3517 : oContext.Dump();
1428 3517 : PushContext(oContext);
1429 : }
1430 :
1431 33293 : m_oCurCtxt.m_poFeature = nullptr;
1432 33293 : m_oCurCtxt.m_poGroupLayer = nullptr;
1433 33293 : m_oCurCtxt.m_nGroupLayerLevel = -1;
1434 33293 : m_oCurCtxt.m_nLastFieldIdxGroupLayer = -1;
1435 33293 : m_oCurCtxt.m_poLayer = poLayer.get();
1436 33293 : if (m_aoStackContext.empty())
1437 1257 : m_osCurSubXPath = osXPath;
1438 : }
1439 : }
1440 :
1441 54471 : if (m_oCurCtxt.m_poFeature == nullptr)
1442 : {
1443 38610 : CPLAssert(bPushNewState);
1444 38610 : CreateNewFeature(osLocalname);
1445 : }
1446 :
1447 54471 : if (bPushNewState)
1448 : {
1449 91432 : Context oContext;
1450 45716 : oContext = m_oCurCtxt;
1451 45716 : oContext.m_nLevel = m_nLevel;
1452 45716 : PushContext(oContext);
1453 45716 : m_oCurCtxt.m_oMapCounter.clear();
1454 : }
1455 54471 : break;
1456 : }
1457 : }
1458 :
1459 154978 : if (m_oCurCtxt.m_poLayer)
1460 : {
1461 : #ifdef DEBUG_VERBOSE
1462 : CPLDebug("GMLAS", "Current layer: %s", m_oCurCtxt.m_poLayer->GetName());
1463 : #endif
1464 :
1465 154763 : bool bHasProcessedAttributes = false;
1466 :
1467 : // Find if we can match this element with one of our fields
1468 : int idx =
1469 154763 : m_oCurCtxt.m_poLayer->GetOGRFieldIndexFromXPath(m_osCurSubXPath);
1470 309526 : int geom_idx = m_oCurCtxt.m_poLayer->GetOGRGeomFieldIndexFromXPath(
1471 154763 : m_osCurSubXPath);
1472 :
1473 154763 : if (idx < 0 && idx != IDX_COMPOUND_FOLDED)
1474 : {
1475 : /* Special case for a layer that matches everything, as found */
1476 : /* in swe:extension */
1477 20491 : idx = m_oCurCtxt.m_poLayer->GetOGRFieldIndexFromXPath(
1478 40982 : m_oCurCtxt.m_poLayer->GetFeatureClass().GetXPath() +
1479 : szMATCH_ALL);
1480 22169 : if (idx >= 0 &&
1481 1678 : m_oCurCtxt.m_poLayer->GetFeatureClass().GetFields().size() > 1)
1482 : {
1483 : // But only match this wildcard field if it is the only child
1484 : // of the feature class, otherwise that is going to prevent
1485 : // matching regular fields
1486 : // Practical case the <any processContents="lax" minOccurs="0"
1487 : // maxOccurs="unbounded"> declaratin of
1488 : // http://schemas.earthresourceml.org/earthresourceml-lite/1.0/erml-lite.xsd
1489 : // http://services.ga.gov.au/earthresource/ows?service=wfs&version=2.0.0&request=GetFeature&typenames=erl:CommodityResourceView&count=10
1490 : // FIXME: currently we will thus ignore those extra content
1491 : // See ogr_gmlas_any_field_at_end_of_declaration test case
1492 6 : idx = -1;
1493 : }
1494 : }
1495 154763 : if (idx < 0 && geom_idx < 0 && geom_idx != IDX_COMPOUND_FOLDED)
1496 : {
1497 : /* Special case for a layer that is a made of only a geometry */
1498 34120 : geom_idx = m_oCurCtxt.m_poLayer->GetOGRGeomFieldIndexFromXPath(
1499 68240 : m_oCurCtxt.m_poLayer->GetFeatureClass().GetXPath() +
1500 : szMATCH_ALL);
1501 : }
1502 :
1503 154763 : if (idx >= 0 || geom_idx >= 0)
1504 : {
1505 : // Sanity check. Shouldn't normally happen !
1506 241290 : if (m_oCurCtxt.m_poFeature == nullptr ||
1507 120645 : m_oCurCtxt.m_poLayer->GetLayerDefn() !=
1508 120645 : m_oCurCtxt.m_poFeature->GetDefnRef())
1509 : {
1510 0 : CPLError(CE_Failure, CPLE_AppDefined,
1511 : "Inconsistent m_poLayer / m_poFeature state");
1512 0 : m_bParsingError = true;
1513 0 : return;
1514 : }
1515 :
1516 120645 : bool bPushNewFeature = false;
1517 : const int nFCFieldIdx =
1518 : (idx >= 0)
1519 120645 : ? m_oCurCtxt.m_poLayer->GetFCFieldIndexFromOGRFieldIdx(idx)
1520 368 : : m_oCurCtxt.m_poLayer->GetFCFieldIndexFromOGRGeomFieldIdx(
1521 120645 : geom_idx);
1522 :
1523 : /* For cases like
1524 : <xs:element name="element_compound">
1525 : <xs:complexType>
1526 : <xs:sequence maxOccurs="unbounded">
1527 : <xs:element name="subelement1"
1528 : type="xs:string"/> <xs:element name="subelement2"
1529 : type="xs:string"/>
1530 : </xs:sequence>
1531 : </xs:complexType>
1532 : </xs:element>
1533 :
1534 : <element_compound>
1535 : <subelement1>a</subelement>
1536 : <subelement2>b</subelement>
1537 : <subelement1>c</subelement>
1538 : <subelement2>d</subelement>
1539 : </element_compound>
1540 : */
1541 :
1542 120645 : if (idx >= 0 && idx < m_nCurFieldIdx)
1543 : {
1544 : #ifdef DEBUG_VERBOSE
1545 : CPLDebug("GMLAS", "new feature: idx < m_nCurFieldIdx");
1546 : #endif
1547 2 : bPushNewFeature = true;
1548 : }
1549 :
1550 : /* For cases like
1551 : <xs:element name="element_compound">
1552 : <xs:complexType>
1553 : <xs:sequence maxOccurs="unbounded">
1554 : <xs:element name="subelement"
1555 : type="xs:dateTime"/>
1556 : </xs:sequence>
1557 : </xs:complexType>
1558 : </xs:element>
1559 :
1560 : <element_compound>
1561 : <subelement>2012-01-01T12:34:56Z</subelement>
1562 : <subelement>2012-01-02T12:34:56Z</subelement>
1563 : </element_compound>
1564 : */
1565 120275 : else if (idx >= 0 && idx == m_nCurFieldIdx &&
1566 13385 : !IsArrayType(
1567 13385 : m_oCurCtxt.m_poFeature->GetFieldDefnRef(m_nCurFieldIdx)
1568 240918 : ->GetType()) &&
1569 : // Make sure this isn't a repeated geometry as well
1570 0 : !(geom_idx >= 0 && nFCFieldIdx >= 0 &&
1571 0 : m_oCurCtxt.m_poLayer->GetFeatureClass()
1572 0 : .GetFields()[nFCFieldIdx]
1573 0 : .GetMaxOccurs() > 1))
1574 : {
1575 2055 : bPushNewFeature = true;
1576 : }
1577 :
1578 : // Make sure we are in a repeated sequence, otherwise this is
1579 : // invalid XML
1580 122702 : if (bPushNewFeature &&
1581 120649 : !m_oCurCtxt.m_poLayer->GetFeatureClass().IsRepeatedSequence() &&
1582 : // Case of element within xs:choice
1583 4 : !(idx >= 0 && nFCFieldIdx >= 0 &&
1584 4 : m_oCurCtxt.m_poLayer->GetFeatureClass()
1585 4 : .GetFields()[nFCFieldIdx]
1586 4 : .MayAppearOutOfOrder()))
1587 : {
1588 4 : bPushNewFeature = false;
1589 4 : CPLError(CE_Warning, CPLE_AppDefined, "Unexpected element %s",
1590 : m_osCurSubXPath.c_str());
1591 : }
1592 :
1593 120645 : if (bPushNewFeature)
1594 : {
1595 : // CPLDebug("GMLAS", "Feature ready");
1596 2053 : PushFeatureReady(
1597 4106 : std::unique_ptr<OGRFeature>(m_oCurCtxt.m_poFeature),
1598 : m_oCurCtxt.m_poLayer);
1599 4106 : Context oContext = m_aoStackContext.back();
1600 2053 : m_aoStackContext.pop_back();
1601 2053 : CreateNewFeature(osLocalname);
1602 2053 : oContext.m_poFeature = m_oCurCtxt.m_poFeature;
1603 2053 : m_aoStackContext.push_back(oContext);
1604 2053 : m_oCurCtxt.m_oMapCounter.clear();
1605 : }
1606 :
1607 120645 : if (m_nCurFieldIdx != idx)
1608 : {
1609 108945 : m_osTextContentList.Clear();
1610 108945 : m_nTextContentListEstimatedSize = 0;
1611 : }
1612 120645 : m_nCurFieldIdx = idx;
1613 120645 : m_nCurGeomFieldIdx = geom_idx;
1614 120645 : m_nCurFieldLevel = m_nLevel + 1;
1615 120645 : m_osTextContent.clear();
1616 120645 : m_bIsXMLBlob = false;
1617 120645 : m_bIsXMLBlobIncludeUpper = false;
1618 :
1619 : #ifdef DEBUG_VERBOSE
1620 : if (idx >= 0)
1621 : {
1622 : CPLDebug("GMLAS", "Matches field %s",
1623 : m_oCurCtxt.m_poLayer->GetLayerDefn()
1624 : ->GetFieldDefn(idx)
1625 : ->GetNameRef());
1626 : }
1627 : if (geom_idx >= 0)
1628 : {
1629 : CPLDebug("GMLAS", "Matches geometry field %s",
1630 : m_oCurCtxt.m_poLayer->GetLayerDefn()
1631 : ->GetGeomFieldDefn(geom_idx)
1632 : ->GetNameRef());
1633 : }
1634 : #endif
1635 120645 : if (nFCFieldIdx >= 0)
1636 : {
1637 120645 : const GMLASField &oField(m_oCurCtxt.m_poLayer->GetFeatureClass()
1638 120645 : .GetFields()[nFCFieldIdx]);
1639 120645 : if (m_nSWEDataArrayLevel < 0 && m_nSWEDataRecordLevel < 0)
1640 : {
1641 235840 : m_bIsXMLBlob = (oField.GetType() == GMLAS_FT_ANYTYPE ||
1642 115248 : m_nCurGeomFieldIdx != -1);
1643 : }
1644 120645 : m_bIsXMLBlobIncludeUpper =
1645 120645 : m_bIsXMLBlob && oField.GetIncludeThisEltInBlob();
1646 120645 : if (m_bIsXMLBlobIncludeUpper)
1647 : {
1648 1688 : BuildXMLBlobStartElement(osXPath, attrs);
1649 1688 : m_nLevel++;
1650 1688 : return;
1651 : }
1652 :
1653 : // Figure out if it is an element that calls for a related
1654 : // top-level feature (but without junction table)
1655 118957 : if (oField.GetCategory() ==
1656 : GMLASField::PATH_TO_CHILD_ELEMENT_WITH_LINK)
1657 : {
1658 : const CPLString &osNestedXPath(
1659 7157 : oField.GetRelatedClassXPath());
1660 7157 : CPLAssert(!osNestedXPath.empty());
1661 7157 : OGRGMLASLayer *poSubLayer = GetLayerByXPath(osNestedXPath);
1662 7157 : if (poSubLayer && m_nCurFieldIdx >= 0)
1663 : {
1664 7157 : int nOldCurFieldIdx = m_nCurFieldIdx;
1665 7157 : OGRFeature *poOldCurFeature = m_oCurCtxt.m_poFeature;
1666 7157 : OGRGMLASLayer *poOldLayer = m_oCurCtxt.m_poLayer;
1667 7157 : m_oCurCtxt.m_poLayer = poSubLayer;
1668 7157 : CreateNewFeature(osLocalname);
1669 :
1670 7157 : m_oCurCtxt.m_poGroupLayer = nullptr;
1671 7157 : m_oCurCtxt.m_nGroupLayerLevel = -1;
1672 7157 : m_oCurCtxt.m_nLastFieldIdxGroupLayer = -1;
1673 :
1674 : // Install new context
1675 14314 : Context oContext;
1676 7157 : oContext = m_oCurCtxt;
1677 7157 : oContext.m_nLevel = m_nLevel;
1678 7157 : oContext.m_osCurSubXPath = m_osCurSubXPath;
1679 7157 : m_osCurSubXPath = osNestedXPath;
1680 : #ifdef DEBUG_VERBOSE
1681 : CPLDebug("GMLAS",
1682 : "Installing new m_osCurSubXPath from %s to %s",
1683 : oContext.m_osCurSubXPath.c_str(),
1684 : m_osCurSubXPath.c_str());
1685 : #endif
1686 7157 : PushContext(oContext);
1687 7157 : m_oCurCtxt.m_oMapCounter.clear();
1688 :
1689 : // Process attributes now because we might need to
1690 : // fetch the child id from them
1691 7157 : ProcessAttributes(attrs);
1692 7157 : bHasProcessedAttributes = true;
1693 :
1694 : CPLString osChildId(
1695 7157 : m_oCurCtxt.m_poFeature->GetFieldAsString(
1696 14314 : m_oCurCtxt.m_poLayer->GetIDFieldIdx()));
1697 7157 : SetField(poOldCurFeature, poOldLayer, nOldCurFieldIdx,
1698 : osChildId);
1699 :
1700 29 : if (m_bProcessSWEDataRecord && !m_bIsXMLBlob &&
1701 29 : m_nSWEDataArrayLevel < 0 &&
1702 7191 : m_nSWEDataRecordLevel < 0 &&
1703 5 : osNestedXPath == "swe:DataRecord")
1704 : {
1705 5 : m_nSWEDataRecordLevel = m_nLevel;
1706 5 : BuildXMLBlobStartElement(osXPath, attrs);
1707 : }
1708 : }
1709 : }
1710 118957 : }
1711 : }
1712 :
1713 : #if 0
1714 : // Case where we have an abstract type and don't know its realizations
1715 : else if ( idx != IDX_COMPOUND_FOLDED &&
1716 : (idx = m_oCurCtxt.m_poLayer->GetOGRFieldIndexFromXPath(
1717 : osSubXPathBefore + "/" + "*")) >= 0 &&
1718 : m_oCurCtxt.m_poGroupLayer == NULL )
1719 : {
1720 : m_nCurFieldIdx = idx;
1721 : m_nCurFieldLevel = m_nLevel + 1;
1722 : m_osTextContent.clear();
1723 : m_bIsXMLBlob = true;
1724 : m_bIsXMLBlobIncludeUpper = true;
1725 : BuildXMLBlobStartElement(osNSPrefix, osLocalname, attrs);
1726 : m_nLevel ++;
1727 : return;
1728 : }
1729 : #endif
1730 :
1731 34118 : else if (m_nLevel > m_aoStackContext.back().m_nLevel)
1732 : {
1733 : // Figure out if it is an element that calls from a related
1734 : // top-level feature with a junction table
1735 : const std::vector<GMLASField> &aoFields =
1736 20586 : m_oCurCtxt.m_poLayer->GetFeatureClass().GetFields();
1737 1496610 : for (size_t i = 0; i < aoFields.size(); ++i)
1738 : {
1739 1480620 : if (aoFields[i].GetCategory() ==
1740 1531710 : GMLASField::PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE &&
1741 51085 : aoFields[i].GetXPath() == m_osCurSubXPath)
1742 : {
1743 : const CPLString &osAbstractElementXPath(
1744 4596 : aoFields[i].GetAbstractElementXPath());
1745 : const CPLString &osNestedXPath(
1746 4596 : aoFields[i].GetRelatedClassXPath());
1747 4596 : CPLAssert(!osAbstractElementXPath.empty());
1748 4596 : CPLAssert(!osNestedXPath.empty());
1749 :
1750 4596 : OGRGMLASLayer *poJunctionLayer = GetLayerByXPath(
1751 9192 : GMLASSchemaAnalyzer::BuildJunctionTableXPath(
1752 : osAbstractElementXPath, osNestedXPath));
1753 4596 : OGRGMLASLayer *poSubLayer = GetLayerByXPath(osNestedXPath);
1754 :
1755 4596 : if (poSubLayer && poJunctionLayer)
1756 : {
1757 : CPLString osParentId(
1758 4596 : m_oCurCtxt.m_poFeature->GetFieldAsString(
1759 9192 : m_oCurCtxt.m_poLayer->GetIDFieldIdx()));
1760 :
1761 : // Create child feature
1762 4596 : m_oCurCtxt.m_poLayer = poSubLayer;
1763 4596 : CreateNewFeature(osLocalname);
1764 :
1765 4596 : ++m_oMapGlobalCounter[poJunctionLayer];
1766 : const int nGlobalCounter =
1767 4596 : m_oMapGlobalCounter[poJunctionLayer];
1768 :
1769 4596 : ++m_oCurCtxt.m_oMapCounter[poJunctionLayer];
1770 : const int nCounter =
1771 4596 : m_oCurCtxt.m_oMapCounter[poJunctionLayer];
1772 :
1773 4596 : m_oCurCtxt.m_poGroupLayer = nullptr;
1774 4596 : m_oCurCtxt.m_nGroupLayerLevel = -1;
1775 4596 : m_oCurCtxt.m_nLastFieldIdxGroupLayer = -1;
1776 :
1777 : // Install new context
1778 9192 : Context oContext;
1779 4596 : oContext = m_oCurCtxt;
1780 4596 : oContext.m_nLevel = m_nLevel;
1781 4596 : oContext.m_osCurSubXPath = m_osCurSubXPath;
1782 4596 : m_osCurSubXPath = osNestedXPath;
1783 : #ifdef DEBUG_VERBOSE
1784 : CPLDebug("GMLAS",
1785 : "Installing new m_osCurSubXPath from %s to %s",
1786 : oContext.m_osCurSubXPath.c_str(),
1787 : m_osCurSubXPath.c_str());
1788 : #endif
1789 4596 : PushContext(oContext);
1790 4596 : m_oCurCtxt.m_oMapCounter.clear();
1791 :
1792 : // Process attributes now because we might need to
1793 : // fetch the child id from them
1794 4596 : ProcessAttributes(attrs);
1795 4596 : bHasProcessedAttributes = true;
1796 :
1797 : CPLString osChildId(
1798 4596 : m_oCurCtxt.m_poFeature->GetFieldAsString(
1799 9192 : m_oCurCtxt.m_poLayer->GetIDFieldIdx()));
1800 :
1801 : // Create junction feature
1802 : auto poJunctionFeature = std::make_unique<OGRFeature>(
1803 9192 : poJunctionLayer->GetLayerDefn());
1804 4596 : poJunctionFeature->SetFID(nGlobalCounter);
1805 4596 : poJunctionFeature->SetField(szOCCURRENCE, nCounter);
1806 4596 : poJunctionFeature->SetField(szPARENT_PKID, osParentId);
1807 4596 : poJunctionFeature->SetField(szCHILD_PKID, osChildId);
1808 4596 : PushFeatureReady(std::move(poJunctionFeature),
1809 : poJunctionLayer);
1810 : }
1811 4596 : idx = IDX_COMPOUND_FOLDED;
1812 :
1813 4596 : break;
1814 : }
1815 : }
1816 :
1817 20586 : m_nCurFieldIdx = -1;
1818 20586 : m_nCurGeomFieldIdx = -1;
1819 20909 : if (idx != IDX_COMPOUND_FOLDED && m_nLevelSilentIgnoredXPath < 0 &&
1820 :
1821 : // Detect if we are in a situation where elements like
1822 : // <foo xsi:nil="true"/> have no corresponding OGR field
1823 : // because of the use of remove_unused_fields=true
1824 323 : !(m_oCurCtxt.m_poLayer->GetFCFieldIndexFromXPath(
1825 323 : m_osCurSubXPath) >= 0 &&
1826 78 : attrs.getLength() == 1 &&
1827 20586 : m_oMapURIToPrefix[transcode(attrs.getURI(0))] ==
1828 : szXSI_PREFIX &&
1829 20586 : transcode(attrs.getLocalName(0)) == szNIL))
1830 : {
1831 646 : CPLString osMatchedXPath;
1832 323 : if (m_oIgnoredXPathMatcher.MatchesRefXPath(m_osCurSubXPath,
1833 : osMatchedXPath))
1834 : {
1835 0 : if (m_oMapIgnoredXPathToWarn[osMatchedXPath])
1836 : {
1837 0 : CPLError(CE_Warning, CPLE_AppDefined,
1838 : "Element with xpath=%s found in document but "
1839 : "ignored according to configuration",
1840 : m_osCurSubXPath.c_str());
1841 : }
1842 : else
1843 : {
1844 0 : CPLDebug("GMLAS",
1845 : "Element with xpath=%s found in document but "
1846 : "ignored according to configuration",
1847 : m_osCurSubXPath.c_str());
1848 : }
1849 0 : m_nLevelSilentIgnoredXPath = m_nLevel;
1850 : }
1851 : else
1852 : {
1853 323 : if (m_bWarnUnexpected)
1854 : {
1855 9 : CPLError(CE_Warning, CPLE_AppDefined,
1856 : "Unexpected element with xpath=%s "
1857 : "(subxpath=%s) found",
1858 : m_osCurXPath.c_str(), m_osCurSubXPath.c_str());
1859 : }
1860 : else
1861 : {
1862 314 : CPLDebug("GMLAS",
1863 : "Unexpected element with xpath=%s "
1864 : "(subxpath=%s) found",
1865 : m_osCurXPath.c_str(), m_osCurSubXPath.c_str());
1866 : }
1867 : }
1868 : }
1869 : }
1870 : else
1871 : {
1872 13532 : m_nCurFieldIdx = -1;
1873 13532 : m_nCurGeomFieldIdx = -1;
1874 : }
1875 :
1876 153075 : if (!bHasProcessedAttributes && m_nLevelSilentIgnoredXPath < 0)
1877 141322 : ProcessAttributes(attrs);
1878 : }
1879 : else
1880 : {
1881 215 : m_nCurFieldIdx = -1;
1882 215 : m_nCurGeomFieldIdx = -1;
1883 : }
1884 :
1885 153290 : m_nLevel++;
1886 : }
1887 :
1888 : /************************************************************************/
1889 : /* ProcessAttributes() */
1890 : /************************************************************************/
1891 :
1892 153075 : void GMLASReader::ProcessAttributes(const Attributes &attrs)
1893 : {
1894 : // Browse through attributes and match them with one of our fields
1895 : const int nWildcardAttrIdx =
1896 153075 : m_oCurCtxt.m_poLayer->GetOGRFieldIndexFromXPath(m_osCurSubXPath + "/" +
1897 : szAT_ANY_ATTR);
1898 153075 : json_object *poWildcard = nullptr;
1899 :
1900 179700 : for (unsigned int i = 0; i < attrs.getLength(); i++)
1901 : {
1902 : const CPLString &osAttrNSPrefix(
1903 : m_osAttrNSPrefix =
1904 26625 : m_oMapURIToPrefix[transcode(attrs.getURI(i), m_osAttrNSUri)]);
1905 : const CPLString &osAttrLocalname(
1906 26625 : transcode(attrs.getLocalName(i), m_osAttrLocalName));
1907 : const CPLString &osAttrValue(
1908 26625 : transcode(attrs.getValue(i), m_osAttrValue));
1909 26625 : CPLString &osAttrXPath(m_osAttrXPath);
1910 26625 : if (!osAttrNSPrefix.empty())
1911 : {
1912 8915 : osAttrXPath.reserve(m_osCurSubXPath.size() + 2 +
1913 17830 : osAttrNSPrefix.size() + 1 +
1914 8915 : osAttrLocalname.size());
1915 8915 : osAttrXPath = m_osCurSubXPath;
1916 8915 : osAttrXPath += "/@";
1917 8915 : osAttrXPath += osAttrNSPrefix;
1918 8915 : osAttrXPath += ":";
1919 8915 : osAttrXPath += osAttrLocalname;
1920 : }
1921 : else
1922 : {
1923 35420 : osAttrXPath.reserve(m_osCurSubXPath.size() + 2 +
1924 17710 : osAttrLocalname.size());
1925 17710 : osAttrXPath = m_osCurSubXPath;
1926 17710 : osAttrXPath += "/@";
1927 17710 : osAttrXPath += osAttrLocalname;
1928 : }
1929 :
1930 : // CPLDebug("GMLAS", "Attr %s=%s", osAttrXPath.c_str(),
1931 : // osAttrValue.c_str());
1932 :
1933 : const int nAttrIdx =
1934 26625 : m_oCurCtxt.m_poLayer->GetOGRFieldIndexFromXPath(osAttrXPath);
1935 : int nFCIdx;
1936 26625 : if (nAttrIdx >= 0)
1937 : {
1938 : const OGRFieldType eType(
1939 19146 : m_oCurCtxt.m_poFeature->GetFieldDefnRef(nAttrIdx)->GetType());
1940 19146 : if (osAttrValue.empty() && eType == OFTString)
1941 : {
1942 0 : m_oCurCtxt.m_poFeature->SetField(nAttrIdx, "");
1943 : }
1944 : else
1945 : {
1946 19146 : SetField(m_oCurCtxt.m_poFeature, m_oCurCtxt.m_poLayer, nAttrIdx,
1947 : osAttrValue);
1948 : }
1949 :
1950 19201 : if (osAttrNSPrefix == szXLINK_PREFIX && osAttrLocalname == szHREF &&
1951 55 : !osAttrValue.empty())
1952 : {
1953 55 : ProcessXLinkHref(nAttrIdx, osAttrXPath, osAttrValue);
1954 : }
1955 :
1956 37767 : if (m_oXLinkResolver.GetConf().m_bResolveInternalXLinks &&
1957 18621 : m_bInitialPass)
1958 : {
1959 : nFCIdx =
1960 412 : m_oCurCtxt.m_poLayer->GetFCFieldIndexFromXPath(osAttrXPath);
1961 824 : if (nFCIdx >= 0 && m_oCurCtxt.m_poLayer->GetFeatureClass()
1962 412 : .GetFields()[nFCIdx]
1963 412 : .GetType() == GMLAS_FT_ID)
1964 : {
1965 : // We don't check that there's no existing id in the map
1966 : // This is normally forbidden by the xs:ID rules
1967 : // If not respected by the document, this should not lead to
1968 : // crashes
1969 42 : m_oMapElementIdToLayer[osAttrValue] = m_oCurCtxt.m_poLayer;
1970 :
1971 42 : if (m_oCurCtxt.m_poLayer->IsGeneratedIDField())
1972 : {
1973 : const std::string osFeaturePKID(
1974 19 : m_oCurCtxt.m_poFeature->GetFieldAsString(
1975 19 : m_oCurCtxt.m_poLayer->GetIDFieldIdx()));
1976 19 : m_oMapElementIdToPKID[osAttrValue] = osFeaturePKID;
1977 : }
1978 : }
1979 : }
1980 : }
1981 :
1982 7479 : else if (osAttrNSPrefix == szXSI_PREFIX && osAttrLocalname == szNIL)
1983 : {
1984 1161 : if (osAttrValue == "true")
1985 : {
1986 : const int nMainAttrIdx =
1987 2322 : m_oCurCtxt.m_poLayer->GetOGRFieldIndexFromXPath(
1988 1161 : m_osCurSubXPath);
1989 1161 : if (nMainAttrIdx >= 0)
1990 : {
1991 1140 : m_oCurCtxt.m_poFeature->SetFieldNull(nMainAttrIdx);
1992 : }
1993 : else
1994 : {
1995 : const int nHrefAttrIdx =
1996 21 : m_oCurCtxt.m_poLayer->GetOGRFieldIndexFromXPath(
1997 42 : m_osCurSubXPath + "/@" + szXLINK_PREFIX + ":" +
1998 : szHREF);
1999 21 : if (nHrefAttrIdx >= 0)
2000 : {
2001 0 : m_oCurCtxt.m_poFeature->SetFieldNull(nHrefAttrIdx);
2002 : }
2003 : }
2004 : }
2005 : }
2006 :
2007 6318 : else if (osAttrNSPrefix != szXMLNS_PREFIX &&
2008 2987 : osAttrLocalname != szXMLNS_PREFIX &&
2009 2945 : !(osAttrNSPrefix == szXSI_PREFIX &&
2010 1121 : osAttrLocalname == szSCHEMA_LOCATION) &&
2011 1840 : !(osAttrNSPrefix == szXSI_PREFIX &&
2012 9305 : osAttrLocalname == szNO_NAMESPACE_SCHEMA_LOCATION) &&
2013 : // Do not warn about fixed attributes on geometry properties
2014 1824 : !(m_nCurGeomFieldIdx >= 0 &&
2015 0 : ((osAttrNSPrefix == szXLINK_PREFIX &&
2016 0 : osAttrLocalname == szTYPE) ||
2017 0 : (osAttrNSPrefix == "" && osAttrLocalname == szOWNS))))
2018 : {
2019 3648 : CPLString osMatchedXPath;
2020 1824 : if (nWildcardAttrIdx >= 0)
2021 : {
2022 1812 : if (poWildcard == nullptr)
2023 1812 : poWildcard = json_object_new_object();
2024 3624 : CPLString osKey;
2025 1812 : if (!osAttrNSPrefix.empty())
2026 0 : osKey = osAttrNSPrefix + ":" + osAttrLocalname;
2027 : else
2028 1812 : osKey = osAttrLocalname;
2029 1812 : json_object_object_add(poWildcard, osKey,
2030 : json_object_new_string(osAttrValue));
2031 : }
2032 30 : else if (m_bValidate &&
2033 6 : (nFCIdx = m_oCurCtxt.m_poLayer->GetFCFieldIndexFromXPath(
2034 18 : osAttrXPath)) >= 0 &&
2035 6 : !m_oCurCtxt.m_poLayer->GetFeatureClass()
2036 3 : .GetFields()[nFCIdx]
2037 3 : .GetFixedValue()
2038 3 : .empty())
2039 : {
2040 : // In validation mode, fixed attributes not present in the
2041 : // document are still reported, which cause spurious warnings
2042 : }
2043 27 : else if (m_bValidate &&
2044 5 : (nFCIdx = m_oCurCtxt.m_poLayer->GetFCFieldIndexFromXPath(
2045 2 : osAttrXPath)) >= 0 &&
2046 4 : !m_oCurCtxt.m_poLayer->GetFeatureClass()
2047 2 : .GetFields()[nFCIdx]
2048 2 : .GetDefaultValue()
2049 18 : .empty() &&
2050 2 : m_oCurCtxt.m_poLayer->GetFeatureClass()
2051 2 : .GetFields()[nFCIdx]
2052 4 : .GetDefaultValue() == m_osAttrValue)
2053 : {
2054 : // In validation mode, default attributes not present in the
2055 : // document are still reported, which cause spurious warnings
2056 : }
2057 9 : else if (m_oIgnoredXPathMatcher.MatchesRefXPath(osAttrXPath,
2058 : osMatchedXPath))
2059 : {
2060 2 : if (m_oMapIgnoredXPathToWarn[osMatchedXPath])
2061 : {
2062 1 : CPLError(CE_Warning, CPLE_AppDefined,
2063 : "Attribute with xpath=%s found in document but "
2064 : "ignored according to configuration",
2065 : osAttrXPath.c_str());
2066 : }
2067 : else
2068 : {
2069 1 : CPLDebug("GMLAS",
2070 : "Attribute with xpath=%s found in document but "
2071 : "ignored according to configuration",
2072 : osAttrXPath.c_str());
2073 : }
2074 : }
2075 : else
2076 : {
2077 7 : if (m_bWarnUnexpected)
2078 : {
2079 5 : CPLError(CE_Warning, CPLE_AppDefined,
2080 : "Unexpected attribute with xpath=%s found",
2081 : osAttrXPath.c_str());
2082 : }
2083 : else
2084 : {
2085 : // Emit debug message if unexpected attribute
2086 2 : CPLDebug("GMLAS",
2087 : "Unexpected attribute with xpath=%s found",
2088 : osAttrXPath.c_str());
2089 : }
2090 : }
2091 : }
2092 : }
2093 :
2094 : // Store wildcard attributes
2095 153075 : if (poWildcard != nullptr)
2096 : {
2097 1812 : SetField(m_oCurCtxt.m_poFeature, m_oCurCtxt.m_poLayer, nWildcardAttrIdx,
2098 : json_object_get_string(poWildcard));
2099 1812 : json_object_put(poWildcard);
2100 : }
2101 :
2102 : // Process fixed and default values, except when doing the initial scan
2103 : // so as to avoid the bRemoveUnusedFields logic to be confused
2104 153075 : if (!m_bInitialPass)
2105 : {
2106 147024 : const int nFieldCount = m_oCurCtxt.m_poFeature->GetFieldCount();
2107 : const std::vector<GMLASField> &aoFields =
2108 147024 : m_oCurCtxt.m_poLayer->GetFeatureClass().GetFields();
2109 5399380 : for (int i = 0; i < nFieldCount; i++)
2110 : {
2111 : const int nFCIdx =
2112 5252350 : m_oCurCtxt.m_poLayer->GetFCFieldIndexFromOGRFieldIdx(i);
2113 10362800 : if (nFCIdx >= 0 &&
2114 5110420 : aoFields[nFCIdx].GetXPath().find('@') != std::string::npos)
2115 : {
2116 : // We process fixed as default. In theory, to be XSD compliant,
2117 : // the user shouldn't have put a different value than the fixed
2118 : // one, but just in case he did, then honour it instead of
2119 : // overwriting it.
2120 : CPLString osFixedDefaultValue =
2121 3229300 : aoFields[nFCIdx].GetFixedValue();
2122 1614650 : if (osFixedDefaultValue.empty())
2123 1483370 : osFixedDefaultValue = aoFields[nFCIdx].GetDefaultValue();
2124 1877210 : if (!osFixedDefaultValue.empty() &&
2125 262564 : !m_oCurCtxt.m_poFeature->IsFieldSetAndNotNull(i))
2126 : {
2127 2072 : SetField(m_oCurCtxt.m_poFeature, m_oCurCtxt.m_poLayer, i,
2128 : osFixedDefaultValue);
2129 : }
2130 : }
2131 : }
2132 : }
2133 153075 : }
2134 :
2135 : /************************************************************************/
2136 : /* ProcessXLinkHref() */
2137 : /************************************************************************/
2138 :
2139 55 : void GMLASReader::ProcessXLinkHref(int nAttrIdx, const CPLString &osAttrXPath,
2140 : const CPLString &osAttrValue)
2141 : {
2142 : // If we are a xlink:href attribute, and that the link value is
2143 : // a internal link, then find if we have
2144 : // a field that does a relation to a targetElement
2145 55 : if (osAttrValue[0] == '#')
2146 : {
2147 20 : const int nAttrIdx2 = m_oCurCtxt.m_poLayer->GetOGRFieldIndexFromXPath(
2148 40 : GMLASField::MakePKIDFieldXPathFromXLinkHrefXPath(osAttrXPath));
2149 20 : if (nAttrIdx2 >= 0)
2150 : {
2151 2 : SetField(m_oCurCtxt.m_poFeature, m_oCurCtxt.m_poLayer, nAttrIdx2,
2152 4 : osAttrValue.substr(1));
2153 : }
2154 18 : else if (m_oXLinkResolver.GetConf().m_bResolveInternalXLinks)
2155 : {
2156 : const CPLString osReferringField(
2157 18 : m_oCurCtxt.m_poLayer->GetLayerDefn()
2158 18 : ->GetFieldDefn(nAttrIdx)
2159 36 : ->GetNameRef());
2160 36 : const CPLString osId(osAttrValue.substr(1));
2161 18 : if (m_bInitialPass)
2162 : {
2163 : std::pair<OGRGMLASLayer *, CPLString> oReferringPair(
2164 18 : m_oCurCtxt.m_poLayer, osReferringField);
2165 9 : m_oMapFieldXPathToLinkValue[oReferringPair].push_back(osId);
2166 : }
2167 : else
2168 : {
2169 9 : const auto oIter = m_oMapElementIdToLayer.find(osId);
2170 9 : if (oIter != m_oMapElementIdToLayer.end())
2171 : {
2172 5 : OGRGMLASLayer *poTargetLayer = oIter->second;
2173 : const CPLString osLinkFieldXPath =
2174 5 : m_oCurCtxt.m_poLayer
2175 : ->GetXPathOfFieldLinkForAttrToOtherLayer(
2176 : osReferringField,
2177 10 : poTargetLayer->GetFeatureClass().GetXPath());
2178 : const int nLinkFieldOGRId =
2179 5 : m_oCurCtxt.m_poLayer->GetOGRFieldIndexFromXPath(
2180 : osLinkFieldXPath);
2181 5 : if (nLinkFieldOGRId >= 0)
2182 : {
2183 5 : const auto oIter2 = m_oMapElementIdToPKID.find(osId);
2184 5 : if (oIter2 != m_oMapElementIdToPKID.end())
2185 : {
2186 3 : m_oCurCtxt.m_poFeature->SetField(nLinkFieldOGRId,
2187 3 : oIter2->second);
2188 : }
2189 : else
2190 : {
2191 2 : m_oCurCtxt.m_poFeature->SetField(nLinkFieldOGRId,
2192 : osId);
2193 : }
2194 : }
2195 : }
2196 : }
2197 : }
2198 : }
2199 : else
2200 : {
2201 : const int nRuleIdx =
2202 35 : m_oXLinkResolver.GetMatchingResolutionRule(osAttrValue);
2203 35 : if (nRuleIdx >= 0)
2204 : {
2205 : const GMLASXLinkResolutionConf::URLSpecificResolution &oRule(
2206 14 : m_oXLinkResolver.GetConf().m_aoURLSpecificRules[nRuleIdx]);
2207 14 : if (m_bInitialPass)
2208 : {
2209 8 : m_oMapXLinkFields[m_oCurCtxt.m_poLayer][osAttrXPath].insert(
2210 8 : nRuleIdx);
2211 : }
2212 6 : else if (oRule.m_eResolutionMode ==
2213 : GMLASXLinkResolutionConf::RawContent)
2214 : {
2215 : const int nAttrIdx2 =
2216 1 : m_oCurCtxt.m_poLayer->GetOGRFieldIndexFromXPath(
2217 : GMLASField::
2218 2 : MakeXLinkRawContentFieldXPathFromXLinkHrefXPath(
2219 : osAttrXPath));
2220 1 : CPLAssert(nAttrIdx2 >= 0);
2221 :
2222 : const CPLString osRawContent(
2223 1 : m_oXLinkResolver.GetRawContentForRule(osAttrValue,
2224 2 : nRuleIdx));
2225 1 : if (!osRawContent.empty())
2226 : {
2227 1 : SetField(m_oCurCtxt.m_poFeature, m_oCurCtxt.m_poLayer,
2228 : nAttrIdx2, osRawContent);
2229 : }
2230 : }
2231 5 : else if (oRule.m_eResolutionMode ==
2232 : GMLASXLinkResolutionConf::FieldsFromXPath)
2233 : {
2234 : const CPLString osRawContent(
2235 5 : m_oXLinkResolver.GetRawContentForRule(osAttrValue,
2236 10 : nRuleIdx));
2237 5 : if (!osRawContent.empty())
2238 : {
2239 5 : CPLXMLNode *psNode = CPLParseXMLString(osRawContent);
2240 5 : if (psNode != nullptr)
2241 : {
2242 10 : std::vector<CPLString> aoXPaths;
2243 10 : std::map<CPLString, size_t> oMapFieldXPathToIdx;
2244 23 : for (size_t i = 0; i < oRule.m_aoFields.size(); ++i)
2245 : {
2246 : const CPLString &osXPathRule(
2247 18 : oRule.m_aoFields[i].m_osXPath);
2248 18 : aoXPaths.push_back(osXPathRule);
2249 18 : oMapFieldXPathToIdx[osXPathRule] = i;
2250 : }
2251 10 : GMLASXPathMatcher oMatcher;
2252 5 : oMatcher.SetRefXPaths(std::map<CPLString, CPLString>(),
2253 : aoXPaths);
2254 5 : oMatcher.SetDocumentMapURIToPrefix(
2255 10 : std::map<CPLString, CPLString>());
2256 :
2257 5 : CPLXMLNode *psIter = psNode;
2258 15 : for (; psIter != nullptr; psIter = psIter->psNext)
2259 : {
2260 10 : if (psIter->eType == CXT_Element &&
2261 10 : psIter->pszValue[0] != '?')
2262 : {
2263 5 : ExploreXMLDoc(osAttrXPath, oRule, psIter,
2264 10 : CPLString(), oMatcher,
2265 : oMapFieldXPathToIdx);
2266 : }
2267 : }
2268 : }
2269 5 : CPLDestroyXMLNode(psNode);
2270 : }
2271 : }
2272 : }
2273 21 : else if (m_oXLinkResolver.IsRawContentResolutionEnabled())
2274 : {
2275 : const int nAttrIdx2 =
2276 11 : m_oCurCtxt.m_poLayer->GetOGRFieldIndexFromXPath(
2277 22 : GMLASField::MakeXLinkRawContentFieldXPathFromXLinkHrefXPath(
2278 : osAttrXPath));
2279 11 : CPLAssert(nAttrIdx2 >= 0);
2280 :
2281 : const CPLString osRawContent(
2282 22 : m_oXLinkResolver.GetRawContent(osAttrValue));
2283 11 : if (!osRawContent.empty())
2284 : {
2285 7 : SetField(m_oCurCtxt.m_poFeature, m_oCurCtxt.m_poLayer,
2286 : nAttrIdx2, osRawContent);
2287 : }
2288 : }
2289 : }
2290 55 : }
2291 :
2292 : /************************************************************************/
2293 : /* ExploreXMLDoc() */
2294 : /************************************************************************/
2295 :
2296 29 : void GMLASReader::ExploreXMLDoc(
2297 : const CPLString &osAttrXPath,
2298 : const GMLASXLinkResolutionConf::URLSpecificResolution &oRule,
2299 : CPLXMLNode *psNode, const CPLString &osParentXPath,
2300 : const GMLASXPathMatcher &oMatcher,
2301 : const std::map<CPLString, size_t> &oMapFieldXPathToIdx)
2302 : {
2303 58 : CPLString osXPath;
2304 29 : if (osParentXPath.empty())
2305 5 : osXPath = psNode->pszValue;
2306 24 : else if (psNode->eType == CXT_Element)
2307 22 : osXPath = osParentXPath + "/" + psNode->pszValue;
2308 : else
2309 : {
2310 2 : CPLAssert(psNode->eType == CXT_Attribute);
2311 2 : osXPath = osParentXPath + "/@" + psNode->pszValue;
2312 : }
2313 :
2314 58 : CPLString osMatchedXPathRule;
2315 29 : if (oMatcher.MatchesRefXPath(osXPath, osMatchedXPathRule))
2316 : {
2317 20 : const auto oIter = oMapFieldXPathToIdx.find(osMatchedXPathRule);
2318 20 : CPLAssert(oIter != oMapFieldXPathToIdx.end());
2319 20 : const size_t nFieldRuleIdx = oIter->second;
2320 : const CPLString osDerivedFieldXPath(
2321 : GMLASField::MakeXLinkDerivedFieldXPathFromXLinkHrefXPath(
2322 40 : osAttrXPath, oRule.m_aoFields[nFieldRuleIdx].m_osName));
2323 20 : const int nAttrIdx = m_oCurCtxt.m_poLayer->GetOGRFieldIndexFromXPath(
2324 : osDerivedFieldXPath);
2325 20 : CPLAssert(nAttrIdx >= 0);
2326 40 : CPLString osVal;
2327 20 : if (psNode->eType == CXT_Element && psNode->psChild != nullptr &&
2328 18 : psNode->psChild->eType == CXT_Text &&
2329 18 : psNode->psChild->psNext == nullptr)
2330 : {
2331 16 : osVal = psNode->psChild->pszValue;
2332 : }
2333 4 : else if (psNode->eType == CXT_Attribute)
2334 : {
2335 2 : osVal = psNode->psChild->pszValue;
2336 : }
2337 : else
2338 : {
2339 2 : char *pszContent = CPLSerializeXMLTree(psNode->psChild);
2340 2 : osVal = pszContent;
2341 2 : CPLFree(pszContent);
2342 : }
2343 22 : if (m_oCurCtxt.m_poFeature->IsFieldSetAndNotNull(nAttrIdx) &&
2344 2 : m_oCurCtxt.m_poFeature->GetFieldDefnRef(nAttrIdx)->GetType() ==
2345 : OFTString)
2346 : {
2347 2 : osVal = m_oCurCtxt.m_poFeature->GetFieldAsString(nAttrIdx) +
2348 4 : CPLString(" ") + osVal;
2349 : }
2350 20 : SetField(m_oCurCtxt.m_poFeature, m_oCurCtxt.m_poLayer, nAttrIdx, osVal);
2351 : }
2352 :
2353 29 : CPLXMLNode *psIter = psNode->psChild;
2354 75 : for (; psIter != nullptr; psIter = psIter->psNext)
2355 : {
2356 46 : if (psIter->eType == CXT_Element || psIter->eType == CXT_Attribute)
2357 : {
2358 24 : ExploreXMLDoc(osAttrXPath, oRule, psIter, osXPath, oMatcher,
2359 : oMapFieldXPathToIdx);
2360 : }
2361 : }
2362 29 : }
2363 :
2364 : /************************************************************************/
2365 : /* endElement() */
2366 : /************************************************************************/
2367 :
2368 162232 : void GMLASReader::endElement(const XMLCh *const uri,
2369 : const XMLCh *const localname,
2370 : const XMLCh *const
2371 : #ifdef DEBUG_VERBOSE
2372 : qname
2373 : #endif
2374 : )
2375 : {
2376 162232 : m_nEntityCounter = 0;
2377 :
2378 162232 : m_nLevel--;
2379 :
2380 : #ifdef DEBUG_VERBOSE
2381 : CPLDebug("GMLAS", "m_nLevel = %d", m_nLevel);
2382 : #endif
2383 :
2384 : #ifdef DEBUG_VERBOSE
2385 : {
2386 : const CPLString &osLocalname(transcode(localname, m_osLocalname));
2387 : const CPLString &osNSPrefix(
2388 : m_osNSPrefix = m_oMapURIToPrefix[transcode(uri, m_osNSUri)]);
2389 : if (osNSPrefix.empty())
2390 : m_osXPath = osLocalname;
2391 : else
2392 : {
2393 : m_osXPath.reserve(osNSPrefix.size() + 1 + osLocalname.size());
2394 : m_osXPath = osNSPrefix;
2395 : m_osXPath += ":";
2396 : m_osXPath += osLocalname;
2397 : }
2398 : }
2399 : CPLDebug("GMLAS", "endElement(%s / %s)", transcode(qname).c_str(),
2400 : m_osXPath.c_str());
2401 : #endif
2402 :
2403 162232 : if (m_nLevelSilentIgnoredXPath == m_nLevel)
2404 : {
2405 0 : m_nLevelSilentIgnoredXPath = -1;
2406 : }
2407 :
2408 : // Make sure to set field only if we are at the expected nesting level
2409 162232 : if (m_nCurFieldIdx >= 0 && m_nLevel == m_nCurFieldLevel - 1)
2410 : {
2411 : const OGRFieldType eType(
2412 113078 : m_oCurCtxt.m_poFeature->GetFieldDefnRef(m_nCurFieldIdx)->GetType());
2413 :
2414 : // Assign XML content to field value
2415 113078 : if (IsArrayType(eType))
2416 : {
2417 : const int nFCFieldIdx =
2418 28886 : m_oCurCtxt.m_poLayer->GetFCFieldIndexFromOGRFieldIdx(
2419 : m_nCurFieldIdx);
2420 57772 : if (nFCFieldIdx >= 0 && m_oCurCtxt.m_poLayer->GetFeatureClass()
2421 28886 : .GetFields()[nFCFieldIdx]
2422 28886 : .IsList())
2423 : {
2424 5300 : SetField(m_oCurCtxt.m_poFeature, m_oCurCtxt.m_poLayer,
2425 5300 : m_nCurFieldIdx, m_osTextContent);
2426 : }
2427 23586 : else if (m_nTextContentListEstimatedSize > m_nMaxContentSize)
2428 : {
2429 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
2430 : "Too much repeated data in a single element");
2431 0 : m_bParsingError = true;
2432 : }
2433 : else
2434 : {
2435 : // Transform boolean values to something that OGR understands
2436 29806 : if (eType == OFTIntegerList &&
2437 6220 : m_oCurCtxt.m_poFeature->GetFieldDefnRef(m_nCurFieldIdx)
2438 6220 : ->GetSubType() == OFSTBoolean)
2439 : {
2440 2140 : if (m_osTextContent == "true")
2441 1052 : m_osTextContent = "1";
2442 : else
2443 1088 : m_osTextContent = "0";
2444 : }
2445 :
2446 23586 : m_osTextContentList.AddString(m_osTextContent);
2447 : // 16 is an arbitrary number for the cost of a new entry in the
2448 : // string list
2449 23586 : m_nTextContentListEstimatedSize += 16 + m_osTextContent.size();
2450 23586 : m_oCurCtxt.m_poFeature->SetField(m_nCurFieldIdx,
2451 23586 : m_osTextContentList.List());
2452 : }
2453 : }
2454 : else
2455 : {
2456 84192 : if (m_bIsXMLBlobIncludeUpper && FillTextContent())
2457 : {
2458 : const CPLString &osLocalname(
2459 1638 : transcode(localname, m_osLocalname));
2460 : const CPLString &osNSPrefix(
2461 1638 : m_oMapURIToPrefix[transcode(uri, m_osNSUri)]);
2462 :
2463 1638 : m_osTextContent += "</";
2464 1638 : if (!osNSPrefix.empty())
2465 : {
2466 2 : m_osTextContent += osNSPrefix;
2467 2 : m_osTextContent += ":";
2468 : }
2469 1638 : m_osTextContent += osLocalname;
2470 1638 : m_osTextContent += ">";
2471 : }
2472 :
2473 84192 : SetField(m_oCurCtxt.m_poFeature, m_oCurCtxt.m_poLayer,
2474 84192 : m_nCurFieldIdx, m_osTextContent);
2475 : }
2476 : }
2477 :
2478 : // Make sure to set field only if we are at the expected nesting level
2479 162232 : if (m_nCurGeomFieldIdx >= 0 && m_nLevel == m_nCurFieldLevel - 1)
2480 : {
2481 444 : if (!m_apsXMLNodeStack.empty())
2482 : {
2483 420 : CPLAssert(m_apsXMLNodeStack.size() == 1);
2484 420 : CPLXMLNode *psRoot = m_apsXMLNodeStack[0].psNode;
2485 420 : ProcessGeometry(psRoot);
2486 420 : CPLDestroyXMLNode(psRoot);
2487 420 : m_apsXMLNodeStack.clear();
2488 : }
2489 : }
2490 :
2491 162232 : if ((m_nCurFieldIdx >= 0 || m_nCurGeomFieldIdx >= 0) &&
2492 148093 : m_nLevel == m_nCurFieldLevel - 1)
2493 : {
2494 113446 : m_bIsXMLBlob = false;
2495 113446 : m_bIsXMLBlobIncludeUpper = false;
2496 : }
2497 :
2498 162232 : if (m_bIsXMLBlob)
2499 : {
2500 7832 : if (m_nCurGeomFieldIdx >= 0)
2501 : {
2502 1478 : if (m_apsXMLNodeStack.size() > 1)
2503 : {
2504 : #ifdef DEBUG_VERBOSE
2505 : CPLDebug("GMLAS", "m_apsXMLNodeStack.pop_back()");
2506 : #endif
2507 1074 : m_apsXMLNodeStack.pop_back();
2508 : }
2509 : }
2510 :
2511 7832 : if (FillTextContent())
2512 : {
2513 4716 : const CPLString &osLocalname(transcode(localname, m_osLocalname));
2514 : const CPLString &osNSPrefix(
2515 4716 : m_oMapURIToPrefix[transcode(uri, m_osNSUri)]);
2516 :
2517 4716 : m_osTextContent += "</";
2518 4716 : if (!osNSPrefix.empty())
2519 : {
2520 1011 : m_osTextContent += osNSPrefix;
2521 1011 : m_osTextContent += ":";
2522 : }
2523 4716 : m_osTextContent += osLocalname;
2524 4716 : m_osTextContent += ">";
2525 :
2526 4716 : if (m_osTextContent.size() > m_nMaxContentSize)
2527 : {
2528 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
2529 : "Too much data in a single element");
2530 0 : m_bParsingError = true;
2531 : }
2532 : }
2533 : }
2534 : else
2535 : {
2536 154400 : m_osTextContent.clear();
2537 : }
2538 :
2539 162232 : if (m_nSWEDataArrayLevel >= 0)
2540 : {
2541 204 : if (m_nLevel > m_nSWEDataArrayLevel)
2542 : {
2543 192 : CPLAssert(m_apsXMLNodeStack.size() > 1);
2544 192 : m_apsXMLNodeStack.pop_back();
2545 : }
2546 : else
2547 : {
2548 12 : CPLAssert(m_apsXMLNodeStack.size() == 1);
2549 12 : CPLXMLNode *psRoot = m_apsXMLNodeStack[0].psNode;
2550 12 : ProcessSWEDataArray(psRoot);
2551 12 : m_nSWEDataArrayLevel = -1;
2552 12 : CPLDestroyXMLNode(psRoot);
2553 12 : m_apsXMLNodeStack.clear();
2554 : }
2555 : }
2556 :
2557 : // The while and not just if is needed when a group is at the end of an
2558 : // element
2559 437298 : while (!m_aoStackContext.empty() &&
2560 218059 : m_aoStackContext.back().m_nLevel >= m_nLevel)
2561 : {
2562 114014 : auto oMapCounter = m_aoStackContext.back().m_oMapCounter;
2563 57007 : if (!m_aoStackContext.back().m_osCurSubXPath.empty())
2564 : {
2565 : #ifdef DEBUG_VERBOSE
2566 : CPLDebug("GMLAS", "Restoring m_osCurSubXPath from %s to %s",
2567 : m_osCurSubXPath.c_str(),
2568 : m_aoStackContext.back().m_osCurSubXPath.c_str());
2569 : #endif
2570 11613 : m_osCurSubXPath = m_aoStackContext.back().m_osCurSubXPath;
2571 : }
2572 :
2573 57007 : if (m_oCurCtxt.m_poGroupLayer == m_oCurCtxt.m_poLayer)
2574 : {
2575 12403 : PopContext();
2576 12403 : CPLAssert(!m_aoStackContext.empty());
2577 12403 : m_oCurCtxt.m_poLayer = m_aoStackContext.back().m_poLayer;
2578 : }
2579 : else
2580 : {
2581 44604 : if (m_oCurCtxt.m_poGroupLayer)
2582 : {
2583 : /* Case like
2584 : <first_elt_of_group>...</first_elt_of_group>
2585 : </end_of_enclosing_element> <!-- we are here at
2586 : endElement() -->
2587 : */
2588 :
2589 : // CPLDebug("GMLAS", "Feature ready");
2590 0 : PushFeatureReady(
2591 0 : std::unique_ptr<OGRFeature>(m_oCurCtxt.m_poFeature),
2592 : m_oCurCtxt.m_poGroupLayer);
2593 : // CPLDebug("GMLAS", "Feature ready");
2594 0 : PushFeatureReady(std::unique_ptr<OGRFeature>(
2595 0 : m_aoStackContext.back().m_poFeature),
2596 0 : m_aoStackContext.back().m_poLayer);
2597 : }
2598 : else
2599 : {
2600 : // CPLDebug("GMLAS", "Feature ready");
2601 44604 : PushFeatureReady(
2602 89208 : std::unique_ptr<OGRFeature>(m_oCurCtxt.m_poFeature),
2603 : m_oCurCtxt.m_poLayer);
2604 : }
2605 44604 : PopContext();
2606 44604 : if (!m_aoStackContext.empty())
2607 : {
2608 43608 : m_oCurCtxt = m_aoStackContext.back();
2609 43608 : m_oCurCtxt.m_osCurSubXPath.clear();
2610 43608 : if (m_oCurCtxt.m_nLevel < 0)
2611 : {
2612 3517 : PopContext();
2613 3517 : CPLAssert(!m_aoStackContext.empty());
2614 3517 : m_oCurCtxt.m_poLayer = m_aoStackContext.back().m_poLayer;
2615 : }
2616 : }
2617 : else
2618 : {
2619 996 : m_oCurCtxt.m_poFeature = nullptr;
2620 996 : m_oCurCtxt.m_poLayer = nullptr;
2621 996 : m_oCurCtxt.m_poGroupLayer = nullptr;
2622 996 : m_oCurCtxt.m_nGroupLayerLevel = -1;
2623 996 : m_oCurCtxt.m_nLastFieldIdxGroupLayer = -1;
2624 : }
2625 44604 : m_nCurFieldIdx = -1;
2626 : }
2627 57007 : m_oCurCtxt.m_oMapCounter = std::move(oMapCounter);
2628 :
2629 : #ifdef DEBUG_VERBOSE
2630 : CPLDebug("GMLAS", "m_oCurCtxt = ");
2631 : m_oCurCtxt.Dump();
2632 : #endif
2633 : }
2634 :
2635 162232 : size_t nLastXPathLength = m_anStackXPathLength.back();
2636 162232 : m_anStackXPathLength.pop_back();
2637 162232 : if (m_anStackXPathLength.empty())
2638 946 : m_osCurXPath.clear();
2639 : else
2640 161286 : m_osCurXPath.resize(m_osCurXPath.size() - 1 - nLastXPathLength);
2641 :
2642 162232 : if (m_osCurSubXPath.size() >= 1 + nLastXPathLength)
2643 161052 : m_osCurSubXPath.resize(m_osCurSubXPath.size() - 1 - nLastXPathLength);
2644 1180 : else if (m_osCurSubXPath.size() == nLastXPathLength)
2645 996 : m_osCurSubXPath.clear();
2646 :
2647 162232 : if (m_nSWEDataRecordLevel >= 0)
2648 : {
2649 87 : if (m_nLevel > m_nSWEDataRecordLevel)
2650 : {
2651 82 : CPLAssert(m_apsXMLNodeStack.size() > 1);
2652 82 : m_apsXMLNodeStack.pop_back();
2653 : }
2654 : else
2655 : {
2656 5 : CPLAssert(m_apsXMLNodeStack.size() == 1);
2657 5 : CPLXMLNode *psRoot = m_apsXMLNodeStack[0].psNode;
2658 5 : ProcessSWEDataRecord(psRoot);
2659 5 : m_nSWEDataRecordLevel = -1;
2660 5 : CPLDestroyXMLNode(psRoot);
2661 5 : m_apsXMLNodeStack.clear();
2662 : }
2663 : }
2664 162232 : }
2665 :
2666 : /************************************************************************/
2667 : /* startEntity() */
2668 : /************************************************************************/
2669 :
2670 2002 : void GMLASReader::startEntity(const XMLCh *const /* name */)
2671 : {
2672 2002 : m_nEntityCounter++;
2673 2002 : if (m_nEntityCounter > 1000 && !m_bParsingError)
2674 : {
2675 : throw SAXNotSupportedException(
2676 2 : "File probably corrupted (million laugh pattern)");
2677 : }
2678 2000 : }
2679 :
2680 : /************************************************************************/
2681 : /* SetSWEValue() */
2682 : /************************************************************************/
2683 :
2684 63 : static void SetSWEValue(OGRFeature *poFeature, int iField, CPLString &osValue)
2685 : {
2686 63 : if (!osValue.empty())
2687 : {
2688 57 : OGRFieldDefn *poFieldDefn = poFeature->GetFieldDefnRef(iField);
2689 57 : OGRFieldType eType(poFieldDefn->GetType());
2690 57 : OGRFieldSubType eSubType(poFieldDefn->GetSubType());
2691 57 : if (eType == OFTReal || eType == OFTInteger)
2692 : {
2693 24 : osValue.Trim();
2694 24 : if (eSubType == OFSTBoolean)
2695 : {
2696 : osValue =
2697 3 : EQUAL(osValue, "1") || EQUAL(osValue, "True") ? "1" : "0";
2698 : }
2699 : }
2700 57 : poFeature->SetField(iField, osValue.c_str());
2701 : }
2702 63 : }
2703 :
2704 : /************************************************************************/
2705 : /* SkipSpace() */
2706 : /************************************************************************/
2707 :
2708 111 : static size_t SkipSpace(const char *pszValues, size_t i)
2709 : {
2710 111 : while (isspace(static_cast<unsigned char>(pszValues[i])))
2711 39 : i++;
2712 72 : return i;
2713 : }
2714 :
2715 : /************************************************************************/
2716 : /* ProcessSWEDataArray() */
2717 : /************************************************************************/
2718 :
2719 12 : void GMLASReader::ProcessSWEDataArray(CPLXMLNode *psRoot)
2720 : {
2721 12 : if (m_oCurCtxt.m_poLayer == nullptr)
2722 0 : return;
2723 :
2724 12 : CPLStripXMLNamespace(psRoot, "swe", true);
2725 12 : CPLXMLNode *psElementType = CPLGetXMLNode(psRoot, "elementType");
2726 12 : if (psElementType == nullptr)
2727 0 : return;
2728 12 : CPLXMLNode *psDataRecord = CPLGetXMLNode(psElementType, "DataRecord");
2729 12 : if (psDataRecord == nullptr)
2730 0 : return;
2731 12 : const char *pszValues = CPLGetXMLValue(psRoot, "values", nullptr);
2732 12 : if (pszValues == nullptr)
2733 0 : return;
2734 12 : CPLXMLNode *psTextEncoding = CPLGetXMLNode(psRoot, "encoding.TextEncoding");
2735 12 : if (psTextEncoding == nullptr)
2736 0 : return;
2737 : // CPLString osDecimalSeparator =
2738 : // CPLGetXMLValue(psTextEncoding, "decimalSeparator", ".");
2739 : CPLString osBlockSeparator =
2740 12 : CPLGetXMLValue(psTextEncoding, "blockSeparator", "");
2741 : CPLString osTokenSeparator =
2742 12 : CPLGetXMLValue(psTextEncoding, "tokenSeparator", "");
2743 12 : if (osBlockSeparator.empty() || osTokenSeparator.empty())
2744 0 : return;
2745 :
2746 12 : if (m_bInitialPass)
2747 : {
2748 6 : CPLString osLayerName;
2749 3 : osLayerName.Printf("DataArray_%d", m_nSWEDataArrayLayerIdx + 1);
2750 : const char *pszElementTypeName =
2751 3 : CPLGetXMLValue(psElementType, "name", nullptr);
2752 3 : if (pszElementTypeName != nullptr)
2753 : {
2754 1 : osLayerName += "_";
2755 1 : osLayerName += pszElementTypeName;
2756 : }
2757 3 : osLayerName = osLayerName.tolower();
2758 6 : auto poLayer = std::make_unique<OGRGMLASLayer>(osLayerName);
2759 :
2760 : // Register layer in _ogr_layers_metadata
2761 : {
2762 : OGRFeature oLayerDescFeature(
2763 6 : m_poLayersMetadataLayer->GetLayerDefn());
2764 3 : oLayerDescFeature.SetField(szLAYER_NAME, osLayerName);
2765 3 : oLayerDescFeature.SetField(szLAYER_CATEGORY, szSWE_DATA_ARRAY);
2766 :
2767 3 : CPLString osFieldName(szPARENT_PREFIX);
2768 : osFieldName +=
2769 3 : m_oCurCtxt.m_poLayer->GetLayerDefn()
2770 3 : ->GetFieldDefn(m_oCurCtxt.m_poLayer->GetIDFieldIdx())
2771 3 : ->GetNameRef();
2772 3 : oLayerDescFeature.SetField(szLAYER_PARENT_PKID_NAME,
2773 : osFieldName.c_str());
2774 3 : CPL_IGNORE_RET_VAL(
2775 3 : m_poLayersMetadataLayer->CreateFeature(&oLayerDescFeature));
2776 : }
2777 :
2778 : // Register layer relationship in _ogr_layer_relationships
2779 : {
2780 : OGRFeature oRelationshipsFeature(
2781 3 : m_poRelationshipsLayer->GetLayerDefn());
2782 3 : oRelationshipsFeature.SetField(szPARENT_LAYER,
2783 3 : m_oCurCtxt.m_poLayer->GetName());
2784 3 : oRelationshipsFeature.SetField(
2785 : szPARENT_PKID,
2786 3 : m_oCurCtxt.m_poLayer->GetLayerDefn()
2787 3 : ->GetFieldDefn(m_oCurCtxt.m_poLayer->GetIDFieldIdx())
2788 : ->GetNameRef());
2789 3 : if (!m_osSWEDataArrayParentField.empty())
2790 : {
2791 3 : oRelationshipsFeature.SetField(szPARENT_ELEMENT_NAME,
2792 : m_osSWEDataArrayParentField);
2793 : }
2794 3 : oRelationshipsFeature.SetField(szCHILD_LAYER, osLayerName);
2795 3 : CPL_IGNORE_RET_VAL(
2796 3 : m_poRelationshipsLayer->CreateFeature(&oRelationshipsFeature));
2797 : }
2798 :
2799 3 : poLayer->ProcessDataRecordOfDataArrayCreateFields(
2800 : m_oCurCtxt.m_poLayer, psDataRecord, m_poFieldsMetadataLayer);
2801 3 : m_apoSWEDataArrayLayersOwned.emplace_back(std::move(poLayer));
2802 : }
2803 : else
2804 : {
2805 9 : CPLAssert(m_nSWEDataArrayLayerIdx <
2806 : static_cast<int>(m_apoSWEDataArrayLayersRef.size()));
2807 : OGRGMLASLayer *poLayer =
2808 9 : m_apoSWEDataArrayLayersRef[m_nSWEDataArrayLayerIdx];
2809 : // -1 because first field is parent id
2810 9 : const int nFieldCount = poLayer->GetLayerDefn()->GetFieldCount() - 1;
2811 9 : int nFID = 1;
2812 9 : int iField = 0;
2813 9 : const size_t nLen = strlen(pszValues);
2814 9 : std::unique_ptr<OGRFeature> poFeature;
2815 9 : const bool bSameSep = (osTokenSeparator == osBlockSeparator);
2816 9 : size_t nLastValid = SkipSpace(pszValues, 0);
2817 9 : size_t i = nLastValid;
2818 645 : while (i < nLen)
2819 : {
2820 636 : if (poFeature == nullptr)
2821 : {
2822 : poFeature =
2823 15 : std::make_unique<OGRFeature>(poLayer->GetLayerDefn());
2824 15 : poFeature->SetFID(nFID);
2825 30 : poFeature->SetField(0,
2826 15 : m_oCurCtxt.m_poFeature->GetFieldAsString(
2827 15 : m_oCurCtxt.m_poLayer->GetIDFieldIdx()));
2828 15 : nFID++;
2829 15 : iField = 0;
2830 : }
2831 636 : if (strncmp(pszValues + i, osTokenSeparator,
2832 636 : osTokenSeparator.size()) == 0)
2833 : {
2834 54 : if (bSameSep && iField == nFieldCount)
2835 : {
2836 3 : PushFeatureReady(std::move(poFeature), poLayer);
2837 : poFeature =
2838 3 : std::make_unique<OGRFeature>(poLayer->GetLayerDefn());
2839 3 : poFeature->SetFID(nFID);
2840 6 : poFeature->SetField(
2841 3 : 0, m_oCurCtxt.m_poFeature->GetFieldAsString(
2842 3 : m_oCurCtxt.m_poLayer->GetIDFieldIdx()));
2843 3 : nFID++;
2844 3 : iField = 0;
2845 : }
2846 :
2847 54 : if (iField < nFieldCount)
2848 : {
2849 51 : CPLString osValue(pszValues + nLastValid, i - nLastValid);
2850 : // +1 because first field is parent id
2851 51 : SetSWEValue(poFeature.get(), iField + 1, osValue);
2852 51 : iField++;
2853 : }
2854 54 : nLastValid = i + osTokenSeparator.size();
2855 54 : nLastValid = SkipSpace(pszValues, nLastValid);
2856 54 : i = nLastValid;
2857 : }
2858 582 : else if (strncmp(pszValues + i, osBlockSeparator,
2859 582 : osBlockSeparator.size()) == 0)
2860 : {
2861 9 : if (iField < nFieldCount)
2862 : {
2863 6 : CPLString osValue(pszValues + nLastValid, i - nLastValid);
2864 : // +1 because first field is parent id
2865 6 : SetSWEValue(poFeature.get(), iField + 1, osValue);
2866 6 : iField++;
2867 : }
2868 9 : PushFeatureReady(std::move(poFeature), poLayer);
2869 9 : poFeature.reset();
2870 9 : nLastValid = i + osBlockSeparator.size();
2871 9 : nLastValid = SkipSpace(pszValues, nLastValid);
2872 9 : i = nLastValid;
2873 : }
2874 : else
2875 : {
2876 573 : i++;
2877 : }
2878 : }
2879 : // cppcheck-suppress accessMoved
2880 9 : if (poFeature)
2881 : {
2882 6 : if (iField < nFieldCount)
2883 : {
2884 12 : CPLString osValue(pszValues + nLastValid, nLen - nLastValid);
2885 : // +1 because first field is parent id
2886 6 : SetSWEValue(poFeature.get(), iField + 1, osValue);
2887 : // iField ++;
2888 : }
2889 6 : PushFeatureReady(std::move(poFeature), poLayer);
2890 : }
2891 : }
2892 12 : m_nSWEDataArrayLayerIdx++;
2893 : }
2894 :
2895 : /************************************************************************/
2896 : /* ProcessSWEDataRecord() */
2897 : /************************************************************************/
2898 :
2899 5 : void GMLASReader::ProcessSWEDataRecord(CPLXMLNode *psRoot)
2900 : {
2901 5 : CPLStripXMLNamespace(psRoot, "swe", true);
2902 5 : if (m_bInitialPass)
2903 : {
2904 : // Collect existing live features of this layer, so that we can
2905 : // patch them
2906 8 : std::vector<OGRFeature *> apoFeatures;
2907 4 : apoFeatures.push_back(m_oCurCtxt.m_poFeature);
2908 8 : for (auto &feature : m_aoFeaturesReady)
2909 : {
2910 4 : if (feature.second == m_oCurCtxt.m_poLayer)
2911 0 : apoFeatures.push_back(feature.first.get());
2912 : }
2913 4 : m_oCurCtxt.m_poLayer->ProcessDataRecordCreateFields(
2914 : psRoot, apoFeatures, m_poFieldsMetadataLayer);
2915 : }
2916 : else
2917 : {
2918 1 : m_oCurCtxt.m_poLayer->ProcessDataRecordFillFeature(
2919 : psRoot, m_oCurCtxt.m_poFeature);
2920 : }
2921 5 : }
2922 :
2923 : /************************************************************************/
2924 : /* GMLASGetSRSName() */
2925 : /************************************************************************/
2926 :
2927 420 : static const char *GMLASGetSRSName(CPLXMLNode *psNode)
2928 : {
2929 420 : const char *pszSRSName = CPLGetXMLValue(psNode, szSRS_NAME, nullptr);
2930 420 : if (pszSRSName == nullptr)
2931 : {
2932 : // Case of a gml:Point where the srsName is on the gml:pos
2933 340 : pszSRSName = CPLGetXMLValue(psNode, "gml:pos.srsName", nullptr);
2934 : }
2935 420 : return pszSRSName;
2936 : }
2937 :
2938 : /************************************************************************/
2939 : /* AddMissingSRSDimension() */
2940 : /************************************************************************/
2941 :
2942 1 : static void AddMissingSRSDimension(CPLXMLNode *psRoot, int nDefaultSrsDimension)
2943 : {
2944 3 : for (CPLXMLNode *psIter = psRoot->psChild; psIter; psIter = psIter->psNext)
2945 : {
2946 2 : if (psIter->eType == CXT_Element)
2947 : {
2948 1 : if (CPLGetXMLValue(psIter, "srsDimension", nullptr) == nullptr)
2949 : {
2950 1 : if (strcmp(psIter->pszValue, "gml:posList") == 0)
2951 : {
2952 1 : CPLAddXMLAttributeAndValue(
2953 : psIter, "srsDimension",
2954 : CPLSPrintf("%d", nDefaultSrsDimension));
2955 : }
2956 : else
2957 : {
2958 0 : AddMissingSRSDimension(psIter, nDefaultSrsDimension);
2959 : }
2960 : }
2961 : }
2962 : }
2963 1 : }
2964 :
2965 : /************************************************************************/
2966 : /* ProcessGeometry() */
2967 : /************************************************************************/
2968 :
2969 420 : void GMLASReader::ProcessGeometry(CPLXMLNode *psRoot)
2970 : {
2971 : OGRGeomFieldDefn *poGeomFieldDefn =
2972 420 : m_oCurCtxt.m_poFeature->GetGeomFieldDefnRef(m_nCurGeomFieldIdx);
2973 :
2974 420 : if (m_bInitialPass)
2975 : {
2976 228 : const char *pszSRSName = GMLASGetSRSName(psRoot);
2977 228 : if (pszSRSName != nullptr)
2978 : {
2979 : // If we are doing a first pass, store the SRS of the geometry
2980 : // column
2981 100 : if (!m_oSetGeomFieldsWithUnknownSRS.empty() &&
2982 50 : m_oSetGeomFieldsWithUnknownSRS.find(poGeomFieldDefn) !=
2983 100 : m_oSetGeomFieldsWithUnknownSRS.end())
2984 : {
2985 42 : OGRSpatialReference *poSRS = new OGRSpatialReference();
2986 42 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2987 :
2988 42 : if (poSRS->SetFromUserInput(
2989 : pszSRSName,
2990 : OGRSpatialReference::
2991 42 : SET_FROM_USER_INPUT_LIMITATIONS_get()) ==
2992 : OGRERR_NONE)
2993 : {
2994 42 : m_oMapGeomFieldDefnToSRSName[poGeomFieldDefn] = pszSRSName;
2995 42 : poGeomFieldDefn->SetSpatialRef(poSRS);
2996 : }
2997 42 : poSRS->Release();
2998 42 : m_oSetGeomFieldsWithUnknownSRS.erase(poGeomFieldDefn);
2999 : }
3000 : }
3001 228 : return;
3002 : }
3003 :
3004 193 : if (m_nDefaultSrsDimension != 0 &&
3005 1 : CPLGetXMLValue(psRoot, "srsDimension", nullptr) == nullptr)
3006 : {
3007 1 : AddMissingSRSDimension(psRoot, m_nDefaultSrsDimension);
3008 : }
3009 :
3010 : #ifdef DEBUG_VERBOSE
3011 : {
3012 : char *pszXML = CPLSerializeXMLTree(psRoot);
3013 : CPLDebug("GML", "geometry = %s", pszXML);
3014 : CPLFree(pszXML);
3015 : }
3016 : #endif
3017 :
3018 : auto poGeom = std::unique_ptr<OGRGeometry>(
3019 384 : OGRGeometry::FromHandle(OGR_G_CreateFromGMLTree(psRoot)));
3020 192 : if (poGeom != nullptr)
3021 : {
3022 192 : const char *pszSRSName = GMLASGetSRSName(psRoot);
3023 :
3024 192 : bool bSwapXY = false;
3025 192 : if (pszSRSName != nullptr)
3026 : {
3027 : // Check if the srsName indicates unusual axis order,
3028 : // and if so swap x and y coordinates.
3029 38 : const auto oIter = m_oMapSRSNameToInvertedAxis.find(pszSRSName);
3030 38 : if (oIter == m_oMapSRSNameToInvertedAxis.end())
3031 : {
3032 38 : OGRSpatialReference oSRS;
3033 38 : oSRS.SetFromUserInput(
3034 : pszSRSName,
3035 : OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get());
3036 66 : bSwapXY = !STARTS_WITH_CI(pszSRSName, "EPSG:") &&
3037 28 : (CPL_TO_BOOL(oSRS.EPSGTreatsAsLatLong()) ||
3038 2 : CPL_TO_BOOL(oSRS.EPSGTreatsAsNorthingEasting()));
3039 38 : m_oMapSRSNameToInvertedAxis[pszSRSName] = bSwapXY;
3040 : }
3041 : else
3042 : {
3043 0 : bSwapXY = oIter->second;
3044 : }
3045 : }
3046 192 : if ((bSwapXY && m_eSwapCoordinates == GMLAS_SWAP_AUTO) ||
3047 172 : m_eSwapCoordinates == GMLAS_SWAP_YES)
3048 : {
3049 36 : poGeom->swapXY();
3050 : }
3051 :
3052 : // Do we need to do reprojection ?
3053 230 : if (pszSRSName != nullptr &&
3054 230 : poGeomFieldDefn->GetSpatialRef() != nullptr &&
3055 38 : m_oMapGeomFieldDefnToSRSName[poGeomFieldDefn] != pszSRSName)
3056 : {
3057 2 : bool bReprojectionOK = false;
3058 4 : OGRSpatialReference oSRS;
3059 2 : if (oSRS.SetFromUserInput(
3060 : pszSRSName,
3061 : OGRSpatialReference::
3062 2 : SET_FROM_USER_INPUT_LIMITATIONS_get()) == OGRERR_NONE)
3063 : {
3064 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
3065 : OGRCreateCoordinateTransformation(
3066 2 : &oSRS, poGeomFieldDefn->GetSpatialRef()));
3067 1 : if (poCT != nullptr)
3068 : {
3069 1 : bReprojectionOK =
3070 1 : (poGeom->transform(poCT.get()) == OGRERR_NONE);
3071 : }
3072 : }
3073 2 : if (!bReprojectionOK)
3074 : {
3075 1 : CPLError(CE_Warning, CPLE_AppDefined,
3076 : "Reprojection from %s to %s failed", pszSRSName,
3077 1 : m_oMapGeomFieldDefnToSRSName[poGeomFieldDefn].c_str());
3078 1 : poGeom.reset();
3079 : }
3080 : #ifdef DEBUG_VERBOSE
3081 : else
3082 : {
3083 : CPLDebug("GMLAS", "Reprojected geometry from %s to %s",
3084 : pszSRSName,
3085 : m_oMapGeomFieldDefnToSRSName[poGeomFieldDefn].c_str());
3086 : }
3087 : #endif
3088 : }
3089 :
3090 192 : if (poGeom != nullptr)
3091 : {
3092 : // Deal with possibly repeated geometries by building
3093 : // a geometry collection. We could also create a
3094 : // nested table, but that would probably be less
3095 : // convenient to use.
3096 : auto poPrevGeom = std::unique_ptr<OGRGeometry>(
3097 382 : m_oCurCtxt.m_poFeature->StealGeometry(m_nCurGeomFieldIdx));
3098 191 : if (poPrevGeom != nullptr)
3099 : {
3100 25 : if (poPrevGeom->getGeometryType() == wkbGeometryCollection)
3101 : {
3102 24 : poPrevGeom->toGeometryCollection()->addGeometryDirectly(
3103 12 : poGeom.release());
3104 12 : poGeom = std::move(poPrevGeom);
3105 : }
3106 : else
3107 : {
3108 26 : auto poGC = std::make_unique<OGRGeometryCollection>();
3109 13 : poGC->addGeometryDirectly(poPrevGeom.release());
3110 13 : poGC->addGeometryDirectly(poGeom.release());
3111 13 : poGeom = std::move(poGC);
3112 : }
3113 : }
3114 191 : poGeom->assignSpatialReference(poGeomFieldDefn->GetSpatialRef());
3115 191 : m_oCurCtxt.m_poFeature->SetGeomFieldDirectly(m_nCurGeomFieldIdx,
3116 : poGeom.release());
3117 : }
3118 : }
3119 : else
3120 : {
3121 0 : char *pszXML = CPLSerializeXMLTree(psRoot);
3122 0 : CPLDebug("GMLAS", "Non-recognized geometry: %s", pszXML);
3123 0 : CPLFree(pszXML);
3124 : }
3125 : }
3126 :
3127 : /************************************************************************/
3128 : /* characters() */
3129 : /************************************************************************/
3130 :
3131 290115 : void GMLASReader::characters(const XMLCh *const chars, const XMLSize_t length)
3132 : {
3133 290115 : bool bTextMemberUpdated = false;
3134 5693 : if (((m_bIsXMLBlob && m_nCurGeomFieldIdx >= 0 && !m_bInitialPass) ||
3135 296265 : m_nSWEDataArrayLevel >= 0 || m_nSWEDataRecordLevel >= 0) &&
3136 : // Check the stack is not empty in case of space chars before the
3137 : // starting node
3138 711 : !m_apsXMLNodeStack.empty())
3139 : {
3140 699 : bTextMemberUpdated = true;
3141 : const CPLString &osText(
3142 699 : transcode(chars, m_osText, static_cast<int>(length)));
3143 :
3144 : // Merge content in current text node if it exists
3145 699 : NodeLastChild &sNodeLastChild = m_apsXMLNodeStack.back();
3146 699 : if (sNodeLastChild.psLastChild != nullptr &&
3147 374 : sNodeLastChild.psLastChild->eType == CXT_Text)
3148 : {
3149 20 : CPLXMLNode *psNode = sNodeLastChild.psLastChild;
3150 20 : const size_t nOldLength = strlen(psNode->pszValue);
3151 : char *pszNewValue = reinterpret_cast<char *>(
3152 20 : VSIRealloc(psNode->pszValue, nOldLength + osText.size() + 1));
3153 20 : if (pszNewValue)
3154 : {
3155 20 : psNode->pszValue = pszNewValue;
3156 20 : memcpy(pszNewValue + nOldLength, osText.c_str(),
3157 20 : osText.size() + 1);
3158 : }
3159 : else
3160 : {
3161 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
3162 0 : m_bParsingError = true;
3163 20 : }
3164 : }
3165 : // Otherwise create a new text node
3166 : else
3167 : {
3168 : CPLXMLNode *psNode =
3169 679 : reinterpret_cast<CPLXMLNode *>(CPLMalloc(sizeof(CPLXMLNode)));
3170 679 : psNode->eType = CXT_Text;
3171 679 : psNode->pszValue =
3172 679 : reinterpret_cast<char *>(CPLMalloc(osText.size() + 1));
3173 679 : memcpy(psNode->pszValue, osText.c_str(), osText.size() + 1);
3174 679 : psNode->psNext = nullptr;
3175 679 : psNode->psChild = nullptr;
3176 679 : AttachAsLastChild(psNode);
3177 : }
3178 : }
3179 :
3180 290115 : if (!FillTextContent())
3181 : {
3182 90898 : m_osTextContent = "1"; // dummy
3183 90898 : return;
3184 : }
3185 :
3186 199217 : if (m_bIsXMLBlob)
3187 : {
3188 3894 : if (m_nCurFieldIdx >= 0)
3189 : {
3190 : const CPLString &osText(
3191 : bTextMemberUpdated
3192 3894 : ? m_osText
3193 3592 : : transcode(chars, m_osText, static_cast<int>(length)));
3194 :
3195 3894 : char *pszEscaped = CPLEscapeString(
3196 3894 : osText.c_str(), static_cast<int>(osText.size()), CPLES_XML);
3197 : try
3198 : {
3199 3894 : m_osTextContent += pszEscaped;
3200 : }
3201 0 : catch (const std::bad_alloc &)
3202 : {
3203 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
3204 0 : m_bParsingError = true;
3205 : }
3206 3894 : CPLFree(pszEscaped);
3207 : }
3208 : }
3209 : // Make sure to set content only if we are at the expected nesting level
3210 195323 : else if (m_nLevel == m_nCurFieldLevel)
3211 : {
3212 : const CPLString &osText(
3213 100795 : transcode(chars, m_osText, static_cast<int>(length)));
3214 : try
3215 : {
3216 100795 : m_osTextContent += osText;
3217 : }
3218 0 : catch (const std::bad_alloc &)
3219 : {
3220 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
3221 0 : m_bParsingError = true;
3222 : }
3223 : }
3224 :
3225 199217 : if (m_osTextContent.size() > m_nMaxContentSize)
3226 : {
3227 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
3228 : "Too much data in a single element");
3229 0 : m_bParsingError = true;
3230 : }
3231 : }
3232 :
3233 : /************************************************************************/
3234 : /* GetNextFeature() */
3235 : /************************************************************************/
3236 :
3237 5403 : OGRFeature *GMLASReader::GetNextFeature(OGRGMLASLayer **ppoBelongingLayer,
3238 : GDALProgressFunc pfnProgress,
3239 : void *pProgressData)
3240 : {
3241 5403 : while (!m_aoFeaturesReady.empty())
3242 : {
3243 3 : auto poFeatureReady = std::move(m_aoFeaturesReady.front().first);
3244 3 : OGRGMLASLayer *poFeatureReadyLayer = m_aoFeaturesReady.front().second;
3245 3 : m_aoFeaturesReady.erase(m_aoFeaturesReady.begin());
3246 :
3247 3 : if (m_poLayerOfInterest == nullptr ||
3248 3 : m_poLayerOfInterest == poFeatureReadyLayer)
3249 : {
3250 3 : if (ppoBelongingLayer)
3251 0 : *ppoBelongingLayer = poFeatureReadyLayer;
3252 3 : return poFeatureReady.release();
3253 : }
3254 : }
3255 :
3256 5400 : if (m_bEOF)
3257 0 : return nullptr;
3258 :
3259 : try
3260 : {
3261 5400 : if (m_bFirstIteration)
3262 : {
3263 1229 : m_bFirstIteration = false;
3264 2458 : if (!m_poSAXReader->parseFirst(*(m_GMLInputSource.get()),
3265 1229 : m_oToFill))
3266 : {
3267 0 : m_bParsingError = true;
3268 0 : m_bEOF = true;
3269 0 : return nullptr;
3270 : }
3271 : }
3272 :
3273 5400 : vsi_l_offset nLastOffset = m_fp->Tell();
3274 617550 : while (m_poSAXReader->parseNext(m_oToFill))
3275 : {
3276 616623 : if (pfnProgress && m_fp->Tell() - nLastOffset > 100 * 1024)
3277 : {
3278 0 : nLastOffset = m_fp->Tell();
3279 0 : double dfPct = -1;
3280 0 : if (m_nFileSize)
3281 0 : dfPct = 1.0 * nLastOffset / m_nFileSize;
3282 0 : if (!pfnProgress(dfPct, "", pProgressData))
3283 : {
3284 0 : m_bInterrupted = true;
3285 0 : break;
3286 : }
3287 : }
3288 616623 : if (m_bParsingError)
3289 0 : break;
3290 :
3291 668706 : while (!m_aoFeaturesReady.empty())
3292 : {
3293 : auto poFeatureReady =
3294 56556 : std::move(m_aoFeaturesReady.front().first);
3295 : OGRGMLASLayer *poFeatureReadyLayer =
3296 56556 : m_aoFeaturesReady.front().second;
3297 56556 : m_aoFeaturesReady.erase(m_aoFeaturesReady.begin());
3298 :
3299 56556 : if (m_poLayerOfInterest == nullptr ||
3300 54122 : m_poLayerOfInterest == poFeatureReadyLayer)
3301 : {
3302 4473 : if (ppoBelongingLayer)
3303 2434 : *ppoBelongingLayer = poFeatureReadyLayer;
3304 :
3305 4473 : if (pfnProgress)
3306 : {
3307 0 : nLastOffset = m_fp->Tell();
3308 0 : double dfPct = -1;
3309 0 : if (m_nFileSize)
3310 0 : dfPct = 1.0 * nLastOffset / m_nFileSize;
3311 0 : if (!pfnProgress(dfPct, "", pProgressData))
3312 : {
3313 0 : m_bInterrupted = true;
3314 0 : m_bEOF = true;
3315 0 : return nullptr;
3316 : }
3317 : }
3318 :
3319 4473 : return poFeatureReady.release();
3320 : }
3321 : }
3322 : }
3323 :
3324 925 : m_bEOF = true;
3325 : }
3326 0 : catch (const XMLException &toCatch)
3327 : {
3328 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
3329 0 : transcode(toCatch.getMessage()).c_str());
3330 0 : m_bParsingError = true;
3331 0 : m_bEOF = true;
3332 : }
3333 2 : catch (const SAXException &toCatch)
3334 : {
3335 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s",
3336 4 : transcode(toCatch.getMessage()).c_str());
3337 2 : m_bParsingError = true;
3338 2 : m_bEOF = true;
3339 : }
3340 :
3341 927 : return nullptr;
3342 : }
3343 :
3344 : /************************************************************************/
3345 : /* RunFirstPass() */
3346 : /************************************************************************/
3347 :
3348 107 : bool GMLASReader::RunFirstPass(
3349 : GDALProgressFunc pfnProgress, void *pProgressData, bool bRemoveUnusedLayers,
3350 : bool bRemoveUnusedFields, bool bProcessSWEDataArray,
3351 : OGRLayer *poFieldsMetadataLayer, OGRLayer *poLayersMetadataLayer,
3352 : OGRLayer *poRelationshipsLayer, std::set<CPLString> &aoSetRemovedLayerNames)
3353 : {
3354 107 : m_bInitialPass = true;
3355 107 : m_bProcessSWEDataArray = bProcessSWEDataArray;
3356 107 : m_poFieldsMetadataLayer = poFieldsMetadataLayer;
3357 107 : m_poLayersMetadataLayer = poLayersMetadataLayer;
3358 107 : m_poRelationshipsLayer = poRelationshipsLayer;
3359 :
3360 : // Store in m_oSetGeomFieldsWithUnknownSRS the geometry fields
3361 214 : std::set<OGRGMLASLayer *> oSetUnreferencedLayers;
3362 107 : std::map<OGRGMLASLayer *, std::set<CPLString>> oMapUnusedFields;
3363 14149 : for (auto &poLayer : *m_apoLayers)
3364 : {
3365 14042 : OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
3366 14042 : oSetUnreferencedLayers.insert(poLayer.get());
3367 14259 : for (int j = 0; j < poFDefn->GetGeomFieldCount(); j++)
3368 : {
3369 217 : m_oSetGeomFieldsWithUnknownSRS.insert(poFDefn->GetGeomFieldDefn(j));
3370 : }
3371 213724 : for (int j = 0; j < poFDefn->GetFieldCount(); j++)
3372 : {
3373 199682 : oMapUnusedFields[poLayer.get()].insert(
3374 199682 : poFDefn->GetFieldDefn(j)->GetNameRef());
3375 : }
3376 : }
3377 :
3378 107 : CPLDebug("GMLAS", "Start of first pass");
3379 :
3380 : // Do we need to do a full scan of the file ?
3381 : const bool bHasURLSpecificRules =
3382 107 : !m_oXLinkResolver.GetConf().m_aoURLSpecificRules.empty();
3383 : const bool bDoFullPass =
3384 57 : (m_bValidate || bRemoveUnusedLayers || bRemoveUnusedFields ||
3385 215 : bHasURLSpecificRules || bProcessSWEDataArray ||
3386 158 : m_oXLinkResolver.GetConf().m_bResolveInternalXLinks);
3387 :
3388 : // Loop on features until we have determined the SRS of all geometry
3389 : // columns, or potentially on the whole file for the above reasons
3390 : OGRGMLASLayer *poLayerFeature;
3391 1761 : while (bDoFullPass || !m_oSetGeomFieldsWithUnknownSRS.empty())
3392 : {
3393 : auto poFeature = std::unique_ptr<OGRFeature>(
3394 1761 : GetNextFeature(&poLayerFeature, pfnProgress, pProgressData));
3395 1761 : if (!poFeature)
3396 107 : break;
3397 1654 : if (bRemoveUnusedLayers)
3398 1 : oSetUnreferencedLayers.erase(poLayerFeature);
3399 1654 : if (bRemoveUnusedFields)
3400 : {
3401 : std::set<CPLString> &oSetUnusedFields =
3402 1 : oMapUnusedFields[poLayerFeature];
3403 1 : OGRFeatureDefn *poFDefn = poLayerFeature->GetLayerDefn();
3404 1 : int nFieldCount = poFDefn->GetFieldCount();
3405 9 : for (int j = 0; j < nFieldCount; j++)
3406 : {
3407 8 : if (poFeature->IsFieldSetAndNotNull(j))
3408 4 : oSetUnusedFields.erase(
3409 4 : poFDefn->GetFieldDefn(j)->GetNameRef());
3410 : }
3411 : }
3412 : }
3413 :
3414 107 : CPLDebug("GMLAS", "End of first pass");
3415 :
3416 107 : ProcessInternalXLinkFirstPass(bRemoveUnusedFields, oMapUnusedFields);
3417 :
3418 107 : if (bRemoveUnusedLayers)
3419 : {
3420 2 : std::vector<std::unique_ptr<OGRGMLASLayer>> apoNewLayers;
3421 5 : for (auto &poLayer : *m_apoLayers)
3422 : {
3423 4 : if (oSetUnreferencedLayers.find(poLayer.get()) ==
3424 8 : oSetUnreferencedLayers.end())
3425 : {
3426 1 : apoNewLayers.emplace_back(std::move(poLayer));
3427 : }
3428 : else
3429 : {
3430 3 : aoSetRemovedLayerNames.insert(poLayer->GetName());
3431 : }
3432 : }
3433 1 : *m_apoLayers = std::move(apoNewLayers);
3434 : }
3435 107 : if (bRemoveUnusedFields)
3436 : {
3437 2 : for (auto &poLayer : *m_apoLayers)
3438 : {
3439 5 : for (const auto &oIter : oMapUnusedFields[poLayer.get()])
3440 : {
3441 8 : poLayer->RemoveField(
3442 4 : poLayer->GetLayerDefn()->GetFieldIndex(oIter));
3443 : }
3444 :
3445 : // We need to run this again since we may have delete the
3446 : // element that holds attributes, like in
3447 : // <foo xsi:nil="true" nilReason="unknown"/> where foo will be
3448 : // eliminated, but foo_nilReason kept.
3449 1 : poLayer->CreateCompoundFoldedMappings();
3450 : }
3451 : }
3452 :
3453 : // Add fields coming from matching URL specific rules
3454 107 : if (bHasURLSpecificRules)
3455 : {
3456 3 : CreateFieldsForURLSpecificRules();
3457 : }
3458 :
3459 : // Clear the set even if we didn't manage to determine all the SRS
3460 107 : m_oSetGeomFieldsWithUnknownSRS.clear();
3461 :
3462 214 : return !m_bInterrupted;
3463 : }
3464 :
3465 : /************************************************************************/
3466 : /* ProcessInternalXLinkFirstPass() */
3467 : /************************************************************************/
3468 :
3469 107 : void GMLASReader::ProcessInternalXLinkFirstPass(
3470 : bool bRemoveUnusedFields,
3471 : std::map<OGRGMLASLayer *, std::set<CPLString>> &oMapUnusedFields)
3472 : {
3473 113 : for (const auto &oIter : m_oMapFieldXPathToLinkValue)
3474 : {
3475 6 : OGRGMLASLayer *poReferringLayer = oIter.first.first;
3476 6 : const CPLString &osReferringField = oIter.first.second;
3477 6 : const std::vector<CPLString> &aosLinks = oIter.second;
3478 12 : std::set<OGRGMLASLayer *> oSetTargetLayers;
3479 15 : for (size_t i = 0; i < aosLinks.size(); i++)
3480 : {
3481 9 : const auto oIter2 = m_oMapElementIdToLayer.find(aosLinks[i]);
3482 9 : if (oIter2 == m_oMapElementIdToLayer.end())
3483 : {
3484 4 : CPLError(CE_Warning, CPLE_AppDefined,
3485 : "%s:%s = '#%s' has no corresponding target "
3486 : "element in this document",
3487 : poReferringLayer->GetName(), osReferringField.c_str(),
3488 4 : aosLinks[i].c_str());
3489 : }
3490 5 : else if (oSetTargetLayers.find(oIter2->second) ==
3491 10 : oSetTargetLayers.end())
3492 : {
3493 4 : OGRGMLASLayer *poTargetLayer = oIter2->second;
3494 4 : oSetTargetLayers.insert(poTargetLayer);
3495 : CPLString osLinkFieldName =
3496 : poReferringLayer->CreateLinkForAttrToOtherLayer(
3497 : osReferringField,
3498 8 : poTargetLayer->GetFeatureClass().GetXPath());
3499 4 : if (bRemoveUnusedFields)
3500 : {
3501 0 : oMapUnusedFields[poReferringLayer].erase(osLinkFieldName);
3502 : }
3503 : }
3504 : }
3505 : }
3506 107 : }
3507 :
3508 : /************************************************************************/
3509 : /* CreateFieldsForURLSpecificRules() */
3510 : /************************************************************************/
3511 :
3512 3 : void GMLASReader::CreateFieldsForURLSpecificRules()
3513 : {
3514 6 : for (const auto &oIter : m_oMapXLinkFields)
3515 : {
3516 3 : OGRGMLASLayer *poLayer = oIter.first;
3517 3 : const auto &oMap2 = oIter.second;
3518 8 : for (const auto &oIter2 : oMap2)
3519 : {
3520 5 : const CPLString &osFieldXPath(oIter2.first);
3521 : // Note that CreateFieldsForURLSpecificRule() running on a previous
3522 : // iteration will have inserted new OGR fields, so we really need
3523 : // to compute that index now.
3524 : const int nFieldIdx =
3525 5 : poLayer->GetOGRFieldIndexFromXPath(osFieldXPath);
3526 5 : CPLAssert(nFieldIdx >= 0);
3527 5 : int nInsertFieldIdx = nFieldIdx + 1;
3528 5 : const auto &oSetRuleIndex = oIter2.second;
3529 12 : for (const auto &nRuleIdx : oSetRuleIndex)
3530 : {
3531 : const GMLASXLinkResolutionConf::URLSpecificResolution &oRule =
3532 7 : m_oXLinkResolver.GetConf().m_aoURLSpecificRules[nRuleIdx];
3533 7 : CreateFieldsForURLSpecificRule(poLayer, nFieldIdx, osFieldXPath,
3534 : nInsertFieldIdx, oRule);
3535 : }
3536 : }
3537 : }
3538 3 : }
3539 :
3540 : /************************************************************************/
3541 : /* CreateFieldsForURLSpecificRule() */
3542 : /************************************************************************/
3543 :
3544 7 : void GMLASReader::CreateFieldsForURLSpecificRule(
3545 : OGRGMLASLayer *poLayer, int nFieldIdx, const CPLString &osFieldXPath,
3546 : int &nInsertFieldIdx,
3547 : const GMLASXLinkResolutionConf::URLSpecificResolution &oRule)
3548 : {
3549 7 : if (oRule.m_eResolutionMode == GMLASXLinkResolutionConf::RawContent)
3550 : {
3551 : const CPLString osRawContentXPath(
3552 : GMLASField::MakeXLinkRawContentFieldXPathFromXLinkHrefXPath(
3553 2 : osFieldXPath));
3554 1 : if (poLayer->GetOGRFieldIndexFromXPath(osRawContentXPath) < 0)
3555 : {
3556 : const CPLString osOGRFieldName(
3557 2 : poLayer->GetLayerDefn()->GetFieldDefn(nFieldIdx)->GetNameRef());
3558 2 : CPLString osRawContentFieldname(osOGRFieldName);
3559 1 : size_t nPos = osRawContentFieldname.find("_href");
3560 1 : if (nPos != std::string::npos)
3561 1 : osRawContentFieldname.resize(nPos);
3562 1 : osRawContentFieldname += "_rawcontent";
3563 1 : OGRFieldDefn oFieldDefnRaw(osRawContentFieldname, OFTString);
3564 1 : poLayer->InsertNewField(nInsertFieldIdx, oFieldDefnRaw,
3565 : osRawContentXPath);
3566 1 : nInsertFieldIdx++;
3567 : }
3568 : }
3569 6 : else if (oRule.m_eResolutionMode ==
3570 : GMLASXLinkResolutionConf::FieldsFromXPath)
3571 : {
3572 26 : for (size_t i = 0; i < oRule.m_aoFields.size(); ++i)
3573 : {
3574 : const CPLString osDerivedFieldXPath(
3575 : GMLASField::MakeXLinkDerivedFieldXPathFromXLinkHrefXPath(
3576 40 : osFieldXPath, oRule.m_aoFields[i].m_osName));
3577 20 : if (poLayer->GetOGRFieldIndexFromXPath(osDerivedFieldXPath) < 0)
3578 : {
3579 18 : const CPLString osOGRFieldName(poLayer->GetLayerDefn()
3580 18 : ->GetFieldDefn(nFieldIdx)
3581 36 : ->GetNameRef());
3582 36 : CPLString osNewFieldname(osOGRFieldName);
3583 18 : size_t nPos = osNewFieldname.find("_href");
3584 18 : if (nPos != std::string::npos)
3585 18 : osNewFieldname.resize(nPos);
3586 18 : osNewFieldname += "_" + oRule.m_aoFields[i].m_osName;
3587 :
3588 18 : OGRFieldType eType = OFTString;
3589 18 : const CPLString &osType(oRule.m_aoFields[i].m_osType);
3590 18 : if (osType == "integer")
3591 6 : eType = OFTInteger;
3592 12 : else if (osType == "long")
3593 2 : eType = OFTInteger64;
3594 10 : else if (osType == "double")
3595 2 : eType = OFTReal;
3596 8 : else if (osType == "dateTime")
3597 2 : eType = OFTDateTime;
3598 :
3599 18 : OGRFieldDefn oFieldDefnRaw(osNewFieldname, eType);
3600 18 : poLayer->InsertNewField(nInsertFieldIdx, oFieldDefnRaw,
3601 : osDerivedFieldXPath);
3602 18 : nInsertFieldIdx++;
3603 : }
3604 : }
3605 : }
3606 7 : }
|