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