/src/gdal/ogr/ogrsf_frmts/gmlas/ogrgmlasdatasource.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * Project: OGR |
3 | | * Purpose: OGRGMLASDriver implementation |
4 | | * Author: Even Rouault, <even dot rouault at spatialys dot com> |
5 | | * |
6 | | * Initial development funded by the European Earth observation programme |
7 | | * Copernicus |
8 | | * |
9 | | ****************************************************************************** |
10 | | * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com> |
11 | | * |
12 | | * SPDX-License-Identifier: MIT |
13 | | ****************************************************************************/ |
14 | | |
15 | | #include "ogr_gmlas.h" |
16 | | |
17 | | #include "memdataset.h" |
18 | | #include "cpl_sha256.h" |
19 | | |
20 | | #include <algorithm> |
21 | | |
22 | | /************************************************************************/ |
23 | | /* XercesInitializer::XercesInitializer() */ |
24 | | /************************************************************************/ |
25 | | |
26 | | OGRGMLASDataSource::XercesInitializer::XercesInitializer() |
27 | 766 | { |
28 | 766 | OGRInitializeXerces(); |
29 | 766 | } |
30 | | |
31 | | /************************************************************************/ |
32 | | /* XercesInitializer::~XercesInitializer() */ |
33 | | /************************************************************************/ |
34 | | |
35 | | OGRGMLASDataSource::XercesInitializer::~XercesInitializer() |
36 | 766 | { |
37 | 766 | OGRDeinitializeXerces(); |
38 | 766 | } |
39 | | |
40 | | /************************************************************************/ |
41 | | /* OGRGMLASDataSource() */ |
42 | | /************************************************************************/ |
43 | | |
44 | | OGRGMLASDataSource::OGRGMLASDataSource() |
45 | 766 | : m_poFieldsMetadataLayer(std::make_unique<OGRMemLayer>( |
46 | 766 | szOGR_FIELDS_METADATA, nullptr, wkbNone)), |
47 | 766 | m_poLayersMetadataLayer(std::make_unique<OGRMemLayer>( |
48 | 766 | szOGR_LAYERS_METADATA, nullptr, wkbNone)), |
49 | 766 | m_poRelationshipsLayer(std::make_unique<OGRMemLayer>( |
50 | 766 | szOGR_LAYER_RELATIONSHIPS, nullptr, wkbNone)), |
51 | 766 | m_poOtherMetadataLayer( |
52 | 766 | std::make_unique<OGRMemLayer>(szOGR_OTHER_METADATA, nullptr, wkbNone)) |
53 | 766 | { |
54 | | // Initialize m_poFieldsMetadataLayer |
55 | 766 | { |
56 | 766 | OGRFieldDefn oFieldDefn(szLAYER_NAME, OFTString); |
57 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
58 | 766 | } |
59 | 766 | { |
60 | 766 | OGRFieldDefn oFieldDefn(szFIELD_INDEX, OFTInteger); |
61 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
62 | 766 | } |
63 | 766 | { |
64 | 766 | OGRFieldDefn oFieldDefn(szFIELD_NAME, OFTString); |
65 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
66 | 766 | } |
67 | 766 | { |
68 | 766 | OGRFieldDefn oFieldDefn(szFIELD_XPATH, OFTString); |
69 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
70 | 766 | } |
71 | 766 | { |
72 | 766 | OGRFieldDefn oFieldDefn(szFIELD_TYPE, OFTString); |
73 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
74 | 766 | } |
75 | 766 | { |
76 | 766 | OGRFieldDefn oFieldDefn(szFIELD_IS_LIST, OFTInteger); |
77 | 766 | oFieldDefn.SetSubType(OFSTBoolean); |
78 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
79 | 766 | } |
80 | 766 | { |
81 | 766 | OGRFieldDefn oFieldDefn(szFIELD_MIN_OCCURS, OFTInteger); |
82 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
83 | 766 | } |
84 | 766 | { |
85 | 766 | OGRFieldDefn oFieldDefn(szFIELD_MAX_OCCURS, OFTInteger); |
86 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
87 | 766 | } |
88 | 766 | { |
89 | 766 | OGRFieldDefn oFieldDefn(szFIELD_REPETITION_ON_SEQUENCE, OFTInteger); |
90 | 766 | oFieldDefn.SetSubType(OFSTBoolean); |
91 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
92 | 766 | } |
93 | 766 | { |
94 | 766 | OGRFieldDefn oFieldDefn(szFIELD_DEFAULT_VALUE, OFTString); |
95 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
96 | 766 | } |
97 | 766 | { |
98 | 766 | OGRFieldDefn oFieldDefn(szFIELD_FIXED_VALUE, OFTString); |
99 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
100 | 766 | } |
101 | 766 | { |
102 | 766 | OGRFieldDefn oFieldDefn(szFIELD_CATEGORY, OFTString); |
103 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
104 | 766 | } |
105 | 766 | { |
106 | 766 | OGRFieldDefn oFieldDefn(szFIELD_RELATED_LAYER, OFTString); |
107 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
108 | 766 | } |
109 | 766 | { |
110 | 766 | OGRFieldDefn oFieldDefn(szFIELD_JUNCTION_LAYER, OFTString); |
111 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
112 | 766 | } |
113 | 766 | { |
114 | 766 | OGRFieldDefn oFieldDefn(szFIELD_DOCUMENTATION, OFTString); |
115 | 766 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->CreateField(&oFieldDefn)); |
116 | 766 | } |
117 | | |
118 | | // Initialize m_poLayersMetadataLayer |
119 | 766 | { |
120 | 766 | OGRFieldDefn oFieldDefn(szLAYER_NAME, OFTString); |
121 | 766 | CPL_IGNORE_RET_VAL(m_poLayersMetadataLayer->CreateField(&oFieldDefn)); |
122 | 766 | } |
123 | 766 | { |
124 | 766 | OGRFieldDefn oFieldDefn(szLAYER_XPATH, OFTString); |
125 | 766 | CPL_IGNORE_RET_VAL(m_poLayersMetadataLayer->CreateField(&oFieldDefn)); |
126 | 766 | } |
127 | 766 | { |
128 | 766 | OGRFieldDefn oFieldDefn(szLAYER_CATEGORY, OFTString); |
129 | 766 | CPL_IGNORE_RET_VAL(m_poLayersMetadataLayer->CreateField(&oFieldDefn)); |
130 | 766 | } |
131 | 766 | { |
132 | 766 | OGRFieldDefn oFieldDefn(szLAYER_PKID_NAME, OFTString); |
133 | 766 | CPL_IGNORE_RET_VAL(m_poLayersMetadataLayer->CreateField(&oFieldDefn)); |
134 | 766 | } |
135 | 766 | { |
136 | 766 | OGRFieldDefn oFieldDefn(szLAYER_PARENT_PKID_NAME, OFTString); |
137 | 766 | CPL_IGNORE_RET_VAL(m_poLayersMetadataLayer->CreateField(&oFieldDefn)); |
138 | 766 | } |
139 | 766 | { |
140 | 766 | OGRFieldDefn oFieldDefn(szLAYER_DOCUMENTATION, OFTString); |
141 | 766 | CPL_IGNORE_RET_VAL(m_poLayersMetadataLayer->CreateField(&oFieldDefn)); |
142 | 766 | } |
143 | | |
144 | | // Initialize m_poRelationshipsLayer |
145 | 766 | { |
146 | 766 | OGRFieldDefn oFieldDefn(szPARENT_LAYER, OFTString); |
147 | 766 | CPL_IGNORE_RET_VAL(m_poRelationshipsLayer->CreateField(&oFieldDefn)); |
148 | 766 | } |
149 | 766 | { |
150 | 766 | OGRFieldDefn oFieldDefn(szPARENT_PKID, OFTString); |
151 | 766 | CPL_IGNORE_RET_VAL(m_poRelationshipsLayer->CreateField(&oFieldDefn)); |
152 | 766 | } |
153 | 766 | { |
154 | 766 | OGRFieldDefn oFieldDefn(szPARENT_ELEMENT_NAME, OFTString); |
155 | 766 | CPL_IGNORE_RET_VAL(m_poRelationshipsLayer->CreateField(&oFieldDefn)); |
156 | 766 | } |
157 | 766 | { |
158 | 766 | OGRFieldDefn oFieldDefn(szCHILD_LAYER, OFTString); |
159 | 766 | CPL_IGNORE_RET_VAL(m_poRelationshipsLayer->CreateField(&oFieldDefn)); |
160 | 766 | } |
161 | 766 | { |
162 | 766 | OGRFieldDefn oFieldDefn(szCHILD_PKID, OFTString); |
163 | 766 | CPL_IGNORE_RET_VAL(m_poRelationshipsLayer->CreateField(&oFieldDefn)); |
164 | 766 | } |
165 | | |
166 | | // Initialize m_poOtherMetadataLayer |
167 | 766 | { |
168 | 766 | OGRFieldDefn oFieldDefn(szKEY, OFTString); |
169 | 766 | CPL_IGNORE_RET_VAL(m_poOtherMetadataLayer->CreateField(&oFieldDefn)); |
170 | 766 | } |
171 | 766 | { |
172 | 766 | OGRFieldDefn oFieldDefn(szVALUE, OFTString); |
173 | 766 | CPL_IGNORE_RET_VAL(m_poOtherMetadataLayer->CreateField(&oFieldDefn)); |
174 | 766 | } |
175 | 766 | } |
176 | | |
177 | | /************************************************************************/ |
178 | | /* ~OGRGMLASDataSource() */ |
179 | | /************************************************************************/ |
180 | | |
181 | | OGRGMLASDataSource::~OGRGMLASDataSource() |
182 | 766 | { |
183 | 766 | if (m_bUnlinkConfigFileAfterUse) |
184 | 766 | { |
185 | 766 | VSIUnlink(m_osConfigFile.c_str()); |
186 | 766 | } |
187 | 766 | } |
188 | | |
189 | | /************************************************************************/ |
190 | | /* GetLayerCount() */ |
191 | | /************************************************************************/ |
192 | | |
193 | | int OGRGMLASDataSource::GetLayerCount() const |
194 | 0 | { |
195 | 0 | return static_cast<int>(m_apoLayers.size() + |
196 | 0 | m_apoRequestedMetadataLayers.size()); |
197 | 0 | } |
198 | | |
199 | | /************************************************************************/ |
200 | | /* GetLayer() */ |
201 | | /************************************************************************/ |
202 | | |
203 | | const OGRLayer *OGRGMLASDataSource::GetLayer(int i) const |
204 | 0 | { |
205 | 0 | const int nBaseLayers = static_cast<int>(m_apoLayers.size()); |
206 | 0 | if (i >= nBaseLayers) |
207 | 0 | { |
208 | 0 | const_cast<OGRGMLASDataSource *>(this)->RunFirstPassIfNeeded( |
209 | 0 | nullptr, nullptr, nullptr); |
210 | 0 | if (i - nBaseLayers < |
211 | 0 | static_cast<int>(m_apoRequestedMetadataLayers.size())) |
212 | 0 | return m_apoRequestedMetadataLayers[i - nBaseLayers]; |
213 | 0 | } |
214 | | |
215 | 0 | if (i < 0 || i >= nBaseLayers) |
216 | 0 | return nullptr; |
217 | 0 | return m_apoLayers[i].get(); |
218 | 0 | } |
219 | | |
220 | | /************************************************************************/ |
221 | | /* GetLayerByName() */ |
222 | | /************************************************************************/ |
223 | | |
224 | | OGRLayer *OGRGMLASDataSource::GetLayerByName(const char *pszName) |
225 | 0 | { |
226 | 0 | if (OGRLayer *poLayer = GDALDataset::GetLayerByName(pszName)) |
227 | 0 | return poLayer; |
228 | | |
229 | 0 | OGRLayer *apoLayers[] = { |
230 | 0 | m_poFieldsMetadataLayer.get(), m_poLayersMetadataLayer.get(), |
231 | 0 | m_poRelationshipsLayer.get(), m_poOtherMetadataLayer.get()}; |
232 | 0 | for (auto *poLayer : apoLayers) |
233 | 0 | { |
234 | 0 | if (EQUAL(pszName, poLayer->GetName())) |
235 | 0 | { |
236 | 0 | if (std::find(m_apoRequestedMetadataLayers.begin(), |
237 | 0 | m_apoRequestedMetadataLayers.end(), |
238 | 0 | poLayer) == m_apoRequestedMetadataLayers.end()) |
239 | 0 | { |
240 | 0 | m_apoRequestedMetadataLayers.push_back(poLayer); |
241 | 0 | } |
242 | 0 | RunFirstPassIfNeeded(nullptr, nullptr, nullptr); |
243 | 0 | return poLayer; |
244 | 0 | } |
245 | 0 | } |
246 | | |
247 | 0 | return nullptr; |
248 | 0 | } |
249 | | |
250 | | /************************************************************************/ |
251 | | /* TranslateClasses() */ |
252 | | /************************************************************************/ |
253 | | |
254 | | void OGRGMLASDataSource::TranslateClasses(OGRGMLASLayer *poParentLayer, |
255 | | const GMLASFeatureClass &oFC) |
256 | 0 | { |
257 | 0 | const std::vector<GMLASFeatureClass> &aoClasses = oFC.GetNestedClasses(); |
258 | | |
259 | | // CPLDebug("GMLAS", "TranslateClasses(%s,%s)", |
260 | | // oFC.GetName().c_str(), oFC.GetXPath().c_str()); |
261 | |
|
262 | 0 | m_apoLayers.emplace_back(std::make_unique<OGRGMLASLayer>( |
263 | 0 | this, oFC, poParentLayer, m_oConf.m_bAlwaysGenerateOGRId)); |
264 | 0 | auto poLayer = m_apoLayers.back().get(); |
265 | |
|
266 | 0 | for (size_t i = 0; i < aoClasses.size(); ++i) |
267 | 0 | { |
268 | 0 | TranslateClasses(poLayer, aoClasses[i]); |
269 | 0 | } |
270 | 0 | } |
271 | | |
272 | | /************************************************************************/ |
273 | | /* GMLASTopElementParser */ |
274 | | /************************************************************************/ |
275 | | |
276 | | class GMLASTopElementParser : public DefaultHandler |
277 | | { |
278 | | std::vector<PairURIFilename> m_aoFilenames{}; |
279 | | int m_nStartElementCounter = 0; |
280 | | bool m_bFinish = false; |
281 | | bool m_bFoundSWE = false; |
282 | | std::map<CPLString, CPLString> m_oMapDocNSURIToPrefix{}; |
283 | | |
284 | | public: |
285 | 473 | GMLASTopElementParser() = default; |
286 | | |
287 | | void Parse(const CPLString &osFilename, |
288 | | const std::shared_ptr<VSIVirtualHandle> &fp); |
289 | | |
290 | | const std::vector<PairURIFilename> &GetXSDs() const |
291 | 473 | { |
292 | 473 | return m_aoFilenames; |
293 | 473 | } |
294 | | |
295 | | bool GetSWE() const |
296 | 473 | { |
297 | 473 | return m_bFoundSWE; |
298 | 473 | } |
299 | | |
300 | | const std::map<CPLString, CPLString> &GetMapDocNSURIToPrefix() const |
301 | 1.41k | { |
302 | 1.41k | return m_oMapDocNSURIToPrefix; |
303 | 1.41k | } |
304 | | |
305 | | virtual void startElement(const XMLCh *const uri, |
306 | | const XMLCh *const localname, |
307 | | const XMLCh *const qname, |
308 | | const Attributes &attrs) override; |
309 | | }; |
310 | | |
311 | | /************************************************************************/ |
312 | | /* Parse() */ |
313 | | /************************************************************************/ |
314 | | |
315 | | void GMLASTopElementParser::Parse(const CPLString &osFilename, |
316 | | const std::shared_ptr<VSIVirtualHandle> &fp) |
317 | 473 | { |
318 | 473 | auto poSAXReader = |
319 | 473 | std::unique_ptr<SAX2XMLReader>(XMLReaderFactory::createXMLReader()); |
320 | | |
321 | 473 | poSAXReader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true); |
322 | 473 | poSAXReader->setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes, true); |
323 | | |
324 | 473 | poSAXReader->setContentHandler(this); |
325 | 473 | poSAXReader->setLexicalHandler(this); |
326 | 473 | poSAXReader->setDTDHandler(this); |
327 | | |
328 | 473 | poSAXReader->setFeature(XMLUni::fgXercesLoadSchema, false); |
329 | | |
330 | 473 | GMLASErrorHandler oErrorHandler; |
331 | 473 | poSAXReader->setErrorHandler(&oErrorHandler); |
332 | | |
333 | 473 | GMLASInputSource oIS(osFilename, fp); |
334 | | |
335 | 473 | try |
336 | 473 | { |
337 | 473 | XMLPScanToken oToFill; |
338 | 473 | if (poSAXReader->parseFirst(oIS, oToFill)) |
339 | 0 | { |
340 | 0 | while (!m_bFinish && poSAXReader->parseNext(oToFill)) |
341 | 0 | { |
342 | | // do nothing |
343 | 0 | } |
344 | 0 | } |
345 | 473 | } |
346 | 473 | catch (const XMLException &toCatch) |
347 | 473 | { |
348 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "%s", |
349 | 0 | transcode(toCatch.getMessage()).c_str()); |
350 | 0 | } |
351 | 473 | catch (const SAXException &toCatch) |
352 | 473 | { |
353 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "%s", |
354 | 0 | transcode(toCatch.getMessage()).c_str()); |
355 | 0 | } |
356 | 473 | } |
357 | | |
358 | | /************************************************************************/ |
359 | | /* startElement() */ |
360 | | /************************************************************************/ |
361 | | |
362 | | void GMLASTopElementParser::startElement(const XMLCh *const /*uri*/, |
363 | | const XMLCh *const /*localname*/, |
364 | | const XMLCh *const /*qname*/, |
365 | | const Attributes &attrs) |
366 | 0 | { |
367 | 0 | m_nStartElementCounter++; |
368 | |
|
369 | 0 | for (unsigned int i = 0; i < attrs.getLength(); i++) |
370 | 0 | { |
371 | 0 | const std::string osAttrURIPrefix(transcode(attrs.getURI(i))); |
372 | 0 | const std::string osAttrLocalname(transcode(attrs.getLocalName(i))); |
373 | 0 | const std::string osAttrValue(transcode(attrs.getValue(i))); |
374 | |
|
375 | 0 | if (osAttrURIPrefix == szXSI_URI && |
376 | 0 | osAttrLocalname == szSCHEMA_LOCATION) |
377 | 0 | { |
378 | 0 | CPLDebug("GMLAS", "%s=%s", szSCHEMA_LOCATION, osAttrValue.c_str()); |
379 | |
|
380 | 0 | const CPLStringList aosTokens( |
381 | 0 | CSLTokenizeString2(osAttrValue.c_str(), " ", 0)); |
382 | 0 | const int nTokens = aosTokens.size(); |
383 | 0 | if ((nTokens % 2) == 0) |
384 | 0 | { |
385 | 0 | for (int j = 0; j < nTokens; j += 2) |
386 | 0 | { |
387 | 0 | if (!STARTS_WITH(aosTokens[j], szWFS_URI) && |
388 | 0 | !(EQUAL(aosTokens[j], szGML_URI) || |
389 | 0 | STARTS_WITH(aosTokens[j], |
390 | 0 | (CPLString(szGML_URI) + "/").c_str()))) |
391 | 0 | { |
392 | 0 | CPLDebug("GMLAS", "Schema to analyze: %s -> %s", |
393 | 0 | aosTokens[j], aosTokens[j + 1]); |
394 | 0 | m_aoFilenames.push_back( |
395 | 0 | PairURIFilename(aosTokens[j], aosTokens[j + 1])); |
396 | 0 | } |
397 | 0 | } |
398 | 0 | } |
399 | 0 | } |
400 | 0 | else if (osAttrURIPrefix == szXSI_URI && |
401 | 0 | osAttrLocalname == szNO_NAMESPACE_SCHEMA_LOCATION) |
402 | 0 | { |
403 | 0 | CPLDebug("GMLAS", "%s=%s", szNO_NAMESPACE_SCHEMA_LOCATION, |
404 | 0 | osAttrValue.c_str()); |
405 | 0 | m_aoFilenames.push_back(PairURIFilename("", osAttrValue)); |
406 | 0 | } |
407 | 0 | else if (osAttrURIPrefix == szXMLNS_URI && osAttrValue == szSWE_URI) |
408 | 0 | { |
409 | 0 | CPLDebug("GMLAS", "SWE namespace found"); |
410 | 0 | m_bFoundSWE = true; |
411 | 0 | } |
412 | 0 | else if (osAttrURIPrefix == szXMLNS_URI && !osAttrValue.empty() && |
413 | 0 | !osAttrLocalname.empty()) |
414 | 0 | { |
415 | | #ifdef DEBUG_VERBOSE |
416 | | CPLDebug("GMLAS", "Namespace %s = %s", osAttrLocalname.c_str(), |
417 | | osAttrValue.c_str()); |
418 | | #endif |
419 | 0 | m_oMapDocNSURIToPrefix[osAttrValue] = osAttrLocalname; |
420 | 0 | } |
421 | 0 | } |
422 | |
|
423 | 0 | if (m_nStartElementCounter == 1) |
424 | 0 | m_bFinish = true; |
425 | 0 | } |
426 | | |
427 | | /************************************************************************/ |
428 | | /* FillOtherMetadataLayer() */ |
429 | | /************************************************************************/ |
430 | | |
431 | | void OGRGMLASDataSource::FillOtherMetadataLayer( |
432 | | GDALOpenInfo *poOpenInfo, const CPLString &osConfigFile, |
433 | | const std::vector<PairURIFilename> &aoXSDs, |
434 | | const std::set<CPLString> &oSetSchemaURLs) |
435 | 0 | { |
436 | | // 2 "secret" options just used for tests |
437 | 0 | const bool bKeepRelativePathsForMetadata = CPLTestBool( |
438 | 0 | CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, |
439 | 0 | szKEEP_RELATIVE_PATHS_FOR_METADATA_OPTION, "NO")); |
440 | |
|
441 | 0 | const bool bExposeConfiguration = CPLTestBool( |
442 | 0 | CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, |
443 | 0 | szEXPOSE_CONFIGURATION_IN_METADATA_OPTION, "YES")); |
444 | |
|
445 | 0 | const bool bExposeSchemaNames = CPLTestBool( |
446 | 0 | CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, |
447 | 0 | szEXPOSE_SCHEMAS_NAME_IN_METADATA_OPTION, "YES")); |
448 | |
|
449 | 0 | OGRFeatureDefn *poFDefn = m_poOtherMetadataLayer->GetLayerDefn(); |
450 | |
|
451 | 0 | if (!osConfigFile.empty() && bExposeConfiguration) |
452 | 0 | { |
453 | 0 | if (STARTS_WITH(osConfigFile, "<Configuration")) |
454 | 0 | { |
455 | 0 | OGRFeature oFeature(poFDefn); |
456 | 0 | oFeature.SetField(szKEY, szCONFIGURATION_INLINED); |
457 | 0 | oFeature.SetField(szVALUE, osConfigFile.c_str()); |
458 | 0 | CPL_IGNORE_RET_VAL( |
459 | 0 | m_poOtherMetadataLayer->CreateFeature(&oFeature)); |
460 | 0 | } |
461 | 0 | else |
462 | 0 | { |
463 | 0 | { |
464 | 0 | OGRFeature oFeature(poFDefn); |
465 | 0 | oFeature.SetField(szKEY, szCONFIGURATION_FILENAME); |
466 | 0 | char *pszCurDir = CPLGetCurrentDir(); |
467 | 0 | if (!bKeepRelativePathsForMetadata && |
468 | 0 | CPLIsFilenameRelative(osConfigFile) && pszCurDir != nullptr) |
469 | 0 | { |
470 | 0 | oFeature.SetField( |
471 | 0 | szVALUE, |
472 | 0 | CPLFormFilenameSafe(pszCurDir, osConfigFile, nullptr) |
473 | 0 | .c_str()); |
474 | 0 | } |
475 | 0 | else |
476 | 0 | { |
477 | 0 | oFeature.SetField(szVALUE, osConfigFile.c_str()); |
478 | 0 | } |
479 | 0 | CPLFree(pszCurDir); |
480 | 0 | CPL_IGNORE_RET_VAL( |
481 | 0 | m_poOtherMetadataLayer->CreateFeature(&oFeature)); |
482 | 0 | } |
483 | |
|
484 | 0 | GByte *pabyRet = nullptr; |
485 | 0 | if (VSIIngestFile(nullptr, osConfigFile, &pabyRet, nullptr, -1)) |
486 | 0 | { |
487 | 0 | OGRFeature oFeature(poFDefn); |
488 | 0 | oFeature.SetField(szKEY, szCONFIGURATION_INLINED); |
489 | 0 | oFeature.SetField(szVALUE, reinterpret_cast<char *>(pabyRet)); |
490 | 0 | CPL_IGNORE_RET_VAL( |
491 | 0 | m_poOtherMetadataLayer->CreateFeature(&oFeature)); |
492 | 0 | } |
493 | 0 | VSIFree(pabyRet); |
494 | 0 | } |
495 | 0 | } |
496 | |
|
497 | 0 | const char *const apszMeaningfulOptionsToStoreInMD[] = { |
498 | 0 | szSWAP_COORDINATES_OPTION, szREMOVE_UNUSED_LAYERS_OPTION, |
499 | 0 | szREMOVE_UNUSED_FIELDS_OPTION}; |
500 | 0 | for (size_t i = 0; i < CPL_ARRAYSIZE(apszMeaningfulOptionsToStoreInMD); ++i) |
501 | 0 | { |
502 | 0 | const char *pszKey = apszMeaningfulOptionsToStoreInMD[i]; |
503 | 0 | const char *pszVal = |
504 | 0 | CSLFetchNameValue(poOpenInfo->papszOpenOptions, pszKey); |
505 | 0 | if (pszVal) |
506 | 0 | { |
507 | 0 | OGRFeature oFeature(poFDefn); |
508 | 0 | oFeature.SetField(szKEY, pszKey); |
509 | 0 | oFeature.SetField(szVALUE, pszVal); |
510 | 0 | CPL_IGNORE_RET_VAL( |
511 | 0 | m_poOtherMetadataLayer->CreateFeature(&oFeature)); |
512 | 0 | } |
513 | 0 | } |
514 | |
|
515 | 0 | CPLString osAbsoluteGMLFilename; |
516 | 0 | if (!m_osGMLFilename.empty()) |
517 | 0 | { |
518 | 0 | OGRFeature oFeature(poFDefn); |
519 | 0 | oFeature.SetField(szKEY, szDOCUMENT_FILENAME); |
520 | 0 | char *pszCurDir = CPLGetCurrentDir(); |
521 | 0 | if (!bKeepRelativePathsForMetadata && |
522 | 0 | CPLIsFilenameRelative(m_osGMLFilename) && pszCurDir != nullptr) |
523 | 0 | { |
524 | 0 | osAbsoluteGMLFilename = |
525 | 0 | CPLFormFilenameSafe(pszCurDir, m_osGMLFilename, nullptr); |
526 | 0 | } |
527 | 0 | else |
528 | 0 | osAbsoluteGMLFilename = m_osGMLFilename; |
529 | 0 | oFeature.SetField(szVALUE, osAbsoluteGMLFilename.c_str()); |
530 | 0 | CPLFree(pszCurDir); |
531 | 0 | CPL_IGNORE_RET_VAL(m_poOtherMetadataLayer->CreateFeature(&oFeature)); |
532 | 0 | } |
533 | |
|
534 | 0 | int nNSIdx = 1; |
535 | 0 | std::set<CPLString> oSetVisitedURI; |
536 | 0 | for (int i = 0; i < static_cast<int>(aoXSDs.size()); i++) |
537 | 0 | { |
538 | 0 | const CPLString osURI(aoXSDs[i].first); |
539 | 0 | const std::string osXSDFilename(aoXSDs[i].second); |
540 | |
|
541 | 0 | oSetVisitedURI.insert(osURI); |
542 | |
|
543 | 0 | if (osURI == szOGRGMLAS_URI) |
544 | 0 | continue; |
545 | | |
546 | 0 | { |
547 | 0 | OGRFeature oFeature(poFDefn); |
548 | 0 | oFeature.SetField(szKEY, CPLSPrintf(szNAMESPACE_URI_FMT, nNSIdx)); |
549 | 0 | oFeature.SetField(szVALUE, osURI.c_str()); |
550 | 0 | CPL_IGNORE_RET_VAL( |
551 | 0 | m_poOtherMetadataLayer->CreateFeature(&oFeature)); |
552 | 0 | } |
553 | |
|
554 | 0 | { |
555 | 0 | OGRFeature oFeature(poFDefn); |
556 | 0 | oFeature.SetField(szKEY, |
557 | 0 | CPLSPrintf(szNAMESPACE_LOCATION_FMT, nNSIdx)); |
558 | |
|
559 | 0 | const CPLString osAbsoluteXSDFilename( |
560 | 0 | (osXSDFilename.find("http://") != 0 && |
561 | 0 | osXSDFilename.find("https://") != 0 && |
562 | 0 | CPLIsFilenameRelative(osXSDFilename.c_str())) |
563 | 0 | ? CPLFormFilenameSafe( |
564 | 0 | CPLGetDirnameSafe(osAbsoluteGMLFilename).c_str(), |
565 | 0 | osXSDFilename.c_str(), nullptr) |
566 | 0 | : osXSDFilename); |
567 | 0 | oFeature.SetField(szVALUE, osAbsoluteXSDFilename.c_str()); |
568 | 0 | CPL_IGNORE_RET_VAL( |
569 | 0 | m_poOtherMetadataLayer->CreateFeature(&oFeature)); |
570 | 0 | } |
571 | |
|
572 | 0 | if (m_oMapURIToPrefix.find(osURI) != m_oMapURIToPrefix.end()) |
573 | 0 | { |
574 | 0 | OGRFeature oFeature(poFDefn); |
575 | 0 | oFeature.SetField(szKEY, |
576 | 0 | CPLSPrintf(szNAMESPACE_PREFIX_FMT, nNSIdx)); |
577 | 0 | oFeature.SetField(szVALUE, m_oMapURIToPrefix[osURI].c_str()); |
578 | 0 | CPL_IGNORE_RET_VAL( |
579 | 0 | m_poOtherMetadataLayer->CreateFeature(&oFeature)); |
580 | 0 | } |
581 | |
|
582 | 0 | nNSIdx++; |
583 | 0 | } |
584 | |
|
585 | 0 | for (const auto &oIter : m_oMapURIToPrefix) |
586 | 0 | { |
587 | 0 | const CPLString &osURI(oIter.first); |
588 | 0 | const CPLString &osPrefix(oIter.second); |
589 | |
|
590 | 0 | if (oSetVisitedURI.find(osURI) == oSetVisitedURI.end() && |
591 | 0 | osURI != szXML_URI && osURI != szXS_URI && osURI != szXSI_URI && |
592 | 0 | osURI != szXMLNS_URI && osURI != szOGRGMLAS_URI) |
593 | 0 | { |
594 | 0 | { |
595 | 0 | OGRFeature oFeature(poFDefn); |
596 | 0 | oFeature.SetField(szKEY, |
597 | 0 | CPLSPrintf(szNAMESPACE_URI_FMT, nNSIdx)); |
598 | 0 | oFeature.SetField(szVALUE, osURI.c_str()); |
599 | 0 | CPL_IGNORE_RET_VAL( |
600 | 0 | m_poOtherMetadataLayer->CreateFeature(&oFeature)); |
601 | 0 | } |
602 | |
|
603 | 0 | { |
604 | 0 | OGRFeature oFeature(poFDefn); |
605 | 0 | oFeature.SetField(szKEY, |
606 | 0 | CPLSPrintf(szNAMESPACE_PREFIX_FMT, nNSIdx)); |
607 | 0 | oFeature.SetField(szVALUE, osPrefix.c_str()); |
608 | 0 | CPL_IGNORE_RET_VAL( |
609 | 0 | m_poOtherMetadataLayer->CreateFeature(&oFeature)); |
610 | 0 | } |
611 | |
|
612 | 0 | nNSIdx++; |
613 | 0 | } |
614 | 0 | } |
615 | |
|
616 | 0 | if (!m_osGMLVersionFound.empty()) |
617 | 0 | { |
618 | 0 | OGRFeature oFeature(poFDefn); |
619 | 0 | oFeature.SetField(szKEY, szGML_VERSION); |
620 | 0 | oFeature.SetField(szVALUE, m_osGMLVersionFound); |
621 | 0 | CPL_IGNORE_RET_VAL(m_poOtherMetadataLayer->CreateFeature(&oFeature)); |
622 | 0 | } |
623 | |
|
624 | 0 | int nSchemaIdx = 1; |
625 | 0 | if (bExposeSchemaNames) |
626 | 0 | { |
627 | 0 | for (const auto &osSchemaURL : oSetSchemaURLs) |
628 | 0 | { |
629 | 0 | OGRFeature oFeature(poFDefn); |
630 | 0 | oFeature.SetField(szKEY, CPLSPrintf(szSCHEMA_NAME_FMT, nSchemaIdx)); |
631 | 0 | oFeature.SetField(szVALUE, osSchemaURL.c_str()); |
632 | 0 | CPL_IGNORE_RET_VAL( |
633 | 0 | m_poOtherMetadataLayer->CreateFeature(&oFeature)); |
634 | |
|
635 | 0 | nSchemaIdx++; |
636 | 0 | } |
637 | 0 | } |
638 | 0 | } |
639 | | |
640 | | /************************************************************************/ |
641 | | /* BuildXSDVector() */ |
642 | | /************************************************************************/ |
643 | | |
644 | | std::vector<PairURIFilename> |
645 | | OGRGMLASDataSource::BuildXSDVector(const CPLString &osXSDFilenames) |
646 | 0 | { |
647 | 0 | std::vector<PairURIFilename> aoXSDs; |
648 | 0 | char **papszTokens = CSLTokenizeString2(osXSDFilenames, ",", 0); |
649 | 0 | char *pszCurDir = CPLGetCurrentDir(); |
650 | 0 | for (int i = 0; papszTokens != nullptr && papszTokens[i] != nullptr; i++) |
651 | 0 | { |
652 | 0 | if (!STARTS_WITH(papszTokens[i], "http://") && |
653 | 0 | !STARTS_WITH(papszTokens[i], "https://") && |
654 | 0 | CPLIsFilenameRelative(papszTokens[i]) && pszCurDir != nullptr) |
655 | 0 | { |
656 | 0 | aoXSDs.push_back(PairURIFilename( |
657 | 0 | "", CPLFormFilenameSafe(pszCurDir, papszTokens[i], nullptr) |
658 | 0 | .c_str())); |
659 | 0 | } |
660 | 0 | else |
661 | 0 | { |
662 | 0 | aoXSDs.push_back(PairURIFilename("", papszTokens[i])); |
663 | 0 | } |
664 | 0 | } |
665 | 0 | CPLFree(pszCurDir); |
666 | 0 | CSLDestroy(papszTokens); |
667 | 0 | return aoXSDs; |
668 | 0 | } |
669 | | |
670 | | /************************************************************************/ |
671 | | /* Open() */ |
672 | | /************************************************************************/ |
673 | | |
674 | | bool OGRGMLASDataSource::Open(GDALOpenInfo *poOpenInfo) |
675 | 766 | { |
676 | 766 | m_osConfigFile = CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, |
677 | 766 | szCONFIG_FILE_OPTION, ""); |
678 | 766 | if (m_osConfigFile.empty()) |
679 | 766 | { |
680 | 766 | m_osConfigFile = |
681 | 766 | GMLASConfiguration::GetDefaultConfFile(m_bUnlinkConfigFileAfterUse); |
682 | 766 | } |
683 | 766 | if (m_osConfigFile.empty()) |
684 | 0 | { |
685 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
686 | 0 | "No configuration file found. Using hard-coded defaults"); |
687 | 0 | m_oConf.Finalize(); |
688 | 0 | } |
689 | 766 | else |
690 | 766 | { |
691 | 766 | if (!m_oConf.Load(m_osConfigFile.c_str())) |
692 | 0 | { |
693 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
694 | 0 | "Loading of configuration failed"); |
695 | 0 | return false; |
696 | 0 | } |
697 | 766 | } |
698 | | |
699 | 766 | m_oCache.SetCacheDirectory(m_oConf.m_osXSDCacheDirectory); |
700 | 766 | const bool bRefreshCache(CPLTestBool(CSLFetchNameValueDef( |
701 | 766 | poOpenInfo->papszOpenOptions, szREFRESH_CACHE_OPTION, "NO"))); |
702 | 766 | m_oCache.SetRefreshMode(bRefreshCache); |
703 | 766 | m_oCache.SetAllowDownload(m_oConf.m_bAllowRemoteSchemaDownload); |
704 | | |
705 | 766 | m_oIgnoredXPathMatcher.SetRefXPaths(m_oConf.m_oMapPrefixToURIIgnoredXPaths, |
706 | 766 | m_oConf.m_aosIgnoredXPaths); |
707 | | |
708 | 766 | { |
709 | 766 | std::vector<CPLString> oVector; |
710 | 766 | for (const auto &oIter : m_oConf.m_oMapChildrenElementsConstraints) |
711 | 766 | oVector.push_back(oIter.first); |
712 | 766 | m_oChildrenElementsConstraintsXPathMatcher.SetRefXPaths( |
713 | 766 | m_oConf.m_oMapPrefixToURITypeConstraints, oVector); |
714 | 766 | } |
715 | | |
716 | 766 | m_oForcedFlattenedXPathMatcher.SetRefXPaths( |
717 | 766 | m_oConf.m_oMapPrefixToURIFlatteningRules, |
718 | 766 | m_oConf.m_osForcedFlattenedXPath); |
719 | | |
720 | 766 | m_oDisabledFlattenedXPathMatcher.SetRefXPaths( |
721 | 766 | m_oConf.m_oMapPrefixToURIFlatteningRules, |
722 | 766 | m_oConf.m_osDisabledFlattenedXPath); |
723 | | |
724 | 766 | GMLASSchemaAnalyzer oAnalyzer( |
725 | 766 | m_oIgnoredXPathMatcher, m_oChildrenElementsConstraintsXPathMatcher, |
726 | 766 | m_oConf.m_oMapChildrenElementsConstraints, |
727 | 766 | m_oForcedFlattenedXPathMatcher, m_oDisabledFlattenedXPathMatcher); |
728 | 766 | oAnalyzer.SetUseArrays(m_oConf.m_bUseArrays); |
729 | 766 | oAnalyzer.SetUseNullState(m_oConf.m_bUseNullState); |
730 | 766 | oAnalyzer.SetInstantiateGMLFeaturesOnly( |
731 | 766 | m_oConf.m_bInstantiateGMLFeaturesOnly); |
732 | 766 | oAnalyzer.SetIdentifierMaxLength(m_oConf.m_nIdentifierMaxLength); |
733 | 766 | oAnalyzer.SetCaseInsensitiveIdentifier( |
734 | 766 | m_oConf.m_bCaseInsensitiveIdentifier); |
735 | 766 | oAnalyzer.SetPGIdentifierLaundering(m_oConf.m_bPGIdentifierLaundering); |
736 | 766 | oAnalyzer.SetMaximumFieldsForFlattening( |
737 | 766 | m_oConf.m_nMaximumFieldsForFlattening); |
738 | 766 | oAnalyzer.SetAlwaysGenerateOGRId(m_oConf.m_bAlwaysGenerateOGRId); |
739 | | |
740 | 766 | m_osGMLFilename = STARTS_WITH_CI(poOpenInfo->pszFilename, szGMLAS_PREFIX) |
741 | 766 | ? CPLExpandTildeSafe(poOpenInfo->pszFilename + |
742 | 766 | strlen(szGMLAS_PREFIX)) |
743 | 766 | : poOpenInfo->pszFilename; |
744 | | |
745 | 766 | CPLString osXSDFilenames = |
746 | 766 | CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, szXSD_OPTION, ""); |
747 | | |
748 | 766 | std::shared_ptr<VSIVirtualHandle> fpGML; |
749 | 766 | if (!m_osGMLFilename.empty()) |
750 | 766 | { |
751 | 766 | fpGML.reset(VSIFOpenL(m_osGMLFilename, "rb"), VSIVirtualHandleCloser{}); |
752 | 766 | if (fpGML == nullptr) |
753 | 293 | { |
754 | 293 | CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", |
755 | 293 | m_osGMLFilename.c_str()); |
756 | 293 | return false; |
757 | 293 | } |
758 | 766 | } |
759 | 0 | else if (osXSDFilenames.empty()) |
760 | 0 | { |
761 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
762 | 0 | "%s open option must be provided when no " |
763 | 0 | "XML data file is passed", |
764 | 0 | szXSD_OPTION); |
765 | 0 | return false; |
766 | 0 | } |
767 | | |
768 | 473 | GMLASTopElementParser topElementParser; |
769 | 473 | if (!m_osGMLFilename.empty()) |
770 | 473 | { |
771 | 473 | topElementParser.Parse(m_osGMLFilename, fpGML); |
772 | 473 | if (m_oConf.m_eSWEActivationMode == |
773 | 473 | GMLASConfiguration::SWE_ACTIVATE_IF_NAMESPACE_FOUND) |
774 | 473 | { |
775 | 473 | m_bFoundSWE = topElementParser.GetSWE(); |
776 | 473 | } |
777 | 0 | else if (m_oConf.m_eSWEActivationMode == |
778 | 0 | GMLASConfiguration::SWE_ACTIVATE_TRUE) |
779 | 0 | { |
780 | 0 | m_bFoundSWE = true; |
781 | 0 | } |
782 | 473 | oAnalyzer.SetMapDocNSURIToPrefix( |
783 | 473 | topElementParser.GetMapDocNSURIToPrefix()); |
784 | 473 | } |
785 | 473 | std::vector<PairURIFilename> aoXSDs; |
786 | 473 | if (osXSDFilenames.empty()) |
787 | 473 | { |
788 | 473 | aoXSDs = topElementParser.GetXSDs(); |
789 | 473 | if (aoXSDs.empty()) |
790 | 473 | { |
791 | 473 | const std::map<std::string, std::string> mapWellKnownURIToLocation = |
792 | 473 | { |
793 | 473 | {"http://www.opengis.net/citygml/2.0", |
794 | 473 | "https://schemas.opengis.net/citygml/2.0/cityGMLBase.xsd"}, |
795 | 473 | {"http://www.opengis.net/citygml/appearance/2.0", |
796 | 473 | "https://schemas.opengis.net/citygml/appearance/2.0/" |
797 | 473 | "appearance.xsd"}, |
798 | 473 | {"http://www.opengis.net/citygml/bridge/2.0", |
799 | 473 | "https://schemas.opengis.net/citygml/bridge/2.0/" |
800 | 473 | "bridge.xsd"}, |
801 | 473 | {"http://www.opengis.net/citygml/building/2.0", |
802 | 473 | "https://schemas.opengis.net/citygml/building/2.0/" |
803 | 473 | "building.xsd"}, |
804 | 473 | { |
805 | 473 | "http://www.opengis.net/citygml/cityfurniture/2.0", |
806 | 473 | "https://schemas.opengis.net/citygml/cityfurniture/2.0/" |
807 | 473 | "cityFurniture.xsd", |
808 | 473 | }, |
809 | 473 | {"http://www.opengis.net/citygml/cityobjectgroup/2.0", |
810 | 473 | "https://schemas.opengis.net/citygml/cityobjectgroup/2.0/" |
811 | 473 | "cityObjectGroup.xsd"}, |
812 | 473 | {"http://www.opengis.net/citygml/generics/2.0", |
813 | 473 | "https://schemas.opengis.net/citygml/generics/2.0/" |
814 | 473 | "generics.xsd"}, |
815 | 473 | {"http://www.opengis.net/citygml/landuse/2.0", |
816 | 473 | "https://schemas.opengis.net/citygml/landuse/2.0/" |
817 | 473 | "landUse.xsd"}, |
818 | 473 | {"http://www.opengis.net/citygml/relief/2.0", |
819 | 473 | "https://schemas.opengis.net/citygml/relief/2.0/" |
820 | 473 | "relief.xsd"}, |
821 | | // { "http://www.opengis.net/citygml/textures/2.0", } , |
822 | 473 | {"http://www.opengis.net/citygml/transportation/2.0", |
823 | 473 | "https://schemas.opengis.net/citygml/transportation/2.0/" |
824 | 473 | "transportation.xsd"}, |
825 | 473 | {"http://www.opengis.net/citygml/tunnel/2.0", |
826 | 473 | "https://schemas.opengis.net/citygml/tunnel/2.0/" |
827 | 473 | "tunnel.xsd"}, |
828 | 473 | {"http://www.opengis.net/citygml/vegetation/2.0", |
829 | 473 | "https://schemas.opengis.net/citygml/vegetation/2.0/" |
830 | 473 | "vegetation.xsd"}, |
831 | 473 | {"http://www.opengis.net/citygml/waterbody/2.0", |
832 | 473 | "https://schemas.opengis.net/citygml/waterbody/2.0/" |
833 | 473 | "waterBody.xsd"}, |
834 | 473 | {"http://www.w3.org/1999/xlink", |
835 | 473 | "https://www.w3.org/1999/xlink.xsd"}, |
836 | 473 | {"urn:oasis:names:tc:ciq:xsdschema:xAL:2.0", |
837 | 473 | "https://schemas.opengis.net/citygml/xAL/xAL.xsd"}, |
838 | 473 | }; |
839 | | |
840 | 473 | bool cityGML2Found = false; |
841 | 473 | for (const auto &[uri, prefix] : |
842 | 473 | topElementParser.GetMapDocNSURIToPrefix()) |
843 | 0 | { |
844 | 0 | if (uri == "http://www.opengis.net/citygml/2.0") |
845 | 0 | cityGML2Found = true; |
846 | 0 | } |
847 | | |
848 | 473 | for (const auto &[uri, prefix] : |
849 | 473 | topElementParser.GetMapDocNSURIToPrefix()) |
850 | 0 | { |
851 | 0 | const auto iter = mapWellKnownURIToLocation.find(uri); |
852 | 0 | if (iter != mapWellKnownURIToLocation.end()) |
853 | 0 | { |
854 | 0 | aoXSDs.push_back(PairURIFilename(uri, iter->second)); |
855 | 0 | } |
856 | 0 | else if (cityGML2Found && uri == "http://www.opengis.net/gml") |
857 | 0 | { |
858 | 0 | aoXSDs.push_back(PairURIFilename( |
859 | 0 | uri, |
860 | 0 | "https://schemas.opengis.net/gml/3.1.1/base/gml.xsd")); |
861 | 0 | } |
862 | 0 | else if (uri != "http://www.w3.org/2001/XMLSchema-instance") |
863 | 0 | { |
864 | 0 | CPLDebug("GMLAS", |
865 | 0 | "Could not find schema location for %s(%s)", |
866 | 0 | prefix.c_str(), uri.c_str()); |
867 | 0 | } |
868 | 0 | } |
869 | | |
870 | 473 | m_aoXSDsManuallyPassed = aoXSDs; |
871 | 473 | } |
872 | 473 | } |
873 | 0 | else |
874 | 0 | { |
875 | 0 | aoXSDs = BuildXSDVector(osXSDFilenames); |
876 | 0 | } |
877 | 473 | if (fpGML) |
878 | 473 | { |
879 | 473 | m_osHash = |
880 | 473 | CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "HASH", ""); |
881 | 473 | if (m_osHash.empty()) |
882 | 473 | { |
883 | 473 | fpGML->Seek(0, SEEK_SET); |
884 | 473 | std::string osBuffer; |
885 | 473 | osBuffer.resize(8192); |
886 | 473 | size_t nRead = fpGML->Read(&osBuffer[0], 1, 8192); |
887 | 473 | osBuffer.resize(nRead); |
888 | 473 | size_t nPos = osBuffer.find("timeStamp=\""); |
889 | 473 | if (nPos != std::string::npos) |
890 | 40 | { |
891 | 40 | size_t nPos2 = |
892 | 40 | osBuffer.find('"', nPos + strlen("timeStamp=\"")); |
893 | 40 | if (nPos2 != std::string::npos) |
894 | 32 | osBuffer.replace(nPos, nPos2 - nPos + 1, nPos2 - nPos + 1, |
895 | 32 | ' '); |
896 | 40 | } |
897 | 473 | CPL_SHA256Context ctxt; |
898 | 473 | CPL_SHA256Init(&ctxt); |
899 | 473 | CPL_SHA256Update(&ctxt, osBuffer.data(), osBuffer.size()); |
900 | | |
901 | 473 | VSIStatBufL sStat; |
902 | 473 | if (VSIStatL(m_osGMLFilename, &sStat) == 0) |
903 | 392 | { |
904 | 392 | m_nFileSize = sStat.st_size; |
905 | 392 | GUInt64 nFileSizeLittleEndian = |
906 | 392 | static_cast<GUInt64>(sStat.st_size); |
907 | 392 | CPL_LSBPTR64(&nFileSizeLittleEndian); |
908 | 392 | CPL_SHA256Update(&ctxt, &nFileSizeLittleEndian, |
909 | 392 | sizeof(nFileSizeLittleEndian)); |
910 | 392 | } |
911 | | |
912 | 473 | GByte abyHash[CPL_SHA256_HASH_SIZE]; |
913 | 473 | CPL_SHA256Final(&ctxt, abyHash); |
914 | | // Half of the hash should be enough for our purpose |
915 | 473 | char *pszHash = CPLBinaryToHex(CPL_SHA256_HASH_SIZE / 2, abyHash); |
916 | 473 | m_osHash = pszHash; |
917 | 473 | CPLFree(pszHash); |
918 | 473 | } |
919 | | |
920 | 473 | fpGML->Seek(0, SEEK_SET); |
921 | 473 | PushUnusedGMLFilePointer(fpGML); |
922 | 473 | } |
923 | | |
924 | 473 | if (aoXSDs.empty()) |
925 | 473 | { |
926 | 473 | if (osXSDFilenames.empty()) |
927 | 473 | { |
928 | 473 | CPLError(CE_Failure, CPLE_AppDefined, |
929 | 473 | "No schema locations found when analyzing data file: " |
930 | 473 | "%s open option must be provided", |
931 | 473 | szXSD_OPTION); |
932 | 473 | } |
933 | 0 | else |
934 | 0 | { |
935 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "No schema locations found"); |
936 | 0 | } |
937 | 473 | return false; |
938 | 473 | } |
939 | | |
940 | 0 | m_bSchemaFullChecking = CPLFetchBool(poOpenInfo->papszOpenOptions, |
941 | 0 | szSCHEMA_FULL_CHECKING_OPTION, |
942 | 0 | m_oConf.m_bSchemaFullChecking); |
943 | |
|
944 | 0 | m_bHandleMultipleImports = CPLFetchBool(poOpenInfo->papszOpenOptions, |
945 | 0 | szHANDLE_MULTIPLE_IMPORTS_OPTION, |
946 | 0 | m_oConf.m_bHandleMultipleImports); |
947 | |
|
948 | 0 | bool bRet = oAnalyzer.Analyze( |
949 | 0 | m_oCache, CPLGetDirnameSafe(m_osGMLFilename).c_str(), aoXSDs, |
950 | 0 | m_bSchemaFullChecking, m_bHandleMultipleImports); |
951 | 0 | if (!bRet) |
952 | 0 | { |
953 | 0 | return false; |
954 | 0 | } |
955 | | |
956 | 0 | if (!osXSDFilenames.empty()) |
957 | 0 | m_aoXSDsManuallyPassed = aoXSDs; |
958 | |
|
959 | 0 | m_oMapURIToPrefix = oAnalyzer.GetMapURIToPrefix(); |
960 | |
|
961 | 0 | m_osGMLVersionFound = oAnalyzer.GetGMLVersionFound(); |
962 | |
|
963 | 0 | const std::set<CPLString> &oSetSchemaURLs = oAnalyzer.GetSchemaURLS(); |
964 | |
|
965 | 0 | FillOtherMetadataLayer(poOpenInfo, m_osConfigFile, aoXSDs, oSetSchemaURLs); |
966 | |
|
967 | 0 | if (CPLFetchBool(poOpenInfo->papszOpenOptions, |
968 | 0 | szEXPOSE_METADATA_LAYERS_OPTION, |
969 | 0 | m_oConf.m_bExposeMetadataLayers)) |
970 | 0 | { |
971 | 0 | m_apoRequestedMetadataLayers.push_back(m_poFieldsMetadataLayer.get()); |
972 | 0 | m_apoRequestedMetadataLayers.push_back(m_poLayersMetadataLayer.get()); |
973 | 0 | m_apoRequestedMetadataLayers.push_back(m_poRelationshipsLayer.get()); |
974 | 0 | m_apoRequestedMetadataLayers.push_back(m_poOtherMetadataLayer.get()); |
975 | 0 | } |
976 | |
|
977 | 0 | const char *pszSwapCoordinates = CSLFetchNameValueDef( |
978 | 0 | poOpenInfo->papszOpenOptions, szSWAP_COORDINATES_OPTION, "AUTO"); |
979 | 0 | if (EQUAL(pszSwapCoordinates, "AUTO")) |
980 | 0 | { |
981 | 0 | m_eSwapCoordinates = GMLAS_SWAP_AUTO; |
982 | 0 | } |
983 | 0 | else if (CPLTestBool(pszSwapCoordinates)) |
984 | 0 | { |
985 | 0 | m_eSwapCoordinates = GMLAS_SWAP_YES; |
986 | 0 | } |
987 | 0 | else |
988 | 0 | { |
989 | 0 | m_eSwapCoordinates = GMLAS_SWAP_NO; |
990 | 0 | } |
991 | |
|
992 | 0 | const std::vector<GMLASFeatureClass> &aoClasses = oAnalyzer.GetClasses(); |
993 | | |
994 | | // First "standard" tables |
995 | 0 | for (auto &oClass : aoClasses) |
996 | 0 | { |
997 | 0 | if (oClass.GetParentXPath().empty()) |
998 | 0 | TranslateClasses(nullptr, oClass); |
999 | 0 | } |
1000 | | // Then junction tables |
1001 | 0 | for (auto &oClass : aoClasses) |
1002 | 0 | { |
1003 | 0 | if (!oClass.GetParentXPath().empty()) |
1004 | 0 | TranslateClasses(nullptr, oClass); |
1005 | 0 | } |
1006 | | |
1007 | | // And now do initialization since we need to have instantiated everything |
1008 | | // to be able to do cross-layer links |
1009 | 0 | for (auto &poLayer : m_apoLayers) |
1010 | 0 | { |
1011 | 0 | poLayer->PostInit(m_oConf.m_bIncludeGeometryXML); |
1012 | 0 | } |
1013 | 0 | m_bLayerInitFinished = true; |
1014 | | |
1015 | | // Do optional validation |
1016 | 0 | m_bValidate = CPLFetchBool(poOpenInfo->papszOpenOptions, szVALIDATE_OPTION, |
1017 | 0 | m_oConf.m_bValidate); |
1018 | |
|
1019 | 0 | m_bRemoveUnusedLayers = CPLFetchBool(poOpenInfo->papszOpenOptions, |
1020 | 0 | szREMOVE_UNUSED_LAYERS_OPTION, |
1021 | 0 | m_oConf.m_bRemoveUnusedLayers); |
1022 | |
|
1023 | 0 | m_bRemoveUnusedFields = CPLFetchBool(poOpenInfo->papszOpenOptions, |
1024 | 0 | szREMOVE_UNUSED_FIELDS_OPTION, |
1025 | 0 | m_oConf.m_bRemoveUnusedFields); |
1026 | |
|
1027 | 0 | m_oXLinkResolver.SetConf(m_oConf.m_oXLinkResolution); |
1028 | 0 | m_oXLinkResolver.SetRefreshMode(bRefreshCache); |
1029 | |
|
1030 | 0 | if (m_bValidate || m_bRemoveUnusedLayers || |
1031 | 0 | (m_bFoundSWE && |
1032 | 0 | (m_oConf.m_bSWEProcessDataRecord || m_oConf.m_bSWEProcessDataArray))) |
1033 | 0 | { |
1034 | 0 | CPLErrorReset(); |
1035 | 0 | RunFirstPassIfNeeded(nullptr, nullptr, nullptr); |
1036 | 0 | if (CPLFetchBool(poOpenInfo->papszOpenOptions, |
1037 | 0 | szFAIL_IF_VALIDATION_ERROR_OPTION, |
1038 | 0 | m_oConf.m_bFailIfValidationError) && |
1039 | 0 | CPLGetLastErrorType() != CE_None) |
1040 | 0 | { |
1041 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1042 | 0 | "Validation errors encountered"); |
1043 | 0 | return false; |
1044 | 0 | } |
1045 | 0 | } |
1046 | 0 | if (CPLGetLastErrorType() == CE_Failure) |
1047 | 0 | CPLErrorReset(); |
1048 | |
|
1049 | 0 | return true; |
1050 | 0 | } |
1051 | | |
1052 | | /************************************************************************/ |
1053 | | /* TestCapability() */ |
1054 | | /************************************************************************/ |
1055 | | |
1056 | | int OGRGMLASDataSource::TestCapability(const char *pszCap) const |
1057 | 0 | { |
1058 | 0 | return EQUAL(pszCap, ODsCRandomLayerRead); |
1059 | 0 | } |
1060 | | |
1061 | | /************************************************************************/ |
1062 | | /* CreateReader() */ |
1063 | | /************************************************************************/ |
1064 | | |
1065 | | GMLASReader * |
1066 | | OGRGMLASDataSource::CreateReader(std::shared_ptr<VSIVirtualHandle> &fpGML, |
1067 | | GDALProgressFunc pfnProgress, |
1068 | | void *pProgressData) |
1069 | 0 | { |
1070 | 0 | if (fpGML == nullptr) |
1071 | 0 | { |
1072 | | // Try recycling an already opened and unused file pointer |
1073 | 0 | fpGML = PopUnusedGMLFilePointer(); |
1074 | 0 | if (fpGML == nullptr) |
1075 | 0 | fpGML.reset(VSIFOpenL(GetGMLFilename(), "rb"), |
1076 | 0 | VSIVirtualHandleCloser{}); |
1077 | 0 | if (fpGML == nullptr) |
1078 | 0 | return nullptr; |
1079 | 0 | } |
1080 | | |
1081 | 0 | auto poReader = std::make_unique<GMLASReader>( |
1082 | 0 | GetCache(), GetIgnoredXPathMatcher(), m_oXLinkResolver); |
1083 | 0 | poReader->Init(GetGMLFilename(), fpGML, GetMapURIToPrefix(), GetLayers(), |
1084 | 0 | false, std::vector<PairURIFilename>(), m_bSchemaFullChecking, |
1085 | 0 | m_bHandleMultipleImports); |
1086 | |
|
1087 | 0 | poReader->SetSwapCoordinates(GetSwapCoordinates()); |
1088 | |
|
1089 | 0 | poReader->SetFileSize(m_nFileSize); |
1090 | |
|
1091 | 0 | if (!RunFirstPassIfNeeded(poReader.get(), pfnProgress, pProgressData)) |
1092 | 0 | { |
1093 | 0 | return nullptr; |
1094 | 0 | } |
1095 | | |
1096 | 0 | poReader->SetMapIgnoredXPathToWarn(GetMapIgnoredXPathToWarn()); |
1097 | |
|
1098 | 0 | poReader->SetHash(m_osHash); |
1099 | |
|
1100 | 0 | return poReader.release(); |
1101 | 0 | } |
1102 | | |
1103 | | /************************************************************************/ |
1104 | | /* ResetReading() */ |
1105 | | /************************************************************************/ |
1106 | | |
1107 | | void OGRGMLASDataSource::ResetReading() |
1108 | 0 | { |
1109 | 0 | m_poReader.reset(); |
1110 | 0 | for (auto *poLayer : m_apoRequestedMetadataLayers) |
1111 | 0 | poLayer->ResetReading(); |
1112 | 0 | m_bEndOfReaderLayers = false; |
1113 | 0 | m_nCurMetadataLayerIdx = -1; |
1114 | 0 | } |
1115 | | |
1116 | | /************************************************************************/ |
1117 | | /* GetNextFeature() */ |
1118 | | /************************************************************************/ |
1119 | | |
1120 | | OGRFeature *OGRGMLASDataSource::GetNextFeature(OGRLayer **ppoBelongingLayer, |
1121 | | double *pdfProgressPct, |
1122 | | GDALProgressFunc pfnProgress, |
1123 | | void *pProgressData) |
1124 | 0 | { |
1125 | 0 | if (m_bEndOfReaderLayers) |
1126 | 0 | { |
1127 | 0 | if (m_nCurMetadataLayerIdx >= 0 && |
1128 | 0 | m_nCurMetadataLayerIdx < |
1129 | 0 | static_cast<int>(m_apoRequestedMetadataLayers.size())) |
1130 | 0 | { |
1131 | 0 | while (true) |
1132 | 0 | { |
1133 | 0 | OGRLayer *poLayer = |
1134 | 0 | m_apoRequestedMetadataLayers[m_nCurMetadataLayerIdx]; |
1135 | 0 | OGRFeature *poFeature = poLayer->GetNextFeature(); |
1136 | 0 | if (poFeature != nullptr) |
1137 | 0 | { |
1138 | 0 | if (pdfProgressPct != nullptr) |
1139 | 0 | *pdfProgressPct = 1.0; |
1140 | 0 | if (ppoBelongingLayer != nullptr) |
1141 | 0 | *ppoBelongingLayer = poLayer; |
1142 | 0 | return poFeature; |
1143 | 0 | } |
1144 | 0 | if (m_nCurMetadataLayerIdx + 1 < |
1145 | 0 | static_cast<int>(m_apoRequestedMetadataLayers.size())) |
1146 | 0 | { |
1147 | 0 | m_nCurMetadataLayerIdx++; |
1148 | 0 | } |
1149 | 0 | else |
1150 | 0 | { |
1151 | 0 | m_nCurMetadataLayerIdx = -1; |
1152 | 0 | break; |
1153 | 0 | } |
1154 | 0 | } |
1155 | 0 | } |
1156 | | |
1157 | 0 | if (pdfProgressPct != nullptr) |
1158 | 0 | *pdfProgressPct = 1.0; |
1159 | 0 | if (ppoBelongingLayer != nullptr) |
1160 | 0 | *ppoBelongingLayer = nullptr; |
1161 | 0 | return nullptr; |
1162 | 0 | } |
1163 | | |
1164 | 0 | const double dfInitialScanRatio = 0.1; |
1165 | 0 | if (m_poReader == nullptr) |
1166 | 0 | { |
1167 | 0 | void *pScaledProgress = GDALCreateScaledProgress( |
1168 | 0 | 0.0, dfInitialScanRatio, pfnProgress, pProgressData); |
1169 | |
|
1170 | 0 | m_poReader.reset(CreateReader( |
1171 | 0 | m_fpGMLParser, pScaledProgress ? GDALScaledProgress : nullptr, |
1172 | 0 | pScaledProgress)); |
1173 | |
|
1174 | 0 | GDALDestroyScaledProgress(pScaledProgress); |
1175 | |
|
1176 | 0 | if (m_poReader == nullptr) |
1177 | 0 | { |
1178 | 0 | if (pdfProgressPct != nullptr) |
1179 | 0 | *pdfProgressPct = 1.0; |
1180 | 0 | if (ppoBelongingLayer != nullptr) |
1181 | 0 | *ppoBelongingLayer = nullptr; |
1182 | 0 | m_bEndOfReaderLayers = true; |
1183 | 0 | if (!m_apoRequestedMetadataLayers.empty()) |
1184 | 0 | { |
1185 | 0 | m_nCurMetadataLayerIdx = 0; |
1186 | 0 | return GetNextFeature(ppoBelongingLayer, pdfProgressPct, |
1187 | 0 | pfnProgress, pProgressData); |
1188 | 0 | } |
1189 | 0 | else |
1190 | 0 | { |
1191 | 0 | return nullptr; |
1192 | 0 | } |
1193 | 0 | } |
1194 | 0 | } |
1195 | | |
1196 | 0 | void *pScaledProgress = GDALCreateScaledProgress( |
1197 | 0 | dfInitialScanRatio, 1.0, pfnProgress, pProgressData); |
1198 | |
|
1199 | 0 | while (true) |
1200 | 0 | { |
1201 | 0 | OGRGMLASLayer *poBelongingLayer = nullptr; |
1202 | 0 | auto poFeature = std::unique_ptr<OGRFeature>(m_poReader->GetNextFeature( |
1203 | 0 | &poBelongingLayer, pScaledProgress ? GDALScaledProgress : nullptr, |
1204 | 0 | pScaledProgress)); |
1205 | 0 | if (poFeature == nullptr || |
1206 | 0 | poBelongingLayer->EvaluateFilter(poFeature.get())) |
1207 | 0 | { |
1208 | 0 | if (ppoBelongingLayer != nullptr) |
1209 | 0 | *ppoBelongingLayer = poBelongingLayer; |
1210 | 0 | if (pdfProgressPct != nullptr) |
1211 | 0 | { |
1212 | 0 | const vsi_l_offset nOffset = m_fpGMLParser->Tell(); |
1213 | 0 | if (nOffset == m_nFileSize) |
1214 | 0 | *pdfProgressPct = 1.0; |
1215 | 0 | else |
1216 | 0 | *pdfProgressPct = |
1217 | 0 | dfInitialScanRatio + |
1218 | 0 | (1.0 - dfInitialScanRatio) * nOffset / m_nFileSize; |
1219 | 0 | } |
1220 | 0 | GDALDestroyScaledProgress(pScaledProgress); |
1221 | 0 | if (poFeature == nullptr) |
1222 | 0 | { |
1223 | 0 | m_bEndOfReaderLayers = true; |
1224 | 0 | if (!m_apoRequestedMetadataLayers.empty()) |
1225 | 0 | { |
1226 | 0 | m_nCurMetadataLayerIdx = 0; |
1227 | 0 | return GetNextFeature(ppoBelongingLayer, pdfProgressPct, |
1228 | 0 | pfnProgress, pProgressData); |
1229 | 0 | } |
1230 | 0 | else |
1231 | 0 | { |
1232 | 0 | return nullptr; |
1233 | 0 | } |
1234 | 0 | } |
1235 | 0 | else |
1236 | 0 | return poFeature.release(); |
1237 | 0 | } |
1238 | 0 | } |
1239 | 0 | } |
1240 | | |
1241 | | /************************************************************************/ |
1242 | | /* GetLayerByXPath() */ |
1243 | | /************************************************************************/ |
1244 | | |
1245 | | OGRGMLASLayer *OGRGMLASDataSource::GetLayerByXPath(const CPLString &osXPath) |
1246 | 0 | { |
1247 | 0 | for (auto &poLayer : m_apoLayers) |
1248 | 0 | { |
1249 | 0 | if (poLayer->GetFeatureClass().GetXPath() == osXPath) |
1250 | 0 | { |
1251 | 0 | return poLayer.get(); |
1252 | 0 | } |
1253 | 0 | } |
1254 | 0 | return nullptr; |
1255 | 0 | } |
1256 | | |
1257 | | /************************************************************************/ |
1258 | | /* PushUnusedGMLFilePointer() */ |
1259 | | /************************************************************************/ |
1260 | | |
1261 | | void OGRGMLASDataSource::PushUnusedGMLFilePointer( |
1262 | | std::shared_ptr<VSIVirtualHandle> &fpGML) |
1263 | 473 | { |
1264 | 473 | if (m_fpGML == nullptr) |
1265 | 473 | { |
1266 | 473 | std::swap(m_fpGML, fpGML); |
1267 | 473 | } |
1268 | 0 | else |
1269 | 0 | { |
1270 | 0 | fpGML.reset(); |
1271 | 0 | } |
1272 | 473 | } |
1273 | | |
1274 | | /************************************************************************/ |
1275 | | /* PopUnusedGMLFilePointer() */ |
1276 | | /************************************************************************/ |
1277 | | |
1278 | | std::shared_ptr<VSIVirtualHandle> OGRGMLASDataSource::PopUnusedGMLFilePointer() |
1279 | 0 | { |
1280 | 0 | std::shared_ptr<VSIVirtualHandle> fpGML; |
1281 | 0 | std::swap(fpGML, m_fpGML); |
1282 | 0 | return fpGML; |
1283 | 0 | } |
1284 | | |
1285 | | /************************************************************************/ |
1286 | | /* InitReaderWithFirstPassElements() */ |
1287 | | /************************************************************************/ |
1288 | | |
1289 | | void OGRGMLASDataSource::InitReaderWithFirstPassElements(GMLASReader *poReader) |
1290 | 0 | { |
1291 | 0 | if (poReader != nullptr) |
1292 | 0 | { |
1293 | 0 | poReader->SetMapSRSNameToInvertedAxis(m_oMapSRSNameToInvertedAxis); |
1294 | 0 | poReader->SetMapGeomFieldDefnToSRSName(m_oMapGeomFieldDefnToSRSName); |
1295 | 0 | poReader->SetProcessDataRecord(m_bFoundSWE && |
1296 | 0 | m_oConf.m_bSWEProcessDataRecord); |
1297 | 0 | poReader->SetSWEDataArrayLayersRef(m_apoSWEDataArrayLayersRef); |
1298 | 0 | poReader->SetMapElementIdToLayer(m_oMapElementIdToLayer); |
1299 | 0 | poReader->SetMapElementIdToPKID(m_oMapElementIdToPKID); |
1300 | 0 | poReader->SetDefaultSrsDimension(m_nDefaultSrsDimension); |
1301 | 0 | } |
1302 | 0 | } |
1303 | | |
1304 | | /************************************************************************/ |
1305 | | /* RunFirstPassIfNeeded() */ |
1306 | | /************************************************************************/ |
1307 | | |
1308 | | bool OGRGMLASDataSource::RunFirstPassIfNeeded(GMLASReader *poReader, |
1309 | | GDALProgressFunc pfnProgress, |
1310 | | void *pProgressData) |
1311 | 0 | { |
1312 | 0 | if (m_bFirstPassDone) |
1313 | 0 | { |
1314 | 0 | InitReaderWithFirstPassElements(poReader); |
1315 | 0 | return true; |
1316 | 0 | } |
1317 | | |
1318 | 0 | m_bFirstPassDone = true; |
1319 | | |
1320 | | // Determine if we have geometry fields in any layer |
1321 | | // If so, do an initial pass to determine the SRS of those geometry fields. |
1322 | 0 | bool bHasGeomFields = false; |
1323 | 0 | for (auto &poLayer : m_apoLayers) |
1324 | 0 | { |
1325 | 0 | poLayer->SetLayerDefnFinalized(true); |
1326 | 0 | if (poLayer->GetLayerDefn()->GetGeomFieldCount() > 0) |
1327 | 0 | { |
1328 | 0 | bHasGeomFields = true; |
1329 | 0 | break; |
1330 | 0 | } |
1331 | 0 | } |
1332 | |
|
1333 | 0 | bool bSuccess = true; |
1334 | 0 | const bool bHasURLSpecificRules = |
1335 | 0 | !m_oXLinkResolver.GetConf().m_aoURLSpecificRules.empty(); |
1336 | 0 | if (bHasGeomFields || m_bValidate || m_bRemoveUnusedLayers || |
1337 | 0 | m_bRemoveUnusedFields || bHasURLSpecificRules || |
1338 | 0 | m_oXLinkResolver.GetConf().m_bResolveInternalXLinks || |
1339 | 0 | (m_bFoundSWE && |
1340 | 0 | (m_oConf.m_bSWEProcessDataRecord || m_oConf.m_bSWEProcessDataArray))) |
1341 | 0 | { |
1342 | 0 | bool bJustOpenedFiled = false; |
1343 | 0 | std::shared_ptr<VSIVirtualHandle> fp; |
1344 | 0 | if (poReader) |
1345 | 0 | fp = poReader->GetFP(); |
1346 | 0 | else |
1347 | 0 | { |
1348 | 0 | fp.reset(VSIFOpenL(GetGMLFilename(), "rb"), |
1349 | 0 | VSIVirtualHandleCloser{}); |
1350 | 0 | if (fp == nullptr) |
1351 | 0 | { |
1352 | 0 | return false; |
1353 | 0 | } |
1354 | 0 | bJustOpenedFiled = true; |
1355 | 0 | } |
1356 | | |
1357 | 0 | auto poReaderFirstPass = std::make_unique<GMLASReader>( |
1358 | 0 | m_oCache, m_oIgnoredXPathMatcher, m_oXLinkResolver); |
1359 | 0 | poReaderFirstPass->Init(GetGMLFilename(), fp, GetMapURIToPrefix(), |
1360 | 0 | GetLayers(), m_bValidate, |
1361 | 0 | m_aoXSDsManuallyPassed, m_bSchemaFullChecking, |
1362 | 0 | m_bHandleMultipleImports); |
1363 | |
|
1364 | 0 | poReaderFirstPass->SetProcessDataRecord( |
1365 | 0 | m_bFoundSWE && m_oConf.m_bSWEProcessDataRecord); |
1366 | |
|
1367 | 0 | poReaderFirstPass->SetFileSize(m_nFileSize); |
1368 | |
|
1369 | 0 | poReaderFirstPass->SetMapIgnoredXPathToWarn( |
1370 | 0 | m_oConf.m_oMapIgnoredXPathToWarn); |
1371 | |
|
1372 | 0 | poReaderFirstPass->SetHash(m_osHash); |
1373 | | |
1374 | | // No need to warn afterwards |
1375 | 0 | m_oConf.m_oMapIgnoredXPathToWarn.clear(); |
1376 | |
|
1377 | 0 | std::set<CPLString> aoSetRemovedLayerNames; |
1378 | 0 | bSuccess = poReaderFirstPass->RunFirstPass( |
1379 | 0 | pfnProgress, pProgressData, m_bRemoveUnusedLayers, |
1380 | 0 | m_bRemoveUnusedFields, |
1381 | 0 | m_bFoundSWE && m_oConf.m_bSWEProcessDataArray, |
1382 | 0 | m_poFieldsMetadataLayer.get(), m_poLayersMetadataLayer.get(), |
1383 | 0 | m_poRelationshipsLayer.get(), aoSetRemovedLayerNames); |
1384 | |
|
1385 | 0 | std::vector<std::unique_ptr<OGRGMLASLayer>> apoSWEDataArrayLayers = |
1386 | 0 | poReaderFirstPass->StealSWEDataArrayLayersOwned(); |
1387 | 0 | for (auto &poLayer : apoSWEDataArrayLayers) |
1388 | 0 | { |
1389 | 0 | poLayer->SetDataSource(this); |
1390 | 0 | m_apoSWEDataArrayLayersRef.push_back(poLayer.get()); |
1391 | 0 | m_apoLayers.emplace_back(std::move(poLayer)); |
1392 | 0 | } |
1393 | | |
1394 | | // If we have removed layers, we also need to cleanup our special |
1395 | | // metadata layers |
1396 | 0 | if (!aoSetRemovedLayerNames.empty()) |
1397 | 0 | { |
1398 | | // Removing features while iterating works here given the layers |
1399 | | // are MEM layers |
1400 | 0 | m_poLayersMetadataLayer->ResetReading(); |
1401 | 0 | for (auto &poFeature : *m_poLayersMetadataLayer) |
1402 | 0 | { |
1403 | 0 | const char *pszLayerName = |
1404 | 0 | poFeature->GetFieldAsString(szLAYER_NAME); |
1405 | 0 | if (aoSetRemovedLayerNames.find(pszLayerName) != |
1406 | 0 | aoSetRemovedLayerNames.end()) |
1407 | 0 | { |
1408 | 0 | CPL_IGNORE_RET_VAL(m_poLayersMetadataLayer->DeleteFeature( |
1409 | 0 | poFeature->GetFID())); |
1410 | 0 | } |
1411 | 0 | } |
1412 | 0 | m_poLayersMetadataLayer->ResetReading(); |
1413 | |
|
1414 | 0 | m_poFieldsMetadataLayer->ResetReading(); |
1415 | 0 | for (auto &poFeature : *m_poFieldsMetadataLayer) |
1416 | 0 | { |
1417 | 0 | const char *pszLayerName = |
1418 | 0 | poFeature->GetFieldAsString(szLAYER_NAME); |
1419 | 0 | const char *pszRelatedLayerName = |
1420 | 0 | poFeature->GetFieldAsString(szFIELD_RELATED_LAYER); |
1421 | 0 | if (aoSetRemovedLayerNames.find(pszLayerName) != |
1422 | 0 | aoSetRemovedLayerNames.end() || |
1423 | 0 | aoSetRemovedLayerNames.find(pszRelatedLayerName) != |
1424 | 0 | aoSetRemovedLayerNames.end()) |
1425 | 0 | { |
1426 | 0 | CPL_IGNORE_RET_VAL(m_poFieldsMetadataLayer->DeleteFeature( |
1427 | 0 | poFeature->GetFID())); |
1428 | 0 | } |
1429 | 0 | } |
1430 | 0 | m_poFieldsMetadataLayer->ResetReading(); |
1431 | |
|
1432 | 0 | m_poRelationshipsLayer->ResetReading(); |
1433 | 0 | for (auto &poFeature : *m_poRelationshipsLayer) |
1434 | 0 | { |
1435 | 0 | const char *pszParentLayerName = |
1436 | 0 | poFeature->GetFieldAsString(szPARENT_LAYER); |
1437 | 0 | const char *pszChildLayerName = |
1438 | 0 | poFeature->GetFieldAsString(szCHILD_LAYER); |
1439 | 0 | if (aoSetRemovedLayerNames.find(pszParentLayerName) != |
1440 | 0 | aoSetRemovedLayerNames.end() || |
1441 | 0 | aoSetRemovedLayerNames.find(pszChildLayerName) != |
1442 | 0 | aoSetRemovedLayerNames.end()) |
1443 | 0 | { |
1444 | 0 | CPL_IGNORE_RET_VAL(m_poRelationshipsLayer->DeleteFeature( |
1445 | 0 | poFeature->GetFID())); |
1446 | 0 | } |
1447 | 0 | } |
1448 | 0 | m_poRelationshipsLayer->ResetReading(); |
1449 | 0 | } |
1450 | | |
1451 | | // Store maps to reinject them in real readers |
1452 | 0 | m_oMapSRSNameToInvertedAxis = |
1453 | 0 | poReaderFirstPass->GetMapSRSNameToInvertedAxis(); |
1454 | 0 | m_oMapGeomFieldDefnToSRSName = |
1455 | 0 | poReaderFirstPass->GetMapGeomFieldDefnToSRSName(); |
1456 | |
|
1457 | 0 | m_oMapElementIdToLayer = poReaderFirstPass->GetMapElementIdToLayer(); |
1458 | 0 | m_oMapElementIdToPKID = poReaderFirstPass->GetMapElementIdToPKID(); |
1459 | 0 | m_nDefaultSrsDimension = poReaderFirstPass->GetDefaultSrsDimension(); |
1460 | |
|
1461 | 0 | poReaderFirstPass.reset(); |
1462 | |
|
1463 | 0 | fp->Seek(0, SEEK_SET); |
1464 | 0 | if (bJustOpenedFiled) |
1465 | 0 | PushUnusedGMLFilePointer(fp); |
1466 | |
|
1467 | 0 | InitReaderWithFirstPassElements(poReader); |
1468 | 0 | } |
1469 | | |
1470 | 0 | return bSuccess; |
1471 | 0 | } |