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 : #ifndef OGR_GMLAS_INCLUDED
32 : #define OGR_GMLAS_INCLUDED
33 :
34 : #include "xercesc_headers.h"
35 : #include "ogr_xerces.h"
36 :
37 : #include "cpl_vsi_virtual.h"
38 : #include "gdal_priv.h"
39 : #include "ogrsf_frmts.h"
40 :
41 : #include "ogr_gmlas_consts.h"
42 :
43 : #include <list>
44 : #include <set>
45 : #include <map>
46 : #include <vector>
47 :
48 : typedef std::pair<CPLString, CPLString> PairURIFilename;
49 :
50 : typedef enum
51 : {
52 : GMLAS_SWAP_AUTO,
53 : GMLAS_SWAP_YES,
54 : GMLAS_SWAP_NO,
55 : } GMLASSwapCoordinatesEnum;
56 :
57 : GDALDataset *OGRGMLASDriverCreateCopy(const char *pszFilename,
58 : GDALDataset *poSrcDS, int /*bStrict*/,
59 : char **papszOptions,
60 : GDALProgressFunc pfnProgress,
61 : void *pProgressData);
62 :
63 : /************************************************************************/
64 : /* IGMLASInputSourceClosing */
65 : /************************************************************************/
66 :
67 : class IGMLASInputSourceClosing
68 : {
69 : public:
70 232 : virtual ~IGMLASInputSourceClosing()
71 232 : {
72 232 : }
73 :
74 : virtual void notifyClosing(const CPLString &osFilename) = 0;
75 : };
76 :
77 : /************************************************************************/
78 : /* GMLASResourceCache */
79 : /************************************************************************/
80 :
81 : class GMLASResourceCache
82 : {
83 : protected:
84 : bool m_bHasCheckedCacheDirectory = false;
85 : std::string m_osCacheDirectory{};
86 : bool m_bRefresh = false;
87 : bool m_bAllowDownload = false;
88 : std::set<std::string> m_aoSetRefreshedFiles{};
89 :
90 : static bool
91 : RecursivelyCreateDirectoryIfNeeded(const std::string &osDirname);
92 : bool RecursivelyCreateDirectoryIfNeeded();
93 :
94 : std::string GetCachedFilename(const std::string &osResource);
95 :
96 : public:
97 : void SetCacheDirectory(const std::string &osCacheDirectory);
98 :
99 356 : void SetRefreshMode(bool bRefresh)
100 : {
101 356 : m_bRefresh = bRefresh;
102 356 : }
103 :
104 185 : void SetAllowDownload(bool bVal)
105 : {
106 185 : m_bAllowDownload = bVal;
107 185 : }
108 : };
109 :
110 : /************************************************************************/
111 : /* GMLASXSDCache */
112 : /************************************************************************/
113 :
114 : class GMLASXSDCache final : public GMLASResourceCache
115 : {
116 : bool CacheAllGML321();
117 : bool CacheAllISO20070417();
118 :
119 : public:
120 : VSILFILE *Open(const std::string &osResource, const std::string &osBasePath,
121 : std::string &osOutFilename);
122 : };
123 :
124 : /************************************************************************/
125 : /* GMLASBaseEntityResolver */
126 : /************************************************************************/
127 :
128 : class GMLASBaseEntityResolver : public EntityResolver,
129 : public IGMLASInputSourceClosing
130 : {
131 : protected:
132 : std::vector<CPLString> m_aosPathStack{};
133 : GMLASXSDCache &m_oCache;
134 : CPLString m_osGMLVersionFound{};
135 : std::set<CPLString> m_oSetSchemaURLs{};
136 : bool m_bFoundNonOfficialGMLSchemaLocation = false;
137 : bool m_bSubstituteWithOGCSchemaLocation = false;
138 :
139 : public:
140 : GMLASBaseEntityResolver(const CPLString &osBasePath, GMLASXSDCache &oCache);
141 : virtual ~GMLASBaseEntityResolver();
142 :
143 : void SetBasePath(const CPLString &osBasePath);
144 :
145 171 : const CPLString &GetGMLVersionFound() const
146 : {
147 171 : return m_osGMLVersionFound;
148 : }
149 :
150 171 : const std::set<CPLString> &GetSchemaURLS() const
151 : {
152 171 : return m_oSetSchemaURLs;
153 : }
154 :
155 1 : void SetSubstituteWithOGCSchemaLocation(bool b)
156 : {
157 1 : m_bSubstituteWithOGCSchemaLocation = b;
158 1 : }
159 :
160 1 : bool GetFoundNonOfficialGMLSchemaLocation() const
161 : {
162 1 : return m_bFoundNonOfficialGMLSchemaLocation;
163 : }
164 :
165 : virtual void notifyClosing(const CPLString &osFilename) override;
166 : virtual InputSource *resolveEntity(const XMLCh *const publicId,
167 : const XMLCh *const systemId) override;
168 :
169 : virtual void
170 : DoExtraSchemaProcessing(const CPLString &osFilename,
171 : const std::shared_ptr<VSIVirtualHandle> &fp);
172 : };
173 :
174 : /************************************************************************/
175 : /* GMLASInputSource */
176 : /************************************************************************/
177 :
178 : class GMLASInputSource final : public InputSource
179 : {
180 : std::shared_ptr<VSIVirtualHandle> m_fp{};
181 : int m_nCounter = 0;
182 : int *m_pnCounter = nullptr;
183 : CPLString m_osFilename{};
184 : IGMLASInputSourceClosing *m_cbk = nullptr;
185 :
186 : CPL_DISALLOW_COPY_ASSIGN(GMLASInputSource)
187 :
188 : public:
189 : GMLASInputSource(
190 : const char *pszFilename, const std::shared_ptr<VSIVirtualHandle> &fp,
191 : MemoryManager *const manager = XMLPlatformUtils::fgMemoryManager);
192 : virtual ~GMLASInputSource();
193 :
194 : virtual BinInputStream *makeStream() const override;
195 :
196 : void SetClosingCallback(IGMLASInputSourceClosing *cbk);
197 : };
198 :
199 : /************************************************************************/
200 : /* GMLASErrorHandler */
201 : /************************************************************************/
202 :
203 : class GMLASErrorHandler : public ErrorHandler
204 : {
205 : public:
206 2548 : GMLASErrorHandler() = default;
207 :
208 1636 : void SetSchemaFullCheckingEnabled(bool b)
209 : {
210 1636 : m_bSchemaFullChecking = b;
211 1636 : }
212 :
213 1636 : void SetHandleMultipleImportsEnabled(bool b)
214 : {
215 1636 : m_bHandleMultipleImports = b;
216 1636 : }
217 :
218 256 : void SetHideGMLTypeNotFound(bool b)
219 : {
220 256 : m_bHideGMLTypeNotFound = b;
221 256 : }
222 :
223 4 : const std::string &GetGMLTypeNotFoundError() const
224 : {
225 4 : return m_osGMLTypeNotFoundError;
226 : }
227 :
228 254 : bool hasFailed() const
229 : {
230 254 : return m_bFailed;
231 : }
232 :
233 : virtual void warning(const SAXParseException &e) override;
234 : virtual void error(const SAXParseException &e) override;
235 : virtual void fatalError(const SAXParseException &e) override;
236 :
237 2141 : virtual void resetErrors() override
238 : {
239 2141 : m_bFailed = false;
240 2141 : }
241 :
242 : private:
243 : bool m_bFailed = false;
244 : bool m_bSchemaFullChecking = false;
245 : bool m_bHandleMultipleImports = false;
246 : bool m_bHideGMLTypeNotFound = false;
247 : std::string m_osGMLTypeNotFoundError{};
248 :
249 : void handle(const SAXParseException &e, CPLErr eErr);
250 : };
251 :
252 : /************************************************************************/
253 : /* GMLASXLinkResolutionConf */
254 : /************************************************************************/
255 :
256 : class GMLASXLinkResolutionConf
257 : {
258 : public:
259 : /* See data/gmlasconf.xsd for docomentation of the fields */
260 :
261 : typedef enum
262 : {
263 : RawContent,
264 : FieldsFromXPath
265 : } ResolutionMode;
266 :
267 : int m_nTimeOut = 0;
268 :
269 : int m_nMaxFileSize = MAX_FILE_SIZE_DEFAULT;
270 :
271 : int m_nMaxGlobalResolutionTime = 0;
272 :
273 : CPLString m_osProxyServerPort{};
274 :
275 : CPLString m_osProxyUserPassword{};
276 :
277 : CPLString m_osProxyAuth{};
278 :
279 : CPLString m_osCacheDirectory{};
280 :
281 : bool m_bDefaultResolutionEnabled = DEFAULT_RESOLUTION_ENABLED_DEFAULT;
282 :
283 : bool m_bDefaultAllowRemoteDownload = ALLOW_REMOTE_DOWNLOAD_DEFAULT;
284 :
285 : ResolutionMode m_eDefaultResolutionMode = RawContent;
286 :
287 : int m_nDefaultResolutionDepth = 1;
288 :
289 : bool m_bDefaultCacheResults = CACHE_RESULTS_DEFAULT;
290 :
291 : bool m_bResolveInternalXLinks = INTERNAL_XLINK_RESOLUTION_DEFAULT;
292 :
293 : struct URLSpecificResolution
294 : {
295 : CPLString m_osURLPrefix{};
296 :
297 : std::vector<std::pair<CPLString, CPLString>>
298 : m_aosNameValueHTTPHeaders{};
299 :
300 : bool m_bAllowRemoteDownload = false;
301 :
302 : ResolutionMode m_eResolutionMode = RawContent;
303 :
304 : int m_nResolutionDepth = 1;
305 :
306 : bool m_bCacheResults = false;
307 :
308 : struct XPathDerivedField
309 : {
310 : CPLString m_osName{};
311 :
312 : CPLString m_osType{};
313 :
314 : CPLString m_osXPath{};
315 : };
316 :
317 : std::vector<XPathDerivedField> m_aoFields{};
318 : };
319 :
320 : std::vector<URLSpecificResolution> m_aoURLSpecificRules{};
321 :
322 : GMLASXLinkResolutionConf() = default;
323 :
324 : bool LoadFromXML(CPLXMLNode *psRoot);
325 : };
326 :
327 : /************************************************************************/
328 : /* GMLASConfiguration */
329 : /************************************************************************/
330 :
331 : class GMLASConfiguration
332 : {
333 : public:
334 : /** Whether remote schemas are allowed to be download. */
335 : bool m_bAllowRemoteSchemaDownload = ALLOW_REMOTE_SCHEMA_DOWNLOAD_DEFAULT;
336 :
337 : /** Whether a ogr_pkid attribute should always be generated. */
338 : bool m_bAlwaysGenerateOGRId = ALWAYS_GENERATE_OGR_ID_DEFAULT;
339 :
340 : /** Whether to remove layers found to be unused in initial scan pass */
341 : bool m_bRemoveUnusedLayers = REMOVE_UNUSED_LAYERS_DEFAULT;
342 :
343 : /** Whether to remove fields found to be unused in initial scan pass */
344 : bool m_bRemoveUnusedFields = REMOVE_UNUSED_FIELDS_DEFAULT;
345 :
346 : /** Whether repeated strings, integers, reals should be in corresponding
347 : OGR array types. */
348 : bool m_bUseArrays = USE_ARRAYS_DEFAULT;
349 :
350 : /** Whether OGR field null state should be used. */
351 : bool m_bUseNullState = USE_NULL_STATE_DEFAULT;
352 :
353 : /** Whether geometries should be stored as XML in a OGR string field. */
354 : bool m_bIncludeGeometryXML = INCLUDE_GEOMETRY_XML_DEFAULT;
355 :
356 : /** Whether, when dealing with schemas that import the
357 : GML namespace, and that at least one of them has
358 : elements that derive from gml:_Feature or
359 : gml:AbstractFeatureonly, only such elements should be
360 : instantiated as OGR layers, during the first pass that
361 : iterates over top level elements of the imported
362 : schemas. */
363 : bool m_bInstantiateGMLFeaturesOnly = INSTANTIATE_GML_FEATURES_ONLY_DEFAULT;
364 :
365 : /** Maximum length of layer and field identifiers*/
366 : int m_nIdentifierMaxLength = 0;
367 :
368 : /** Whether case insensitive comparison should be used for identifier
369 : * equality testing */
370 : bool m_bCaseInsensitiveIdentifier = CASE_INSENSITIVE_IDENTIFIER_DEFAULT;
371 :
372 : /** Whether to launder identifiers like postgresql does */
373 : bool m_bPGIdentifierLaundering = PG_IDENTIFIER_LAUNDERING_DEFAULT;
374 :
375 : /* Maximum number of fields in an element considered for flattening. */
376 : int m_nMaximumFieldsForFlattening = MAXIMUM_FIELDS_FLATTENING_DEFAULT;
377 :
378 : /** Whether remote XSD schemas should be locally cached. */
379 : bool m_bAllowXSDCache = ALLOW_XSD_CACHE_DEFAULT;
380 :
381 : /** Cache directory for cached XSD schemas. */
382 : CPLString m_osXSDCacheDirectory{};
383 :
384 : /** Whether to enable schema full checking. */
385 : bool m_bSchemaFullChecking = SCHEMA_FULL_CHECKING_DEFAULT;
386 :
387 : /** Whether to allow multiple imports of the same namespace. */
388 : bool m_bHandleMultipleImports = HANDLE_MULTIPLE_IMPORTS_DEFAULT;
389 :
390 : /** Whether validation of document against schema should be done. */
391 : bool m_bValidate = VALIDATE_DEFAULT;
392 :
393 : /** Whether a validation error should prevent dataset opening. */
394 : bool m_bFailIfValidationError = FAIL_IF_VALIDATION_ERROR_DEFAULT;
395 :
396 : /** Whether technical layers should be exposed. */
397 : bool m_bExposeMetadataLayers = WARN_IF_EXCLUDED_XPATH_FOUND_DEFAULT;
398 :
399 : /** For flatening rules, map prefix namespace to its URI */
400 : std::map<CPLString, CPLString> m_oMapPrefixToURIFlatteningRules{};
401 :
402 : std::vector<CPLString> m_osForcedFlattenedXPath{};
403 :
404 : std::vector<CPLString> m_osDisabledFlattenedXPath{};
405 :
406 : enum SWEActivationMode
407 : {
408 : SWE_ACTIVATE_IF_NAMESPACE_FOUND,
409 : SWE_ACTIVATE_TRUE,
410 : SWE_ACTIVATE_FALSE
411 : };
412 :
413 : /** If and when activate SWE special processings */
414 : SWEActivationMode m_eSWEActivationMode = SWE_ACTIVATE_IF_NAMESPACE_FOUND;
415 :
416 : /** If enabling swe:DataRecord parsing */
417 : bool m_bSWEProcessDataRecord = SWE_PROCESS_DATA_RECORD_DEFAULT;
418 :
419 : /** If enabling swe:DataArray parsing */
420 : bool m_bSWEProcessDataArray = SWE_PROCESS_DATA_ARRAY_DEFAULT;
421 :
422 : /** For ignored xpaths, map prefix namespace to its URI */
423 : std::map<CPLString, CPLString> m_oMapPrefixToURIIgnoredXPaths{};
424 :
425 : /** Ignored xpaths */
426 : std::vector<CPLString> m_aosIgnoredXPaths{};
427 :
428 : /** For type constraints, map prefix namespace to its URI */
429 : std::map<CPLString, CPLString> m_oMapPrefixToURITypeConstraints{};
430 :
431 : /** Map an XPath to a list of potential types for its children */
432 : std::map<CPLString, std::vector<CPLString>>
433 : m_oMapChildrenElementsConstraints{};
434 :
435 : /* Beginning of Writer config */
436 :
437 : /** Number of spaces for indentation */
438 : int m_nIndentSize = INDENT_SIZE_DEFAULT;
439 :
440 : CPLString m_osComment{};
441 :
442 : /** End of line format: "CRLF" or "LR" */
443 : CPLString m_osLineFormat{};
444 :
445 : /** "SHORT", "OGC_URN" or "OGC_URL" */
446 : CPLString m_osSRSNameFormat = szSRSNAME_DEFAULT;
447 :
448 : /** "WFS2_FEATURECOLLECTION" or "GMLAS_FEATURECOLLECTION" */
449 : CPLString m_osWrapping = szWFS2_FEATURECOLLECTION;
450 :
451 : /** XML datetime or empty for current time */
452 : CPLString m_osTimestamp{};
453 :
454 : /** Path or URL to OGC WFS 2.0 schema. */
455 : CPLString m_osWFS20SchemaLocation = szWFS20_SCHEMALOCATION;
456 :
457 : /* End of Writer config */
458 :
459 : /** Whether a warning should be emitted when an element or attribute is
460 : found in the document parsed, but ignored because of the ignored
461 : XPath defined. */
462 : std::map<CPLString, bool> m_oMapIgnoredXPathToWarn{};
463 :
464 : GMLASXLinkResolutionConf m_oXLinkResolution{};
465 :
466 : GMLASConfiguration() = default;
467 :
468 : bool Load(const char *pszFilename);
469 : void Finalize();
470 :
471 : static CPLString GetBaseCacheDirectory();
472 : };
473 :
474 : /************************************************************************/
475 : /* GMLASXLinkResolver */
476 : /************************************************************************/
477 :
478 : class GMLASXLinkResolver final : public GMLASResourceCache
479 : {
480 : GMLASXLinkResolutionConf m_oConf{};
481 : int m_nGlobalResolutionTime = 0;
482 :
483 : std::map<CPLString, CPLString> m_oMapURLToContent{};
484 : std::map<size_t, std::vector<CPLString>> m_oMapFileSizeToURLs{};
485 : size_t m_nMaxRAMCacheSize = 0;
486 : size_t m_nCurrentRAMCacheSize = 0;
487 :
488 : CPLString FetchRawContent(const CPLString &osURL, const char *pszHeaders);
489 :
490 : CPLString GetRawContent(const CPLString &osURL, const char *pszHeaders,
491 : bool bAllowRemoteDownload, bool bCacheResults);
492 :
493 : public:
494 : GMLASXLinkResolver();
495 :
496 : void SetConf(const GMLASXLinkResolutionConf &oConf);
497 :
498 19524 : const GMLASXLinkResolutionConf &GetConf() const
499 : {
500 19524 : return m_oConf;
501 : }
502 :
503 : bool IsRawContentResolutionEnabled() const;
504 : int GetMatchingResolutionRule(const CPLString &osURL) const;
505 : CPLString GetRawContent(const CPLString &osURL);
506 : CPLString GetRawContentForRule(const CPLString &osURL, int nIdxRule);
507 : };
508 :
509 : /************************************************************************/
510 : /* GMLASXPathMatcher */
511 : /************************************************************************/
512 :
513 : /** Object to compares a user provided XPath against a set of test XPaths */
514 : class GMLASXPathMatcher
515 : {
516 : struct XPathComponent
517 : {
518 : CPLString m_osValue{};
519 : bool m_bDirectChild = false;
520 : };
521 :
522 : /** For reference xpaths, map prefix namespace to its URI */
523 : std::map<CPLString, CPLString> m_oMapPrefixToURIReferenceXPaths{};
524 :
525 : /** Reference xpaths */
526 : std::vector<CPLString> m_aosReferenceXPathsUncompiled{};
527 :
528 : /** Reference xpaths "compiled" */
529 : std::vector<std::vector<XPathComponent>> m_aosReferenceXPaths{};
530 :
531 : static bool MatchesRefXPath(const CPLString &osXPath,
532 : const std::vector<XPathComponent> &oRefXPath);
533 :
534 : public:
535 : void SetRefXPaths(
536 : const std::map<CPLString, CPLString> &oMapPrefixToURIReferenceXPaths,
537 : const std::vector<CPLString> &aosReferenceXPaths);
538 :
539 : void SetDocumentMapURIToPrefix(
540 : const std::map<CPLString, CPLString> &oMapURIToPrefix);
541 :
542 : /** Return true if osXPath matches one of the XPath of
543 : m_aosReferenceXPaths */
544 : bool MatchesRefXPath(const CPLString &osXPath,
545 : CPLString &osOutMatchedXPath) const;
546 :
547 6 : const std::map<CPLString, CPLString> &GetMapPrefixToURI() const
548 : {
549 6 : return m_oMapPrefixToURIReferenceXPaths;
550 : }
551 : };
552 :
553 : /************************************************************************/
554 : /* GMLASFieldType */
555 : /************************************************************************/
556 :
557 : /** Enumeration for XML primitive types */
558 : typedef enum
559 : {
560 : GMLAS_FT_STRING,
561 : GMLAS_FT_ID,
562 : GMLAS_FT_BOOLEAN,
563 : GMLAS_FT_SHORT,
564 : GMLAS_FT_INT32,
565 : GMLAS_FT_INT64,
566 : GMLAS_FT_FLOAT,
567 : GMLAS_FT_DOUBLE,
568 : GMLAS_FT_DECIMAL,
569 : GMLAS_FT_DATE,
570 : GMLAS_FT_GYEAR,
571 : GMLAS_FT_GYEAR_MONTH,
572 : GMLAS_FT_TIME,
573 : GMLAS_FT_DATETIME,
574 : GMLAS_FT_BASE64BINARY,
575 : GMLAS_FT_HEXBINARY,
576 : GMLAS_FT_ANYURI,
577 : GMLAS_FT_ANYTYPE,
578 : GMLAS_FT_ANYSIMPLETYPE,
579 : GMLAS_FT_GEOMETRY, // this one isn't a XML primitive type.
580 : } GMLASFieldType;
581 :
582 : /************************************************************************/
583 : /* GMLASField */
584 : /************************************************************************/
585 :
586 : class GMLASField
587 : {
588 : public:
589 : typedef enum
590 : {
591 : /** Field that is going to be instantiated as a OGR field */
592 : REGULAR,
593 :
594 : /** Non-instanciable field. The corresponding element to the XPath
595 : is stored in a child layer that will reference back to the
596 : main layer. */
597 : PATH_TO_CHILD_ELEMENT_NO_LINK,
598 :
599 : /** Field that will store the PKID of a child element */
600 : PATH_TO_CHILD_ELEMENT_WITH_LINK,
601 :
602 : /** Non-instanciable field. The corresponding element to the XPath
603 : is stored in a child layer. And the link between both will be
604 : done through a junction table. */
605 : PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE,
606 :
607 : /** Non-instanciable field. Corresponds to a group of an element. */
608 : GROUP
609 : } Category;
610 :
611 : private:
612 : CPLString m_osName{}; /**< Field name */
613 : GMLASFieldType m_eType = GMLAS_FT_STRING; /**< Field type */
614 : OGRwkbGeometryType m_eGeomType = wkbNone; /**< Field geometry type */
615 : CPLString m_osTypeName{}; /**< Original XSD type */
616 : int m_nWidth = 0; /**< Field width */
617 : bool m_bNotNullable = false; /**< If the field is not nullable */
618 :
619 : /** If the field is an array (from OGR types point of view) */
620 : bool m_bArray = false;
621 : bool m_bList = false; /**< If the field is a list (a xs:list) */
622 :
623 : /** Category of the field. */
624 : Category m_eCategory = REGULAR;
625 :
626 : /** XPath of the field. */
627 : CPLString m_osXPath{};
628 :
629 : /** Set of XPath that are linked to this field.
630 : This is used for cases where a gml:AbstractGeometry element is
631 : referenced. In which case all possible realizations of this
632 : element are listed. Will be used with eType == GMLAS_FT_ANYTYPE
633 : to store XML blob on parsing. */
634 : std::vector<CPLString> m_aosXPath{};
635 :
636 : CPLString m_osFixedValue{}; /**< Value of fixed='' attribute */
637 : CPLString m_osDefaultValue{}; /**< Value of default='' attribute */
638 :
639 : /** Minimum number of occurrences. Might be -1 if unset */
640 : int m_nMinOccurs = -1;
641 :
642 : /** Maximum number of occurrences, or MAXOCCURS_UNLIMITED. Might be
643 : -1 if unset. */
644 : int m_nMaxOccurs = -1;
645 :
646 : /** For a PATH_TO_CHILD_ELEMENT_NO_LINK, whether maxOccurs>1 is on the
647 : sequence rather than on the element */
648 : bool m_bRepetitionOnSequence = false;
649 :
650 : /** In case of m_eType == GMLAS_FT_ANYTYPE whether the current element
651 : must be stored in the XML blob (if false, only its children) */
652 : bool m_bIncludeThisEltInBlob = false;
653 :
654 : /** Only used for PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE. The XPath
655 : of the abstract element (the concrete XPath is in m_osXPath).
656 : e.g myns:mainElt/myns:subEltAbstract whereas the concrete XPath
657 : is myns:mainElt/myns:subEltRealization */
658 : CPLString m_osAbstractElementXPath{};
659 :
660 : /** Only used for PATH_TO_CHILD_ELEMENT_WITH_LINK and
661 : PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE (and also for
662 : PATH_TO_CHILD_ELEMENT_NO_LINK and GROUP but for metadata layers only).
663 : The XPath of the child element. */
664 : CPLString m_osRelatedClassXPath{};
665 :
666 : /** Only use for PATH_TO_CHILD_ELEMENT_WITH_JUNCTION_TABLE. Name of
667 : the junction layer to consult for this field. Only used by
668 : writer code. */
669 : CPLString m_osJunctionLayer{};
670 :
671 : /** Dirty hack to register attributes with fixed values, despite being
672 : in the XPath ignored list. Needed to avoid warning when doing validation
673 : */
674 : bool m_bIgnored = false;
675 :
676 : /** Documentation from schema */
677 : CPLString m_osDoc{};
678 :
679 : /** For elements within xs:choice */
680 : bool m_bMayAppearOutOfOrder = false;
681 :
682 : public:
683 216394 : GMLASField() = default;
684 :
685 830316 : void SetName(const CPLString &osName)
686 : {
687 830316 : m_osName = osName;
688 830316 : }
689 :
690 : void SetType(GMLASFieldType eType, const char *pszTypeName);
691 :
692 369 : void SetGeomType(OGRwkbGeometryType eGeomType)
693 : {
694 369 : m_eGeomType = eGeomType;
695 369 : }
696 :
697 194839 : void SetWidth(int nWidth)
698 : {
699 194839 : m_nWidth = nWidth;
700 194839 : }
701 :
702 169674 : void SetNotNullable(bool bNotNullable)
703 : {
704 169674 : m_bNotNullable = bNotNullable;
705 169674 : }
706 :
707 4169 : void SetArray(bool bArray)
708 : {
709 4169 : m_bArray = bArray;
710 4169 : }
711 :
712 2454 : void SetList(bool bList)
713 : {
714 2454 : m_bList = bList;
715 2454 : }
716 :
717 215614 : void SetXPath(const CPLString &osXPath)
718 : {
719 215614 : m_osXPath = osXPath;
720 215614 : }
721 :
722 735 : void AddAlternateXPath(const CPLString &osXPath)
723 : {
724 735 : m_aosXPath.push_back(osXPath);
725 735 : }
726 :
727 560 : void SetFixedValue(const CPLString &osFixedValue)
728 : {
729 560 : m_osFixedValue = osFixedValue;
730 560 : }
731 :
732 907 : void SetDefaultValue(const CPLString &osDefaultValue)
733 : {
734 907 : m_osDefaultValue = osDefaultValue;
735 907 : }
736 :
737 21249 : void SetCategory(Category eCategory)
738 : {
739 21249 : m_eCategory = eCategory;
740 21249 : }
741 :
742 317141 : void SetMinOccurs(int nMinOccurs)
743 : {
744 317141 : m_nMinOccurs = nMinOccurs;
745 317141 : }
746 :
747 215529 : void SetMaxOccurs(int nMaxOccurs)
748 : {
749 215529 : m_nMaxOccurs = nMaxOccurs;
750 215529 : }
751 :
752 815 : void SetRepetitionOnSequence(bool b)
753 : {
754 815 : m_bRepetitionOnSequence = b;
755 815 : }
756 :
757 272 : void SetIncludeThisEltInBlob(bool b)
758 : {
759 272 : m_bIncludeThisEltInBlob = b;
760 272 : }
761 :
762 8935 : void SetAbstractElementXPath(const CPLString &osName)
763 : {
764 8935 : m_osAbstractElementXPath = osName;
765 8935 : }
766 :
767 20681 : void SetRelatedClassXPath(const CPLString &osName)
768 : {
769 20681 : m_osRelatedClassXPath = osName;
770 20681 : }
771 :
772 16 : void SetJunctionLayer(const CPLString &osName)
773 : {
774 16 : m_osJunctionLayer = osName;
775 16 : }
776 :
777 16 : void SetIgnored()
778 : {
779 16 : m_bIgnored = true;
780 16 : }
781 :
782 194178 : void SetDocumentation(const CPLString &osDoc)
783 : {
784 194178 : m_osDoc = osDoc;
785 194178 : }
786 :
787 149468 : void SetMayAppearOutOfOrder(bool b)
788 : {
789 149468 : m_bMayAppearOutOfOrder = b;
790 149468 : }
791 :
792 : static CPLString
793 22 : MakePKIDFieldXPathFromXLinkHrefXPath(const CPLString &osBaseXPath)
794 : {
795 44 : return "{" + osBaseXPath + "}_pkid";
796 : }
797 :
798 25 : static CPLString MakeXLinkRawContentFieldXPathFromXLinkHrefXPath(
799 : const CPLString &osBaseXPath)
800 : {
801 50 : return "{" + osBaseXPath + "}_rawcontent";
802 : }
803 :
804 : static CPLString
805 40 : MakeXLinkDerivedFieldXPathFromXLinkHrefXPath(const CPLString &osBaseXPath,
806 : const CPLString &osName)
807 : {
808 80 : return "{" + osBaseXPath + "}_derived_" + osName;
809 : }
810 :
811 1720780 : const CPLString &GetName() const
812 : {
813 1720780 : return m_osName;
814 : }
815 :
816 6477890 : const CPLString &GetXPath() const
817 : {
818 6477890 : return m_osXPath;
819 : }
820 :
821 188446 : const std::vector<CPLString> &GetAlternateXPaths() const
822 : {
823 188446 : return m_aosXPath;
824 : }
825 :
826 662207 : GMLASFieldType GetType() const
827 : {
828 662207 : return m_eType;
829 : }
830 :
831 369 : OGRwkbGeometryType GetGeomType() const
832 : {
833 369 : return m_eGeomType;
834 : }
835 :
836 364655 : const CPLString &GetTypeName() const
837 : {
838 364655 : return m_osTypeName;
839 : }
840 :
841 174064 : int GetWidth() const
842 : {
843 174064 : return m_nWidth;
844 : }
845 :
846 220167 : bool IsNotNullable() const
847 : {
848 220167 : return m_bNotNullable;
849 : }
850 :
851 340813 : bool IsArray() const
852 : {
853 340813 : return m_bArray;
854 : }
855 :
856 223723 : bool IsList() const
857 : {
858 223723 : return m_bList;
859 : }
860 :
861 1989510 : const CPLString &GetFixedValue() const
862 : {
863 1989510 : return m_osFixedValue;
864 : }
865 :
866 1845810 : const CPLString &GetDefaultValue() const
867 : {
868 1845810 : return m_osDefaultValue;
869 : }
870 :
871 2352600 : Category GetCategory() const
872 : {
873 2352600 : return m_eCategory;
874 : }
875 :
876 377831 : int GetMinOccurs() const
877 : {
878 377831 : return m_nMinOccurs;
879 : }
880 :
881 901795 : int GetMaxOccurs() const
882 : {
883 901795 : return m_nMaxOccurs;
884 : }
885 :
886 14491 : bool GetRepetitionOnSequence() const
887 : {
888 14491 : return m_bRepetitionOnSequence;
889 : }
890 :
891 5788 : bool GetIncludeThisEltInBlob() const
892 : {
893 5788 : return m_bIncludeThisEltInBlob;
894 : }
895 :
896 13501 : const CPLString &GetAbstractElementXPath() const
897 : {
898 13501 : return m_osAbstractElementXPath;
899 : }
900 :
901 24 : const CPLString &GetJunctionLayer() const
902 : {
903 24 : return m_osJunctionLayer;
904 : }
905 :
906 229590 : const CPLString &GetRelatedClassXPath() const
907 : {
908 229590 : return m_osRelatedClassXPath;
909 : }
910 :
911 188015 : bool IsIgnored() const
912 : {
913 188015 : return m_bIgnored;
914 : }
915 :
916 330019 : const CPLString &GetDocumentation() const
917 : {
918 330019 : return m_osDoc;
919 : }
920 :
921 4 : bool MayAppearOutOfOrder() const
922 : {
923 4 : return m_bMayAppearOutOfOrder;
924 : }
925 :
926 : static GMLASFieldType GetTypeFromString(const CPLString &osType);
927 : };
928 :
929 : /************************************************************************/
930 : /* GMLASFeatureClass */
931 : /************************************************************************/
932 :
933 : class GMLASFeatureClass
934 : {
935 : /** User facing name */
936 : CPLString m_osName{};
937 :
938 : /** XPath to the main element of the feature class */
939 : CPLString m_osXPath{};
940 :
941 : /** List of fields */
942 : std::vector<GMLASField> m_aoFields{};
943 :
944 : /** Child nested classes */
945 : std::vector<GMLASFeatureClass> m_aoNestedClasses{};
946 :
947 : /** Whether this layer corresponds to a (multiple instantiated) xs:group
948 : or a repeated sequence */
949 : bool m_bIsRepeatedSequence = false;
950 :
951 : /** Whether this is a repeated group. Should be set together with
952 : * m_bIsRepeatedSequence */
953 : bool m_bIsGroup = false;
954 :
955 : /** Only used for junction tables. The XPath to the parent table */
956 : CPLString m_osParentXPath{};
957 :
958 : /** Only used for junction tables. The XPath to the child table */
959 : CPLString m_osChildXPath{};
960 :
961 : /** Whether this corresponds to a top-level XSD element in the schema */
962 : bool m_bIsTopLevelElt = false;
963 :
964 : /** Documentation from schema */
965 : CPLString m_osDoc{};
966 :
967 : public:
968 42644 : GMLASFeatureClass() = default;
969 :
970 : void SetName(const CPLString &osName);
971 : void SetXPath(const CPLString &osXPath);
972 : void AddField(const GMLASField &oField);
973 : void PrependFields(const std::vector<GMLASField> &aoFields);
974 : void AppendFields(const std::vector<GMLASField> &aoFields);
975 : void AddNestedClass(const GMLASFeatureClass &oNestedClass);
976 :
977 4121 : void SetIsRepeatedSequence(bool bIsRepeatedSequence)
978 : {
979 4121 : m_bIsRepeatedSequence = bIsRepeatedSequence;
980 4121 : }
981 :
982 208 : void SetIsGroup(bool bIsGroup)
983 : {
984 208 : m_bIsGroup = bIsGroup;
985 208 : }
986 :
987 8935 : void SetParentXPath(const CPLString &osXPath)
988 : {
989 8935 : m_osParentXPath = osXPath;
990 8935 : }
991 :
992 8935 : void SetChildXPath(const CPLString &osXPath)
993 : {
994 8935 : m_osChildXPath = osXPath;
995 8935 : }
996 :
997 3129 : void SetIsTopLevelElt(bool bIsTopLevelElt)
998 : {
999 3129 : m_bIsTopLevelElt = bIsTopLevelElt;
1000 3129 : }
1001 :
1002 30570 : void SetDocumentation(const CPLString &osDoc)
1003 : {
1004 30570 : m_osDoc = osDoc;
1005 30570 : }
1006 :
1007 86815 : const CPLString &GetName() const
1008 : {
1009 86815 : return m_osName;
1010 : }
1011 :
1012 9259310 : const CPLString &GetXPath() const
1013 : {
1014 9259310 : return m_osXPath;
1015 : }
1016 :
1017 327814 : const std::vector<GMLASField> &GetFields() const
1018 : {
1019 327814 : return m_aoFields;
1020 : }
1021 :
1022 62689 : std::vector<GMLASField> &GetFields()
1023 : {
1024 62689 : return m_aoFields;
1025 : }
1026 :
1027 15386 : const std::vector<GMLASFeatureClass> &GetNestedClasses() const
1028 : {
1029 15386 : return m_aoNestedClasses;
1030 : }
1031 :
1032 48364 : std::vector<GMLASFeatureClass> &GetNestedClasses()
1033 : {
1034 48364 : return m_aoNestedClasses;
1035 : }
1036 :
1037 8506650 : bool IsRepeatedSequence() const
1038 : {
1039 8506650 : return m_bIsRepeatedSequence;
1040 : }
1041 :
1042 4223340 : bool IsGroup() const
1043 : {
1044 4223340 : return m_bIsGroup;
1045 : }
1046 :
1047 70286 : const CPLString &GetParentXPath() const
1048 : {
1049 70286 : return m_osParentXPath;
1050 : }
1051 :
1052 : const CPLString &GetChildXPath() const
1053 : {
1054 : return m_osChildXPath;
1055 : }
1056 :
1057 6451 : bool IsTopLevelElt() const
1058 : {
1059 6451 : return m_bIsTopLevelElt;
1060 : }
1061 :
1062 11581 : const CPLString &GetDocumentation() const
1063 : {
1064 11581 : return m_osDoc;
1065 : }
1066 : };
1067 :
1068 : /************************************************************************/
1069 : /* GMLASSchemaAnalyzer */
1070 : /************************************************************************/
1071 :
1072 : class GMLASSchemaAnalyzer
1073 : {
1074 : GMLASXPathMatcher &m_oIgnoredXPathMatcher;
1075 :
1076 : GMLASXPathMatcher &m_oChildrenElementsConstraintsXPathMatcher;
1077 :
1078 : GMLASXPathMatcher &m_oForcedFlattenedXPathMatcher;
1079 :
1080 : GMLASXPathMatcher &m_oDisabledFlattenedXPathMatcher;
1081 :
1082 : std::map<CPLString, std::vector<CPLString>>
1083 : m_oMapChildrenElementsConstraints{};
1084 :
1085 : /** Whether repeated strings, integers, reals should be in corresponding
1086 : OGR array types. */
1087 : bool m_bUseArrays = true;
1088 :
1089 : /** Whether OGR field null state should be used. */
1090 : bool m_bUseNullState = false;
1091 :
1092 : /** Whether, when dealing with schemas that import the
1093 : GML namespace, and that at least one of them has
1094 : elements that derive from gml:_Feature or
1095 : gml:AbstractFeatureonly, only such elements should be
1096 : instantiated as OGR layers, during the first pass that
1097 : iterates over top level elements of the imported
1098 : schemas. */
1099 : bool m_bInstantiateGMLFeaturesOnly = true;
1100 :
1101 : /** Vector of feature classes */
1102 : std::vector<GMLASFeatureClass> m_aoClasses{};
1103 :
1104 : /** Map from a namespace URI to the corresponding prefix */
1105 : std::map<CPLString, CPLString> m_oMapURIToPrefix{};
1106 :
1107 : /** Map element XPath to its XSElementDeclaration* */
1108 : std::map<CPLString, XSElementDeclaration *> m_oMapXPathToEltDecl{};
1109 :
1110 : typedef std::map<XSElementDeclaration *,
1111 : std::vector<XSElementDeclaration *>>
1112 : tMapParentEltToChildElt;
1113 : /** Map from a base/parent element to a vector of derived/children
1114 : elements that are substitutionGroup of it. The map only
1115 : addresses the direct derived types, and not the 2nd level or more
1116 : derived ones. For that recursion in the map must be used.*/
1117 : tMapParentEltToChildElt m_oMapParentEltToChildElt{};
1118 :
1119 : /** Map from a XSModelGroup* object to the name of its group definition. */
1120 : std::map<XSModelGroup *, XSModelGroupDefinition *> m_oMapModelGroupToMGD{};
1121 :
1122 : /** Map from (non namespace prefixed) element names to the number of
1123 : elements that share the same namespace (in different namespaces) */
1124 : std::map<CPLString, int> m_oMapEltNamesToInstanceCount{};
1125 :
1126 : /** Set of elements that match a OGR layer */
1127 : std::set<XSElementDeclaration *> m_oSetEltsForTopClass{};
1128 :
1129 : /** Set of elements that are simple enough to be inlined whenever they
1130 : are referenced with cardinality 1. The use case if base:identifier
1131 : used by Inspire schemas. */
1132 : std::set<XSElementDeclaration *> m_oSetSimpleEnoughElts{};
1133 :
1134 : /** Maximum length of layer and field identifiers*/
1135 : int m_nIdentifierMaxLength = 0;
1136 :
1137 : /** Whether case insensitive comparison should be used for identifier
1138 : * equality testing */
1139 : bool m_bCaseInsensitiveIdentifier = CASE_INSENSITIVE_IDENTIFIER_DEFAULT;
1140 :
1141 : /** Whether to launder identifiers like postgresql does */
1142 : bool m_bPGIdentifierLaundering = PG_IDENTIFIER_LAUNDERING_DEFAULT;
1143 :
1144 : /* Maximum number of fields in an element considered for flattening. */
1145 : int m_nMaximumFieldsForFlattening = MAXIMUM_FIELDS_FLATTENING_DEFAULT;
1146 :
1147 : /** GML version found: 2.1.1, 3.1.1 or 3.2.1 or empty*/
1148 : CPLString m_osGMLVersionFound{};
1149 :
1150 : /** Set of schemas opened */
1151 : std::set<CPLString> m_oSetSchemaURLs{};
1152 :
1153 : /** Map from namespace URI to namespace prefix coming from the
1154 : * examination of xmlns:foo=bar attributes of the top element of the
1155 : * GML document */
1156 : std::map<CPLString, CPLString> m_oMapDocNSURIToPrefix{};
1157 :
1158 : bool m_bAlwaysGenerateOGRId = ALWAYS_GENERATE_OGR_ID_DEFAULT;
1159 :
1160 : static bool IsSame(const XSModelGroup *poModelGroup1,
1161 : const XSModelGroup *poModelGroup2);
1162 : XSModelGroupDefinition *
1163 : GetGroupDefinition(const XSModelGroup *poModelGroup);
1164 : void SetFieldFromAttribute(GMLASField &oField, XSAttributeUse *poAttr,
1165 : const CPLString &osXPathPrefix,
1166 : const CPLString &osNamePrefix = CPLString());
1167 : void GetConcreteImplementationTypes(
1168 : XSElementDeclaration *poParentElt,
1169 : std::vector<XSElementDeclaration *> &apoImplEltList);
1170 : std::vector<XSElementDeclaration *>
1171 : GetConstraintChildrenElements(const CPLString &osFullXPath);
1172 : bool FindElementsWithMustBeToLevel(
1173 : const CPLString &osParentXPath, XSModelGroup *poModelGroup,
1174 : int nRecursionCounter,
1175 : std::set<XSElementDeclaration *> &oSetVisitedEltDecl,
1176 : std::set<XSModelGroup *> &oSetVisitedModelGroups,
1177 : std::vector<XSElementDeclaration *> &oVectorEltsForTopClass,
1178 : std::set<CPLString> &aoSetXPathEltsForTopClass, XSModel *poModel,
1179 : bool &bSimpleEnoughOut, int &nCountSubEltsOut);
1180 : static void BuildMapCountOccurrencesOfSameName(
1181 : XSModelGroup *poModelGroup,
1182 : std::map<CPLString, int> &oMapCountOccurrencesOfSameName);
1183 : bool ExploreModelGroup(
1184 : XSModelGroup *psMainModelGroup, XSAttributeUseList *poMainAttrList,
1185 : GMLASFeatureClass &oClass, int nRecursionCounter,
1186 : std::set<XSModelGroup *> &oSetVisitedModelGroups, XSModel *poModel,
1187 : const std::map<CPLString, int> &oMapCountOccurrencesOfSameName);
1188 : void SetFieldTypeAndWidthFromDefinition(XSSimpleTypeDefinition *poST,
1189 : GMLASField &oField);
1190 : CPLString GetPrefix(const CPLString &osNamespaceURI);
1191 : CPLString MakeXPath(const CPLString &osNamespace, const CPLString &osName);
1192 : bool LaunderFieldNames(GMLASFeatureClass &oClass);
1193 : void LaunderClassNames();
1194 :
1195 : XSElementDeclaration *
1196 : GetTopElementDeclarationFromXPath(const CPLString &osXPath,
1197 : XSModel *poModel);
1198 :
1199 : bool InstantiateClassFromEltDeclaration(XSElementDeclaration *poEltDecl,
1200 : XSModel *poModel, bool &bError);
1201 : void CreateNonNestedRelationship(
1202 : XSElementDeclaration *poElt,
1203 : std::vector<XSElementDeclaration *> &apoSubEltList,
1204 : GMLASFeatureClass &oClass, int nMaxOccurs, bool bEltNameWillNeedPrefix,
1205 : bool bForceJunctionTable, bool bCaseOfConstraintChildren);
1206 :
1207 : bool IsGMLNamespace(const CPLString &osURI);
1208 :
1209 : bool DerivesFromGMLFeature(XSElementDeclaration *poEltDecl);
1210 :
1211 : bool IsIgnoredXPath(const CPLString &osXPath);
1212 :
1213 : static void
1214 : CollectClassesReferences(GMLASFeatureClass &oClass,
1215 : std::vector<GMLASFeatureClass *> &aoClasses);
1216 :
1217 : CPL_DISALLOW_COPY_ASSIGN(GMLASSchemaAnalyzer)
1218 :
1219 : public:
1220 : GMLASSchemaAnalyzer(
1221 : GMLASXPathMatcher &oIgnoredXPathMatcher,
1222 : GMLASXPathMatcher &oChildrenElementsConstraintsXPathMatcher,
1223 : const std::map<CPLString, std::vector<CPLString>>
1224 : &oMapChildrenElementsConstraints,
1225 : GMLASXPathMatcher &oForcedFlattenedXPathMatcher,
1226 : GMLASXPathMatcher &oDisabledFlattenedXPathMatcher);
1227 :
1228 185 : void SetUseArrays(bool b)
1229 : {
1230 185 : m_bUseArrays = b;
1231 185 : }
1232 :
1233 185 : void SetUseNullState(bool b)
1234 : {
1235 185 : m_bUseNullState = b;
1236 185 : }
1237 :
1238 185 : void SetInstantiateGMLFeaturesOnly(bool b)
1239 : {
1240 185 : m_bInstantiateGMLFeaturesOnly = b;
1241 185 : }
1242 :
1243 185 : void SetIdentifierMaxLength(int nLength)
1244 : {
1245 185 : m_nIdentifierMaxLength = nLength;
1246 185 : }
1247 :
1248 185 : void SetCaseInsensitiveIdentifier(bool b)
1249 : {
1250 185 : m_bCaseInsensitiveIdentifier = b;
1251 185 : }
1252 :
1253 185 : void SetPGIdentifierLaundering(bool b)
1254 : {
1255 185 : m_bPGIdentifierLaundering = b;
1256 185 : }
1257 :
1258 185 : void SetMaximumFieldsForFlattening(int n)
1259 : {
1260 185 : m_nMaximumFieldsForFlattening = n;
1261 185 : }
1262 :
1263 151 : void SetMapDocNSURIToPrefix(const std::map<CPLString, CPLString> &oMap)
1264 : {
1265 151 : m_oMapDocNSURIToPrefix = oMap;
1266 151 : }
1267 :
1268 185 : void SetAlwaysGenerateOGRId(bool b)
1269 : {
1270 185 : m_bAlwaysGenerateOGRId = b;
1271 185 : }
1272 :
1273 : bool Analyze(GMLASXSDCache &oCache, const CPLString &osBaseDirname,
1274 : std::vector<PairURIFilename> &aoXSDs, bool bSchemaFullChecking,
1275 : bool bHandleMultipleImports);
1276 :
1277 171 : const std::vector<GMLASFeatureClass> &GetClasses() const
1278 : {
1279 171 : return m_aoClasses;
1280 : }
1281 :
1282 171 : const std::map<CPLString, CPLString> &GetMapURIToPrefix() const
1283 : {
1284 171 : return m_oMapURIToPrefix;
1285 : }
1286 :
1287 171 : const CPLString &GetGMLVersionFound() const
1288 : {
1289 171 : return m_osGMLVersionFound;
1290 : }
1291 :
1292 171 : const std::set<CPLString> &GetSchemaURLS() const
1293 : {
1294 171 : return m_oSetSchemaURLs;
1295 : }
1296 :
1297 13531 : static CPLString BuildJunctionTableXPath(const CPLString &osEltXPath,
1298 : const CPLString &osSubEltXPath)
1299 : {
1300 27062 : return osEltXPath + "|" + osSubEltXPath;
1301 : }
1302 : };
1303 :
1304 : /************************************************************************/
1305 : /* OGRGMLASDataSource */
1306 : /************************************************************************/
1307 :
1308 : class OGRGMLASLayer;
1309 : class GMLASReader;
1310 :
1311 : class OGRGMLASDataSource final : public GDALDataset
1312 : {
1313 : struct XercesInitializer
1314 : {
1315 : XercesInitializer();
1316 : ~XercesInitializer();
1317 : };
1318 :
1319 : // MUST be first member, to get destroyed last after we have cleaned up
1320 : // all other Xerces dependent objects.
1321 : XercesInitializer m_oXercesInitializer{};
1322 :
1323 : std::vector<std::unique_ptr<OGRGMLASLayer>> m_apoLayers{};
1324 : std::map<CPLString, CPLString> m_oMapURIToPrefix{};
1325 : CPLString m_osGMLFilename{};
1326 : std::unique_ptr<OGRLayer> m_poFieldsMetadataLayer{};
1327 : std::unique_ptr<OGRLayer> m_poLayersMetadataLayer{};
1328 : std::unique_ptr<OGRLayer> m_poRelationshipsLayer{};
1329 : std::unique_ptr<OGRLayer> m_poOtherMetadataLayer{};
1330 : std::vector<OGRLayer *> m_apoRequestedMetadataLayers{};
1331 : std::shared_ptr<VSIVirtualHandle> m_fpGML{};
1332 : std::shared_ptr<VSIVirtualHandle> m_fpGMLParser{};
1333 : bool m_bLayerInitFinished = false;
1334 : bool m_bSchemaFullChecking = false;
1335 : bool m_bHandleMultipleImports = false;
1336 : bool m_bValidate = false;
1337 : bool m_bRemoveUnusedLayers = false;
1338 : bool m_bRemoveUnusedFields = false;
1339 : bool m_bFirstPassDone = false;
1340 : /** Map from a SRS name to a boolean indicating if its coordinate
1341 : order is inverted. */
1342 : std::map<CPLString, bool> m_oMapSRSNameToInvertedAxis{};
1343 :
1344 : /** Map from geometry field definition to its expected SRSName */
1345 : std::map<OGRGeomFieldDefn *, CPLString> m_oMapGeomFieldDefnToSRSName{};
1346 :
1347 : /* map the ID attribute to its belonging layer, e.g foo.1 -> layer Foo */
1348 : std::map<CPLString, OGRGMLASLayer *> m_oMapElementIdToLayer{};
1349 :
1350 : /* map the ID attribute to the feature PKID (when different from itself) */
1351 : std::map<CPLString, CPLString> m_oMapElementIdToPKID{};
1352 :
1353 : std::vector<PairURIFilename> m_aoXSDsManuallyPassed{};
1354 :
1355 : /** Default value for srsDimension attribute. */
1356 : int m_nDefaultSrsDimension = 0;
1357 :
1358 : GMLASConfiguration m_oConf{};
1359 :
1360 : /** Schema cache */
1361 : GMLASXSDCache m_oCache{};
1362 :
1363 : GMLASXPathMatcher m_oIgnoredXPathMatcher{};
1364 :
1365 : GMLASXPathMatcher m_oChildrenElementsConstraintsXPathMatcher{};
1366 :
1367 : GMLASXPathMatcher m_oForcedFlattenedXPathMatcher{};
1368 :
1369 : GMLASXPathMatcher m_oDisabledFlattenedXPathMatcher{};
1370 :
1371 : GMLASSwapCoordinatesEnum m_eSwapCoordinates = GMLAS_SWAP_AUTO;
1372 :
1373 : /** Base unique identifier */
1374 : CPLString m_osHash{};
1375 :
1376 : vsi_l_offset m_nFileSize = 0;
1377 :
1378 : std::unique_ptr<GMLASReader> m_poReader{};
1379 :
1380 : bool m_bEndOfReaderLayers = false;
1381 :
1382 : int m_nCurMetadataLayerIdx = -1;
1383 :
1384 : GMLASXLinkResolver m_oXLinkResolver{};
1385 :
1386 : CPLString m_osGMLVersionFound{};
1387 :
1388 : bool m_bFoundSWE = false;
1389 :
1390 : // Pointers are also included in m_apoLayers
1391 : std::vector<OGRGMLASLayer *> m_apoSWEDataArrayLayersRef{};
1392 :
1393 : void TranslateClasses(OGRGMLASLayer *poParentLayer,
1394 : const GMLASFeatureClass &oFC);
1395 :
1396 : bool RunFirstPassIfNeeded(GMLASReader *poReader,
1397 : GDALProgressFunc pfnProgress,
1398 : void *pProgressData);
1399 :
1400 : void FillOtherMetadataLayer(GDALOpenInfo *poOpenInfo,
1401 : const CPLString &osConfigFile,
1402 : const std::vector<PairURIFilename> &aoXSDs,
1403 : const std::set<CPLString> &oSetSchemaURLs);
1404 :
1405 : static std::vector<PairURIFilename>
1406 : BuildXSDVector(const CPLString &osXSDFilenames);
1407 :
1408 : void InitReaderWithFirstPassElements(GMLASReader *poReader);
1409 :
1410 : public:
1411 : OGRGMLASDataSource();
1412 :
1413 : virtual int GetLayerCount() override;
1414 : virtual OGRLayer *GetLayer(int) override;
1415 : virtual OGRLayer *GetLayerByName(const char *pszName) override;
1416 :
1417 : virtual void ResetReading() override;
1418 : virtual OGRFeature *GetNextFeature(OGRLayer **ppoBelongingLayer,
1419 : double *pdfProgressPct,
1420 : GDALProgressFunc pfnProgress,
1421 : void *pProgressData) override;
1422 : virtual int TestCapability(const char *) override;
1423 :
1424 : bool Open(GDALOpenInfo *poOpenInfo);
1425 :
1426 1379 : std::vector<std::unique_ptr<OGRGMLASLayer>> &GetLayers()
1427 : {
1428 1379 : return m_apoLayers;
1429 : }
1430 :
1431 1379 : const std::map<CPLString, CPLString> &GetMapURIToPrefix() const
1432 : {
1433 1379 : return m_oMapURIToPrefix;
1434 : }
1435 :
1436 1461 : const CPLString &GetGMLFilename() const
1437 : {
1438 1461 : return m_osGMLFilename;
1439 : }
1440 :
1441 : const CPLString &GetGMLVersionFound() const
1442 : {
1443 : return m_osGMLVersionFound;
1444 : }
1445 :
1446 15415 : OGRLayer *GetFieldsMetadataLayer()
1447 : {
1448 15415 : return m_poFieldsMetadataLayer.get();
1449 : }
1450 :
1451 15386 : OGRLayer *GetLayersMetadataLayer()
1452 : {
1453 15386 : return m_poLayersMetadataLayer.get();
1454 : }
1455 :
1456 15389 : OGRLayer *GetRelationshipsLayer()
1457 : {
1458 15389 : return m_poRelationshipsLayer.get();
1459 : }
1460 :
1461 : OGRGMLASLayer *GetLayerByXPath(const CPLString &osXPath);
1462 :
1463 : GMLASReader *CreateReader(std::shared_ptr<VSIVirtualHandle> &fpGML,
1464 : GDALProgressFunc pfnProgress = nullptr,
1465 : void *pProgressData = nullptr);
1466 :
1467 1272 : GMLASXSDCache &GetCache()
1468 : {
1469 1272 : return m_oCache;
1470 : }
1471 :
1472 : void PushUnusedGMLFilePointer(std::shared_ptr<VSIVirtualHandle> &fpGML);
1473 : std::shared_ptr<VSIVirtualHandle> PopUnusedGMLFilePointer();
1474 :
1475 43742 : bool IsLayerInitFinished() const
1476 : {
1477 43742 : return m_bLayerInitFinished;
1478 : }
1479 :
1480 1272 : GMLASSwapCoordinatesEnum GetSwapCoordinates() const
1481 : {
1482 1272 : return m_eSwapCoordinates;
1483 : }
1484 :
1485 1272 : const std::map<CPLString, bool> &GetMapIgnoredXPathToWarn() const
1486 : {
1487 1272 : return m_oConf.m_oMapIgnoredXPathToWarn;
1488 : }
1489 :
1490 1272 : const GMLASXPathMatcher &GetIgnoredXPathMatcher() const
1491 : {
1492 1272 : return m_oIgnoredXPathMatcher;
1493 : }
1494 :
1495 546 : const GMLASConfiguration &GetConf() const
1496 : {
1497 546 : return m_oConf;
1498 : }
1499 :
1500 : const std::vector<PairURIFilename> &GetXSDsManuallyPassed() const
1501 : {
1502 : return m_aoXSDsManuallyPassed;
1503 : }
1504 : };
1505 :
1506 : /************************************************************************/
1507 : /* OGRGMLASLayer */
1508 : /************************************************************************/
1509 :
1510 : class OGRGMLASLayer final : public OGRLayer
1511 : {
1512 : friend class OGRGMLASDataSource;
1513 :
1514 : OGRGMLASDataSource *m_poDS = nullptr;
1515 : GMLASFeatureClass m_oFC{};
1516 : bool m_bLayerDefnFinalized = false;
1517 : int m_nMaxFieldIndex = 0;
1518 : OGRFeatureDefn *m_poFeatureDefn = nullptr;
1519 :
1520 : /** Map from XPath to corresponding field index in OGR layer
1521 : definition */
1522 : std::map<CPLString, int> m_oMapFieldXPathToOGRFieldIdx{};
1523 :
1524 : /** Map from XPath to corresponding geometry field index in OGR layer
1525 : definition */
1526 : std::map<CPLString, int> m_oMapFieldXPathToOGRGeomFieldIdx{};
1527 :
1528 : /** Map from a OGR field index to the corresponding field index in
1529 : m_oFC.GetFields() */
1530 : std::map<int, int> m_oMapOGRFieldIdxtoFCFieldIdx{};
1531 : std::map<int, int> m_oMapOGRGeomFieldIdxtoFCFieldIdx{};
1532 :
1533 : /** Map from XPath to corresponding field index in m_oFC.GetFields() */
1534 : std::map<CPLString, int> m_oMapFieldXPathToFCFieldIdx{};
1535 :
1536 : bool m_bEOF = false;
1537 : std::unique_ptr<GMLASReader> m_poReader{};
1538 : std::shared_ptr<VSIVirtualHandle> m_fpGML{};
1539 : /** OGR field index of the ID field */
1540 : int m_nIDFieldIdx = -1;
1541 : /** Whether the ID field is generated, or comes from the XML content */
1542 : bool m_bIDFieldIsGenerated = false;
1543 : /** Pointer to parent layer */
1544 : OGRGMLASLayer *m_poParentLayer = nullptr;
1545 : /** OGR field index of the field that points to the parent ID */
1546 : int m_nParentIDFieldIdx = -1;
1547 :
1548 : std::map<CPLString, CPLString> m_oMapSWEFieldToOGRFieldName{};
1549 :
1550 : OGRFeature *GetNextRawFeature();
1551 :
1552 : bool InitReader();
1553 :
1554 14207 : void SetLayerDefnFinalized(bool bVal)
1555 : {
1556 14207 : m_bLayerDefnFinalized = bVal;
1557 14207 : }
1558 :
1559 : CPLString LaunderFieldName(const CPLString &osFieldName);
1560 :
1561 : CPLString GetXPathFromOGRFieldIndex(int nIdx) const;
1562 :
1563 : CPL_DISALLOW_COPY_ASSIGN(OGRGMLASLayer)
1564 :
1565 : public:
1566 : OGRGMLASLayer(OGRGMLASDataSource *poDS, const GMLASFeatureClass &oFC,
1567 : OGRGMLASLayer *poParentLayer, bool bAlwaysGenerateOGRPKId);
1568 : explicit OGRGMLASLayer(const char *pszLayerName);
1569 : virtual ~OGRGMLASLayer();
1570 :
1571 310791 : virtual const char *GetName() override
1572 : {
1573 310791 : return GetDescription();
1574 : }
1575 :
1576 : virtual OGRFeatureDefn *GetLayerDefn() override;
1577 : virtual void ResetReading() override;
1578 : virtual OGRFeature *GetNextFeature() override;
1579 :
1580 919 : virtual int TestCapability(const char *) override
1581 : {
1582 919 : return FALSE;
1583 : }
1584 :
1585 3 : void SetDataSource(OGRGMLASDataSource *poDS)
1586 : {
1587 3 : m_poDS = poDS;
1588 3 : }
1589 :
1590 : void PostInit(bool bIncludeGeometryXML);
1591 : void
1592 : ProcessDataRecordCreateFields(CPLXMLNode *psDataRecord,
1593 : const std::vector<OGRFeature *> &apoFeatures,
1594 : OGRLayer *poFieldsMetadataLayer);
1595 : void ProcessDataRecordFillFeature(CPLXMLNode *psDataRecord,
1596 : OGRFeature *poFeature);
1597 : void
1598 : ProcessDataRecordOfDataArrayCreateFields(OGRGMLASLayer *poParentLayer,
1599 : CPLXMLNode *psDataRecord,
1600 : OGRLayer *poFieldsMetadataLayer);
1601 : void CreateCompoundFoldedMappings();
1602 :
1603 22004000 : const GMLASFeatureClass &GetFeatureClass() const
1604 : {
1605 22004000 : return m_oFC;
1606 : }
1607 :
1608 : int GetOGRFieldIndexFromXPath(const CPLString &osXPath) const;
1609 : int GetOGRGeomFieldIndexFromXPath(const CPLString &osXPath) const;
1610 :
1611 190130 : int GetIDFieldIdx() const
1612 : {
1613 190130 : return m_nIDFieldIdx;
1614 : }
1615 :
1616 52459 : bool IsGeneratedIDField() const
1617 : {
1618 52459 : return m_bIDFieldIsGenerated;
1619 : }
1620 :
1621 109441 : OGRGMLASLayer *GetParent()
1622 : {
1623 109441 : return m_poParentLayer;
1624 : }
1625 :
1626 90567 : int GetParentIDFieldIdx() const
1627 : {
1628 90567 : return m_nParentIDFieldIdx;
1629 : }
1630 :
1631 : int GetFCFieldIndexFromOGRFieldIdx(int iOGRFieldIdx) const;
1632 : int GetFCFieldIndexFromOGRGeomFieldIdx(int iOGRGeomFieldIdx) const;
1633 : int GetFCFieldIndexFromXPath(const CPLString &osXPath) const;
1634 :
1635 : bool EvaluateFilter(OGRFeature *poFeature);
1636 :
1637 : bool RemoveField(int nIdx);
1638 : void InsertNewField(int nInsertPos, const OGRFieldDefn &oFieldDefn,
1639 : const CPLString &osXPath);
1640 :
1641 : CPLString
1642 : GetXPathOfFieldLinkForAttrToOtherLayer(const CPLString &osFieldName,
1643 : const CPLString &osTargetLayerXPath);
1644 : CPLString
1645 : CreateLinkForAttrToOtherLayer(const CPLString &osFieldName,
1646 : const CPLString &osTargetLayerXPath);
1647 : };
1648 :
1649 : /************************************************************************/
1650 : /* GMLASReader */
1651 : /************************************************************************/
1652 :
1653 : class GMLASReader final : public DefaultHandler
1654 : {
1655 : /** Schema cache */
1656 : GMLASXSDCache &m_oCache;
1657 :
1658 : /** Object to tell if a XPath must be ignored */
1659 : const GMLASXPathMatcher &m_oIgnoredXPathMatcher;
1660 :
1661 : /** XLink resolver */
1662 : GMLASXLinkResolver &m_oXLinkResolver;
1663 :
1664 : /** Whether we should stop parsing */
1665 : bool m_bParsingError = false;
1666 :
1667 : /** Xerces reader object */
1668 : std::unique_ptr<SAX2XMLReader> m_poSAXReader{};
1669 :
1670 : /** Token for Xerces */
1671 : XMLPScanToken m_oToFill{};
1672 :
1673 : /** File descriptor */
1674 : std::shared_ptr<VSIVirtualHandle> m_fp{};
1675 :
1676 : /** Input source */
1677 : std::unique_ptr<GMLASInputSource> m_GMLInputSource{};
1678 :
1679 : /** Whether we are at the first iteration */
1680 : bool m_bFirstIteration = true;
1681 :
1682 : /** Whether we have reached end of file (or an error) */
1683 : bool m_bEOF = false;
1684 :
1685 : /** Whether GetNextFeature() has been user interrupted (progress cbk) */
1686 : bool m_bInterrupted = false;
1687 :
1688 : /** Error handler (for Xerces reader) */
1689 : GMLASErrorHandler m_oErrorHandler{};
1690 :
1691 : /** Map URI namespaces to their prefix */
1692 : std::map<CPLString, CPLString> m_oMapURIToPrefix{};
1693 :
1694 : /** List of OGR layers */
1695 : std::vector<std::unique_ptr<OGRGMLASLayer>> *m_apoLayers = nullptr;
1696 :
1697 : /** Vector of features ready for consumption */
1698 : std::list<std::pair<std::unique_ptr<OGRFeature>, OGRGMLASLayer *>>
1699 : m_aoFeaturesReady{};
1700 :
1701 : /** OGR field index of the current field */
1702 : int m_nCurFieldIdx = -1;
1703 :
1704 : /** OGR geometry field index of the current field */
1705 : int m_nCurGeomFieldIdx = -1;
1706 :
1707 : /** XML nested level of current field */
1708 : int m_nCurFieldLevel = 0;
1709 :
1710 : /** Whether we should store all content of the current field as XML */
1711 : bool m_bIsXMLBlob = false;
1712 : bool m_bIsXMLBlobIncludeUpper = false;
1713 :
1714 : /** Content of the current field */
1715 : CPLString m_osTextContent{};
1716 :
1717 : /** For list field types, list of content */
1718 : CPLStringList m_osTextContentList{};
1719 : /** Estimated memory footprint of m_osTextContentList */
1720 : size_t m_nTextContentListEstimatedSize = 0;
1721 :
1722 : /** Which layer is of interest for the reader, or NULL for all */
1723 : OGRGMLASLayer *m_poLayerOfInterest = nullptr;
1724 :
1725 : /** Stack of length of split XPath components */
1726 : std::vector<size_t> m_anStackXPathLength{};
1727 :
1728 : /** Current absolute XPath */
1729 : CPLString m_osCurXPath{};
1730 :
1731 : /** Current XPath, relative to top-level feature */
1732 : CPLString m_osCurSubXPath{};
1733 :
1734 : /** Current XML nesting level */
1735 : int m_nLevel = 0;
1736 :
1737 : /** Whether we are in a gml:boundedBy element at level 1 */
1738 : bool m_bInGMLBoundedByLevel1 = false;
1739 :
1740 : /** Default value for srsDimension attribute. */
1741 : int m_nDefaultSrsDimension = 0;
1742 :
1743 : /** Map layer to global FID */
1744 : std::map<OGRLayer *, int> m_oMapGlobalCounter{};
1745 :
1746 : /** Parsing context */
1747 : struct Context
1748 : {
1749 : /** XML nesting level */
1750 : int m_nLevel = 0;
1751 :
1752 : /** Current feature */
1753 : OGRFeature *m_poFeature = nullptr;
1754 :
1755 : /** Layer of m_poFeature */
1756 : OGRGMLASLayer *m_poLayer = nullptr;
1757 :
1758 : /** Current layer in a repeated group */
1759 : OGRGMLASLayer *m_poGroupLayer = nullptr;
1760 :
1761 : /** Nesting level of m_poCurGroupLayer */
1762 : int m_nGroupLayerLevel = -1;
1763 :
1764 : /** Index of the last processed OGR field in m_poCurGroupLayer */
1765 : int m_nLastFieldIdxGroupLayer = -1;
1766 :
1767 : /** Map layer to local FID */
1768 : std::map<OGRLayer *, int> m_oMapCounter{};
1769 :
1770 : /** Current XPath, relative to (current) top-level feature */
1771 : CPLString m_osCurSubXPath{};
1772 :
1773 : void Dump() const;
1774 : };
1775 :
1776 : /** Current context */
1777 : Context m_oCurCtxt{};
1778 :
1779 : /** Stack of saved contexts */
1780 : std::vector<Context> m_aoStackContext{};
1781 :
1782 : /** Context used in m_apsXMLNodeStack */
1783 : struct NodeLastChild
1784 : {
1785 : /** Current node */
1786 : CPLXMLNode *psNode = nullptr;
1787 :
1788 : /** Last child of psNode (for fast append operations) */
1789 : CPLXMLNode *psLastChild = nullptr;
1790 : };
1791 :
1792 : /** Stack of contexts to build XML tree of GML Geometry */
1793 : std::vector<NodeLastChild> m_apsXMLNodeStack{};
1794 :
1795 : /** Maximum allowed number of XML nesting level */
1796 : int m_nMaxLevel = 100;
1797 :
1798 : /** Maximum allowed size of XML content in byte */
1799 : size_t m_nMaxContentSize = 512000000;
1800 :
1801 : /** Map from a SRS name to a boolean indicating if its coordinate
1802 : order is inverted. */
1803 : std::map<CPLString, bool> m_oMapSRSNameToInvertedAxis{};
1804 :
1805 : /** Set of geometry fields with unknown SRS */
1806 : std::set<OGRGeomFieldDefn *> m_oSetGeomFieldsWithUnknownSRS{};
1807 :
1808 : /** Map from geometry field definition to its expected SRSName.
1809 : This is used to know if reprojection must be done */
1810 : std::map<OGRGeomFieldDefn *, CPLString> m_oMapGeomFieldDefnToSRSName{};
1811 :
1812 : /** Whether this parsing involves schema validation */
1813 : bool m_bValidate = false;
1814 :
1815 : /** Entity resolver used during schema validation */
1816 : std::unique_ptr<GMLASBaseEntityResolver> m_poEntityResolver{};
1817 :
1818 : /** First level from which warnings about ignored XPath should be
1819 : silent. */
1820 : int m_nLevelSilentIgnoredXPath = -1;
1821 :
1822 : /** Whether a warning should be emitted when an element or attribute is
1823 : found in the document parsed, but ignored because of the ignored
1824 : XPath defined. */
1825 : std::map<CPLString, bool> m_oMapIgnoredXPathToWarn{};
1826 :
1827 : /** Policy to decide when to invert coordinates */
1828 : GMLASSwapCoordinatesEnum m_eSwapCoordinates = GMLAS_SWAP_AUTO;
1829 :
1830 : /** Initial pass to guess SRS, etc... */
1831 : bool m_bInitialPass = false;
1832 :
1833 : /** Whether to process swe:DataArray in a special way */
1834 : bool m_bProcessSWEDataArray = false;
1835 :
1836 : /** Whether to process swe:DataArray in a special way */
1837 : bool m_bProcessSWEDataRecord = false;
1838 :
1839 : /** Depth level of the swe:DataArray element */
1840 : int m_nSWEDataArrayLevel = -1;
1841 :
1842 : /** Field name to which the DataArray belongs to */
1843 : CPLString m_osSWEDataArrayParentField{};
1844 :
1845 : /** Depth level of the swe:DataRecord element */
1846 : int m_nSWEDataRecordLevel = -1;
1847 :
1848 : OGRLayer *m_poFieldsMetadataLayer = nullptr;
1849 : OGRLayer *m_poLayersMetadataLayer = nullptr;
1850 : OGRLayer *m_poRelationshipsLayer = nullptr;
1851 :
1852 : /** Base unique identifier */
1853 : CPLString m_osHash{};
1854 :
1855 : vsi_l_offset m_nFileSize = 0;
1856 :
1857 : bool m_bWarnUnexpected = false;
1858 :
1859 : /** Map from layer to a map of field XPath to a set of matching
1860 : URL specific resolution rule index */
1861 : std::map<OGRGMLASLayer *, std::map<CPLString, std::set<int>>>
1862 : m_oMapXLinkFields{};
1863 :
1864 : /** Variables that could be local but more efficient to have same
1865 : persistent, so as to save many memory allocations/deallocations */
1866 : CPLString m_osLocalname{};
1867 : CPLString m_osNSUri{};
1868 : CPLString m_osNSPrefix{};
1869 : CPLString m_osXPath{};
1870 : CPLString m_osLayerXPath{};
1871 : CPLString m_osAttrNSUri{};
1872 : CPLString m_osAttrNSPrefix{};
1873 : CPLString m_osAttrLocalName{};
1874 : CPLString m_osAttrXPath{};
1875 : CPLString m_osAttrValue{};
1876 : CPLString m_osText{};
1877 :
1878 : std::vector<OGRGMLASLayer *> m_apoSWEDataArrayLayersRef{};
1879 : std::vector<std::unique_ptr<OGRGMLASLayer>> m_apoSWEDataArrayLayersOwned{};
1880 :
1881 : int m_nSWEDataArrayLayerIdx = 0;
1882 :
1883 : /* Set of 3 maps used for xlink:href="#xxxx" internal links resolution */
1884 : /* 1) map the ID attribute to its belonging layer, e.g foo.1 -> layer Foo */
1885 : std::map<CPLString, OGRGMLASLayer *> m_oMapElementIdToLayer{};
1886 : /* 2) map the ID attribute to the feature PKID (when different from itself)
1887 : */
1888 : std::map<CPLString, CPLString> m_oMapElementIdToPKID{};
1889 : /* 3) map each (layer, field_xpath) to the list of ID it refers to */
1890 : /* e.g (layer Bar, field_xpath) -> [foo.1, foo.2] */
1891 : std::map<std::pair<OGRGMLASLayer *, CPLString>, std::vector<CPLString>>
1892 : m_oMapFieldXPathToLinkValue{};
1893 :
1894 : void SetField(OGRFeature *poFeature, OGRGMLASLayer *poLayer, int nAttrIdx,
1895 : const CPLString &osAttrValue);
1896 :
1897 : void CreateNewFeature(const CPLString &osLocalname);
1898 :
1899 : void PushFeatureReady(std::unique_ptr<OGRFeature> &&,
1900 : OGRGMLASLayer *poLayer);
1901 :
1902 : void PushContext(const Context &oContext);
1903 : void PopContext();
1904 :
1905 : void BuildXMLBlobStartElement(const CPLString &osXPath,
1906 : const Attributes &attrs);
1907 :
1908 : OGRGMLASLayer *GetLayerByXPath(const CPLString &osXPath);
1909 :
1910 : void AttachAsLastChild(CPLXMLNode *psNode);
1911 :
1912 : void ProcessSWEDataArray(CPLXMLNode *psRoot);
1913 : void ProcessSWEDataRecord(CPLXMLNode *psRoot);
1914 : void ProcessGeometry(CPLXMLNode *psRoot);
1915 :
1916 : void ProcessAttributes(const Attributes &attrs);
1917 : void ProcessXLinkHref(int nAttrIdx, const CPLString &osAttrXPath,
1918 : const CPLString &osAttrValue);
1919 : void
1920 : ExploreXMLDoc(const CPLString &osAttrXPath,
1921 : const GMLASXLinkResolutionConf::URLSpecificResolution &oRule,
1922 : CPLXMLNode *psNode, const CPLString &osParentXPath,
1923 : const GMLASXPathMatcher &oMatcher,
1924 : const std::map<CPLString, size_t> &oMapFieldXPathToIdx);
1925 :
1926 : void CreateFieldsForURLSpecificRules();
1927 : void CreateFieldsForURLSpecificRule(
1928 : OGRGMLASLayer *poLayer, int nFieldIdx, const CPLString &osFieldXPath,
1929 : int &nInsertFieldIdx,
1930 : const GMLASXLinkResolutionConf::URLSpecificResolution &oRule);
1931 :
1932 319435 : bool FillTextContent() const
1933 : {
1934 319435 : return !m_bInitialPass && m_nCurFieldIdx >= 0;
1935 : }
1936 :
1937 : void ProcessInternalXLinkFirstPass(
1938 : bool bRemoveUnusedFields,
1939 : std::map<OGRGMLASLayer *, std::set<CPLString>> &oMapUnusedFields);
1940 :
1941 : CPL_DISALLOW_COPY_ASSIGN(GMLASReader)
1942 :
1943 : public:
1944 : GMLASReader(GMLASXSDCache &oCache,
1945 : const GMLASXPathMatcher &oIgnoredXPathMatcher,
1946 : GMLASXLinkResolver &oXLinkResolver);
1947 : ~GMLASReader();
1948 :
1949 : bool Init(const char *pszFilename,
1950 : const std::shared_ptr<VSIVirtualHandle> &fp,
1951 : const std::map<CPLString, CPLString> &oMapURIToPrefix,
1952 : std::vector<std::unique_ptr<OGRGMLASLayer>> &apoLayers,
1953 : bool bValidate, const std::vector<PairURIFilename> &aoXSDs,
1954 : bool bSchemaFullChecking, bool bHandleMultipleImports);
1955 :
1956 : void SetLayerOfInterest(OGRGMLASLayer *poLayer);
1957 :
1958 1379 : void SetMapIgnoredXPathToWarn(const std::map<CPLString, bool> &oMap)
1959 : {
1960 1379 : m_oMapIgnoredXPathToWarn = oMap;
1961 1379 : }
1962 :
1963 1272 : void SetSwapCoordinates(GMLASSwapCoordinatesEnum eVal)
1964 : {
1965 1272 : m_eSwapCoordinates = eVal;
1966 1272 : }
1967 :
1968 38 : const std::shared_ptr<VSIVirtualHandle> &GetFP() const
1969 : {
1970 38 : return m_fp;
1971 : }
1972 :
1973 107 : const std::map<CPLString, bool> &GetMapSRSNameToInvertedAxis() const
1974 : {
1975 107 : return m_oMapSRSNameToInvertedAxis;
1976 : }
1977 :
1978 1259 : void SetMapSRSNameToInvertedAxis(const std::map<CPLString, bool> &oMap)
1979 : {
1980 1259 : m_oMapSRSNameToInvertedAxis = oMap;
1981 1259 : }
1982 :
1983 : const std::map<OGRGeomFieldDefn *, CPLString> &
1984 107 : GetMapGeomFieldDefnToSRSName() const
1985 : {
1986 107 : return m_oMapGeomFieldDefnToSRSName;
1987 : }
1988 :
1989 1259 : void SetMapGeomFieldDefnToSRSName(
1990 : const std::map<OGRGeomFieldDefn *, CPLString> &oMap)
1991 : {
1992 1259 : m_oMapGeomFieldDefnToSRSName = oMap;
1993 1259 : }
1994 :
1995 107 : const std::map<CPLString, OGRGMLASLayer *> &GetMapElementIdToLayer() const
1996 : {
1997 107 : return m_oMapElementIdToLayer;
1998 : }
1999 :
2000 : void
2001 1259 : SetMapElementIdToLayer(const std::map<CPLString, OGRGMLASLayer *> &oMap)
2002 : {
2003 1259 : m_oMapElementIdToLayer = oMap;
2004 1259 : }
2005 :
2006 107 : const std::map<CPLString, CPLString> &GetMapElementIdToPKID() const
2007 : {
2008 107 : return m_oMapElementIdToPKID;
2009 : }
2010 :
2011 1259 : void SetMapElementIdToPKID(const std::map<CPLString, CPLString> &oMap)
2012 : {
2013 1259 : m_oMapElementIdToPKID = oMap;
2014 1259 : }
2015 :
2016 107 : int GetDefaultSrsDimension() const
2017 : {
2018 107 : return m_nDefaultSrsDimension;
2019 : }
2020 :
2021 1259 : void SetDefaultSrsDimension(int nDim)
2022 : {
2023 1259 : m_nDefaultSrsDimension = nDim;
2024 1259 : }
2025 :
2026 1379 : void SetHash(const CPLString &osHash)
2027 : {
2028 1379 : m_osHash = osHash;
2029 1379 : }
2030 :
2031 1379 : void SetFileSize(vsi_l_offset nFileSize)
2032 : {
2033 1379 : m_nFileSize = nFileSize;
2034 1379 : }
2035 :
2036 : OGRFeature *GetNextFeature(OGRGMLASLayer **ppoBelongingLayer = nullptr,
2037 : GDALProgressFunc pfnProgress = nullptr,
2038 : void *pProgressData = nullptr);
2039 :
2040 : virtual void startElement(const XMLCh *const uri,
2041 : const XMLCh *const localname,
2042 : const XMLCh *const qname,
2043 : const Attributes &attrs) override;
2044 : virtual void endElement(const XMLCh *const uri,
2045 : const XMLCh *const localname,
2046 : const XMLCh *const qname) override;
2047 :
2048 : virtual void characters(const XMLCh *const chars,
2049 : const XMLSize_t length) override;
2050 :
2051 : bool RunFirstPass(GDALProgressFunc pfnProgress, void *pProgressData,
2052 : bool bRemoveUnusedLayers, bool bRemoveUnusedFields,
2053 : bool bProcessSWEDataArray,
2054 : OGRLayer *poFieldsMetadataLayer,
2055 : OGRLayer *poLayersMetadataLayer,
2056 : OGRLayer *poRelationshipsLayer,
2057 : std::set<CPLString> &aoSetRemovedLayerNames);
2058 :
2059 : static bool LoadXSDInParser(SAX2XMLReader *poParser, GMLASXSDCache &oCache,
2060 : GMLASBaseEntityResolver &oXSDEntityResolver,
2061 : const CPLString &osBaseDirname,
2062 : const CPLString &osXSDFilename,
2063 : Grammar **ppoGrammar, bool bSchemaFullChecking,
2064 : bool bHandleMultipleImports);
2065 :
2066 : void SetSWEDataArrayLayersRef(const std::vector<OGRGMLASLayer *> &ar);
2067 :
2068 1366 : void SetProcessDataRecord(bool b)
2069 : {
2070 1366 : m_bProcessSWEDataRecord = b;
2071 1366 : }
2072 :
2073 107 : std::vector<std::unique_ptr<OGRGMLASLayer>> StealSWEDataArrayLayersOwned()
2074 : {
2075 107 : return std::move(m_apoSWEDataArrayLayersOwned);
2076 : }
2077 : };
2078 :
2079 : CPLString OGRGMLASTruncateIdentifier(const CPLString &osName,
2080 : int nIdentMaxLength);
2081 :
2082 : CPLString OGRGMLASAddSerialNumber(const CPLString &osNameIn, int iOccurrence,
2083 : size_t nOccurrences, int nIdentMaxLength);
2084 :
2085 : #endif // OGR_GMLAS_INCLUDED
|