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