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