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