LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gmlas - ogr_gmlas.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 323 323 100.0 %
Date: 2024-11-21 22:18:42 Functions: 135 136 99.3 %

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

Generated by: LCOV version 1.14