/src/gdal/ogr/ogrsf_frmts/gmlas/ogrgmlasconf.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 "cpl_minixml.h" |
18 | | |
19 | | #include <algorithm> |
20 | | |
21 | | #ifdef EMBED_RESOURCE_FILES |
22 | | #include "embedded_resources.h" |
23 | | #endif |
24 | | |
25 | | /************************************************************************/ |
26 | | /* Finalize() */ |
27 | | /************************************************************************/ |
28 | | |
29 | | void GMLASConfiguration::Finalize() |
30 | 2.42k | { |
31 | 2.42k | if (m_bAllowXSDCache && m_osXSDCacheDirectory.empty()) |
32 | 2.42k | { |
33 | 2.42k | m_osXSDCacheDirectory = GDALGetCacheDirectory(); |
34 | 2.42k | if (m_osXSDCacheDirectory.empty()) |
35 | 0 | { |
36 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
37 | 0 | "Could not determine a directory for GMLAS XSD cache"); |
38 | 0 | } |
39 | 2.42k | else |
40 | 2.42k | { |
41 | 2.42k | m_osXSDCacheDirectory = CPLFormFilenameSafe( |
42 | 2.42k | m_osXSDCacheDirectory, "gmlas_xsd_cache", nullptr); |
43 | 2.42k | CPLDebug("GMLAS", "XSD cache directory: %s", |
44 | 2.42k | m_osXSDCacheDirectory.c_str()); |
45 | 2.42k | } |
46 | 2.42k | } |
47 | 2.42k | } |
48 | | |
49 | | /************************************************************************/ |
50 | | /* CPLGetXMLBoolValue() */ |
51 | | /************************************************************************/ |
52 | | |
53 | | static bool CPLGetXMLBoolValue(CPLXMLNode *psNode, const char *pszKey, |
54 | | bool bDefault) |
55 | 104k | { |
56 | 104k | const char *pszVal = CPLGetXMLValue(psNode, pszKey, nullptr); |
57 | 104k | if (pszVal) |
58 | 53.4k | return CPLTestBool(pszVal); |
59 | 50.9k | else |
60 | 50.9k | return bDefault; |
61 | 104k | } |
62 | | |
63 | | /************************************************************************/ |
64 | | /* IsValidXPath() */ |
65 | | /************************************************************************/ |
66 | | |
67 | | static bool IsValidXPath(const CPLString &osXPath) |
68 | 58.2k | { |
69 | | // Check that the XPath syntax belongs to the subset we |
70 | | // understand |
71 | 58.2k | bool bOK = !osXPath.empty(); |
72 | 1.24M | for (size_t i = 0; i < osXPath.size(); ++i) |
73 | 1.18M | { |
74 | 1.18M | const char chCur = osXPath[i]; |
75 | 1.18M | if (chCur == '/') |
76 | 31.5k | { |
77 | | // OK |
78 | 31.5k | } |
79 | 1.15M | else if (chCur == '@' && (i == 0 || osXPath[i - 1] == '/') && |
80 | 31.5k | i < osXPath.size() - 1 && |
81 | 31.5k | isalpha(static_cast<unsigned char>(osXPath[i + 1]))) |
82 | 31.5k | { |
83 | | // OK |
84 | 31.5k | } |
85 | 1.12M | else if (chCur == '_' || isalpha(static_cast<unsigned char>(chCur))) |
86 | 1.02M | { |
87 | | // OK |
88 | 1.02M | } |
89 | 97.1k | else if (isdigit(static_cast<unsigned char>(chCur)) && i > 0 && |
90 | 21.8k | (isalnum(static_cast<unsigned char>(osXPath[i - 1])) || |
91 | 0 | osXPath[i - 1] == '_')) |
92 | 21.8k | { |
93 | | // OK |
94 | 21.8k | } |
95 | 75.2k | else if (chCur == ':' && i > 0 && |
96 | 75.2k | (isalnum(static_cast<unsigned char>(osXPath[i - 1])) || |
97 | 0 | osXPath[i - 1] == '_') && |
98 | 75.2k | i < osXPath.size() - 1 && |
99 | 75.2k | isalpha(static_cast<unsigned char>(osXPath[i + 1]))) |
100 | 75.2k | { |
101 | | // OK |
102 | 75.2k | } |
103 | 0 | else |
104 | 0 | { |
105 | 0 | bOK = false; |
106 | 0 | break; |
107 | 0 | } |
108 | 1.18M | } |
109 | 58.2k | return bOK; |
110 | 58.2k | } |
111 | | |
112 | | /************************************************************************/ |
113 | | /* GMLASConfigurationErrorHandler() */ |
114 | | /************************************************************************/ |
115 | | |
116 | | static void CPL_STDCALL GMLASConfigurationErrorHandler(CPLErr /*eErr*/, |
117 | | CPLErrorNum /*nType*/, |
118 | | const char *pszMsg) |
119 | 2.42k | { |
120 | 2.42k | std::vector<CPLString> *paosErrors = |
121 | 2.42k | static_cast<std::vector<CPLString> *>(CPLGetErrorHandlerUserData()); |
122 | 2.42k | paosErrors->push_back(pszMsg); |
123 | 2.42k | } |
124 | | |
125 | | /************************************************************************/ |
126 | | /* ParseNamespaces() */ |
127 | | /************************************************************************/ |
128 | | |
129 | | static void ParseNamespaces(CPLXMLNode *psContainerNode, |
130 | | std::map<CPLString, CPLString> &oMap) |
131 | 7.28k | { |
132 | 7.28k | CPLXMLNode *psNamespaces = CPLGetXMLNode(psContainerNode, "Namespaces"); |
133 | 7.28k | if (psNamespaces != nullptr) |
134 | 7.28k | { |
135 | 21.8k | for (CPLXMLNode *psIter = psNamespaces->psChild; psIter != nullptr; |
136 | 14.5k | psIter = psIter->psNext) |
137 | 14.5k | { |
138 | 14.5k | if (psIter->eType == CXT_Element && |
139 | 14.5k | EQUAL(psIter->pszValue, "Namespace")) |
140 | 14.5k | { |
141 | 14.5k | const std::string osPrefix = |
142 | 14.5k | CPLGetXMLValue(psIter, "prefix", ""); |
143 | 14.5k | const std::string osURI = CPLGetXMLValue(psIter, "uri", ""); |
144 | 14.5k | if (!osPrefix.empty() && !osURI.empty()) |
145 | 14.5k | { |
146 | 14.5k | if (oMap.find(osPrefix) == oMap.end()) |
147 | 14.5k | { |
148 | 14.5k | oMap[osPrefix] = osURI; |
149 | 14.5k | } |
150 | 0 | else |
151 | 0 | { |
152 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
153 | 0 | "Prefix %s was already mapped to %s. " |
154 | 0 | "Attempt to map it to %s ignored", |
155 | 0 | osPrefix.c_str(), oMap[osPrefix].c_str(), |
156 | 0 | osURI.c_str()); |
157 | 0 | } |
158 | 14.5k | } |
159 | 14.5k | } |
160 | 14.5k | } |
161 | 7.28k | } |
162 | 7.28k | } |
163 | | |
164 | | /************************************************************************/ |
165 | | /* GetDefaultConfFile() */ |
166 | | /************************************************************************/ |
167 | | |
168 | | /* static */ |
169 | | std::string GMLASConfiguration::GetDefaultConfFile(bool &bUnlinkAfterUse) |
170 | 2.42k | { |
171 | 2.42k | bUnlinkAfterUse = false; |
172 | 2.42k | #if !defined(USE_ONLY_EMBEDDED_RESOURCE_FILES) |
173 | 2.42k | const char *pszConfigFile = CPLFindFile("gdal", szDEFAULT_CONF_FILENAME); |
174 | 2.42k | if (pszConfigFile) |
175 | 0 | return pszConfigFile; |
176 | 2.42k | #endif |
177 | 2.42k | #ifdef EMBED_RESOURCE_FILES |
178 | 2.42k | static const bool bOnce [[maybe_unused]] = []() |
179 | 2.42k | { |
180 | 5 | CPLDebug("GMLAS", "Using embedded %s", szDEFAULT_CONF_FILENAME); |
181 | 5 | return true; |
182 | 5 | }(); |
183 | 2.42k | bUnlinkAfterUse = true; |
184 | 2.42k | const std::string osTmpFilename = |
185 | 2.42k | VSIMemGenerateHiddenFilename(szDEFAULT_CONF_FILENAME); |
186 | 2.42k | VSIFCloseL(VSIFileFromMemBuffer( |
187 | 2.42k | osTmpFilename.c_str(), |
188 | 2.42k | const_cast<GByte *>( |
189 | 2.42k | reinterpret_cast<const GByte *>(GMLASConfXMLGetFileContent())), |
190 | 2.42k | static_cast<int>(strlen(GMLASConfXMLGetFileContent())), |
191 | 2.42k | /* bTakeOwnership = */ false)); |
192 | 2.42k | return osTmpFilename; |
193 | | #else |
194 | | return std::string(); |
195 | | #endif |
196 | 2.42k | } |
197 | | |
198 | | /************************************************************************/ |
199 | | /* Load() */ |
200 | | /************************************************************************/ |
201 | | |
202 | | bool GMLASConfiguration::Load(const char *pszFilename) |
203 | 2.42k | { |
204 | | // Allow configuration to be inlined |
205 | 2.42k | CPLXMLNode *psRoot = STARTS_WITH(pszFilename, "<Configuration") |
206 | 2.42k | ? CPLParseXMLString(pszFilename) |
207 | 2.42k | : CPLParseXMLFile(pszFilename); |
208 | 2.42k | if (psRoot == nullptr) |
209 | 0 | { |
210 | 0 | Finalize(); |
211 | 0 | return false; |
212 | 0 | } |
213 | 2.42k | CPLXMLTreeCloser oCloser(psRoot); |
214 | 2.42k | CPL_IGNORE_RET_VAL(oCloser); |
215 | | |
216 | | // Validate the configuration file |
217 | 2.42k | if (CPLTestBool(CPLGetConfigOption("GDAL_XML_VALIDATION", "YES"))) |
218 | 2.42k | { |
219 | 2.42k | #ifdef EMBED_RESOURCE_FILES |
220 | 2.42k | std::string osTmpFilename; |
221 | 2.42k | CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler); |
222 | 2.42k | #endif |
223 | | #ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES |
224 | | const char *pszXSD = nullptr; |
225 | | #else |
226 | 2.42k | const char *pszXSD = CPLFindFile("gdal", "gmlasconf.xsd"); |
227 | 2.42k | #endif |
228 | 2.42k | #ifdef EMBED_RESOURCE_FILES |
229 | 2.42k | if (!pszXSD) |
230 | 2.42k | { |
231 | 2.42k | static const bool bOnce [[maybe_unused]] = []() |
232 | 2.42k | { |
233 | 5 | CPLDebug("GMLAS", "Using embedded gmlasconf.xsd"); |
234 | 5 | return true; |
235 | 5 | }(); |
236 | 2.42k | osTmpFilename = VSIMemGenerateHiddenFilename("gmlasconf.xsd"); |
237 | 2.42k | pszXSD = osTmpFilename.c_str(); |
238 | 2.42k | VSIFCloseL(VSIFileFromMemBuffer( |
239 | 2.42k | osTmpFilename.c_str(), |
240 | 2.42k | const_cast<GByte *>(reinterpret_cast<const GByte *>( |
241 | 2.42k | GMLASConfXSDGetFileContent())), |
242 | 2.42k | static_cast<int>(strlen(GMLASConfXSDGetFileContent())), |
243 | 2.42k | /* bTakeOwnership = */ false)); |
244 | 2.42k | } |
245 | | #else |
246 | | if (pszXSD) |
247 | | #endif |
248 | 2.42k | { |
249 | 2.42k | std::vector<CPLString> aosErrors; |
250 | 2.42k | const CPLErr eErrClass = CPLGetLastErrorType(); |
251 | 2.42k | const CPLErrorNum nErrNum = CPLGetLastErrorNo(); |
252 | 2.42k | const CPLString osErrMsg = CPLGetLastErrorMsg(); |
253 | 2.42k | CPLPushErrorHandlerEx(GMLASConfigurationErrorHandler, &aosErrors); |
254 | 2.42k | int bRet = CPLValidateXML(pszFilename, pszXSD, nullptr); |
255 | 2.42k | CPLPopErrorHandler(); |
256 | 2.42k | if (!bRet && !aosErrors.empty() && |
257 | 2.42k | strstr(aosErrors[0].c_str(), "missing libxml2 support") == |
258 | 2.42k | nullptr) |
259 | 0 | { |
260 | 0 | for (size_t i = 0; i < aosErrors.size(); i++) |
261 | 0 | { |
262 | 0 | CPLError(CE_Warning, CPLE_AppDefined, "%s", |
263 | 0 | aosErrors[i].c_str()); |
264 | 0 | } |
265 | 0 | } |
266 | 2.42k | else |
267 | 2.42k | { |
268 | 2.42k | CPLErrorSetState(eErrClass, nErrNum, osErrMsg); |
269 | 2.42k | } |
270 | 2.42k | } |
271 | | |
272 | 2.42k | #ifdef EMBED_RESOURCE_FILES |
273 | 2.42k | if (!osTmpFilename.empty()) |
274 | 2.42k | VSIUnlink(osTmpFilename.c_str()); |
275 | 2.42k | #endif |
276 | 2.42k | } |
277 | | |
278 | 2.42k | m_bAllowRemoteSchemaDownload = |
279 | 2.42k | CPLGetXMLBoolValue(psRoot, "=Configuration.AllowRemoteSchemaDownload", |
280 | 2.42k | ALLOW_REMOTE_SCHEMA_DOWNLOAD_DEFAULT); |
281 | | |
282 | 2.42k | m_bAllowXSDCache = CPLGetXMLBoolValue( |
283 | 2.42k | psRoot, "=Configuration.SchemaCache.enabled", ALLOW_XSD_CACHE_DEFAULT); |
284 | 2.42k | if (m_bAllowXSDCache) |
285 | 2.42k | { |
286 | 2.42k | m_osXSDCacheDirectory = |
287 | 2.42k | CPLGetXMLValue(psRoot, "=Configuration.SchemaCache.Directory", ""); |
288 | 2.42k | } |
289 | | |
290 | 2.42k | m_bSchemaFullChecking = CPLGetXMLBoolValue( |
291 | 2.42k | psRoot, "=Configuration.SchemaAnalysisOptions.SchemaFullChecking", |
292 | 2.42k | SCHEMA_FULL_CHECKING_DEFAULT); |
293 | | |
294 | 2.42k | m_bHandleMultipleImports = CPLGetXMLBoolValue( |
295 | 2.42k | psRoot, "=Configuration.SchemaAnalysisOptions.HandleMultipleImports", |
296 | 2.42k | HANDLE_MULTIPLE_IMPORTS_DEFAULT); |
297 | | |
298 | 2.42k | m_bValidate = CPLGetXMLBoolValue( |
299 | 2.42k | psRoot, "=Configuration.Validation.enabled", VALIDATE_DEFAULT); |
300 | | |
301 | 2.42k | if (m_bValidate) |
302 | 0 | { |
303 | 0 | m_bFailIfValidationError = |
304 | 0 | CPLGetXMLBoolValue(psRoot, "=Configuration.Validation.FailIfError", |
305 | 0 | FAIL_IF_VALIDATION_ERROR_DEFAULT); |
306 | 0 | } |
307 | | |
308 | 2.42k | m_bExposeMetadataLayers = |
309 | 2.42k | CPLGetXMLBoolValue(psRoot, "=Configuration.ExposeMetadataLayers", |
310 | 2.42k | EXPOSE_METADATA_LAYERS_DEFAULT); |
311 | | |
312 | 2.42k | m_bAlwaysGenerateOGRId = CPLGetXMLBoolValue( |
313 | 2.42k | psRoot, "=Configuration.LayerBuildingRules.AlwaysGenerateOGRId", |
314 | 2.42k | ALWAYS_GENERATE_OGR_ID_DEFAULT); |
315 | | |
316 | 2.42k | m_bRemoveUnusedLayers = CPLGetXMLBoolValue( |
317 | 2.42k | psRoot, "=Configuration.LayerBuildingRules.RemoveUnusedLayers", |
318 | 2.42k | REMOVE_UNUSED_LAYERS_DEFAULT); |
319 | | |
320 | 2.42k | m_bRemoveUnusedFields = CPLGetXMLBoolValue( |
321 | 2.42k | psRoot, "=Configuration.LayerBuildingRules.RemoveUnusedFields", |
322 | 2.42k | REMOVE_UNUSED_FIELDS_DEFAULT); |
323 | | |
324 | 2.42k | m_bUseArrays = CPLGetXMLBoolValue( |
325 | 2.42k | psRoot, "=Configuration.LayerBuildingRules.UseArrays", |
326 | 2.42k | USE_ARRAYS_DEFAULT); |
327 | 2.42k | m_bUseNullState = CPLGetXMLBoolValue( |
328 | 2.42k | psRoot, "=Configuration.LayerBuildingRules.UseNullState", |
329 | 2.42k | USE_NULL_STATE_DEFAULT); |
330 | 2.42k | m_bIncludeGeometryXML = CPLGetXMLBoolValue( |
331 | 2.42k | psRoot, "=Configuration.LayerBuildingRules.GML.IncludeGeometryXML", |
332 | 2.42k | INCLUDE_GEOMETRY_XML_DEFAULT); |
333 | 2.42k | m_bInstantiateGMLFeaturesOnly = CPLGetXMLBoolValue( |
334 | 2.42k | psRoot, |
335 | 2.42k | "=Configuration.LayerBuildingRules.GML.InstantiateGMLFeaturesOnly", |
336 | 2.42k | INSTANTIATE_GML_FEATURES_ONLY_DEFAULT); |
337 | 2.42k | m_nIdentifierMaxLength = atoi(CPLGetXMLValue( |
338 | 2.42k | psRoot, "=Configuration.LayerBuildingRules.IdentifierMaxLength", "0")); |
339 | 2.42k | m_bCaseInsensitiveIdentifier = CPLGetXMLBoolValue( |
340 | 2.42k | psRoot, "=Configuration.LayerBuildingRules.CaseInsensitiveIdentifier", |
341 | 2.42k | CASE_INSENSITIVE_IDENTIFIER_DEFAULT); |
342 | 2.42k | m_bPGIdentifierLaundering = CPLGetXMLBoolValue( |
343 | 2.42k | psRoot, |
344 | 2.42k | "=Configuration.LayerBuildingRules.PostgreSQLIdentifierLaundering", |
345 | 2.42k | PG_IDENTIFIER_LAUNDERING_DEFAULT); |
346 | | |
347 | 2.42k | CPLXMLNode *psFlatteningRules = CPLGetXMLNode( |
348 | 2.42k | psRoot, "=Configuration.LayerBuildingRules.FlatteningRules"); |
349 | 2.42k | if (psFlatteningRules) |
350 | 2.42k | { |
351 | 2.42k | m_nMaximumFieldsForFlattening = atoi(CPLGetXMLValue( |
352 | 2.42k | psFlatteningRules, "MaximumNumberOfFields", |
353 | 2.42k | CPLSPrintf("%d", MAXIMUM_FIELDS_FLATTENING_DEFAULT))); |
354 | | |
355 | 2.42k | ParseNamespaces(psFlatteningRules, m_oMapPrefixToURIFlatteningRules); |
356 | | |
357 | 19.4k | for (CPLXMLNode *psIter = psFlatteningRules->psChild; psIter != nullptr; |
358 | 16.9k | psIter = psIter->psNext) |
359 | 16.9k | { |
360 | 16.9k | if (psIter->eType == CXT_Element && |
361 | 7.28k | EQUAL(psIter->pszValue, "ForceFlatteningXPath")) |
362 | 2.42k | { |
363 | 2.42k | m_osForcedFlattenedXPath.push_back( |
364 | 2.42k | CPLGetXMLValue(psIter, "", "")); |
365 | 2.42k | } |
366 | 14.5k | else if (psIter->eType == CXT_Element && |
367 | 4.85k | EQUAL(psIter->pszValue, "DisableFlatteningXPath")) |
368 | 0 | { |
369 | 0 | m_osDisabledFlattenedXPath.push_back( |
370 | 0 | CPLGetXMLValue(psIter, "", "")); |
371 | 0 | } |
372 | 16.9k | } |
373 | 2.42k | } |
374 | | |
375 | 2.42k | const char *pszSWEProcessingActivation = CPLGetXMLValue( |
376 | 2.42k | psRoot, "=Configuration.LayerBuildingRules.SWEProcessing.Activation", |
377 | 2.42k | "ifSWENamespaceFoundInTopElement"); |
378 | 2.42k | if (EQUAL(pszSWEProcessingActivation, "ifSWENamespaceFoundInTopElement")) |
379 | 2.42k | m_eSWEActivationMode = SWE_ACTIVATE_IF_NAMESPACE_FOUND; |
380 | 0 | else if (CPLTestBool(pszSWEProcessingActivation)) |
381 | 0 | m_eSWEActivationMode = SWE_ACTIVATE_TRUE; |
382 | 0 | else |
383 | 0 | m_eSWEActivationMode = SWE_ACTIVATE_FALSE; |
384 | 2.42k | m_bSWEProcessDataRecord = CPLTestBool(CPLGetXMLValue( |
385 | 2.42k | psRoot, |
386 | 2.42k | "=Configuration.LayerBuildingRules.SWEProcessing.ProcessDataRecord", |
387 | 2.42k | "true")); |
388 | 2.42k | m_bSWEProcessDataArray = CPLTestBool(CPLGetXMLValue( |
389 | 2.42k | psRoot, |
390 | 2.42k | "=Configuration.LayerBuildingRules.SWEProcessing.ProcessDataArray", |
391 | 2.42k | "true")); |
392 | | |
393 | 2.42k | CPLXMLNode *psTypingConstraints = |
394 | 2.42k | CPLGetXMLNode(psRoot, "=Configuration.TypingConstraints"); |
395 | 2.42k | if (psTypingConstraints) |
396 | 2.42k | { |
397 | 2.42k | ParseNamespaces(psTypingConstraints, m_oMapPrefixToURITypeConstraints); |
398 | | |
399 | 2.42k | for (CPLXMLNode *psIter = psTypingConstraints->psChild; |
400 | 7.28k | psIter != nullptr; psIter = psIter->psNext) |
401 | 4.85k | { |
402 | 4.85k | if (psIter->eType == CXT_Element && |
403 | 4.85k | EQUAL(psIter->pszValue, "ChildConstraint")) |
404 | 2.42k | { |
405 | 2.42k | const CPLString &osXPath( |
406 | 2.42k | CPLGetXMLValue(psIter, "ContainerXPath", "")); |
407 | 2.42k | CPLXMLNode *psChildrenTypes = |
408 | 2.42k | CPLGetXMLNode(psIter, "ChildrenElements"); |
409 | 2.42k | if (IsValidXPath(osXPath)) |
410 | 2.42k | { |
411 | 2.42k | for (CPLXMLNode *psIter2 = psChildrenTypes |
412 | 2.42k | ? psChildrenTypes->psChild |
413 | 2.42k | : nullptr; |
414 | 4.85k | psIter2 != nullptr; psIter2 = psIter2->psNext) |
415 | 2.42k | { |
416 | 2.42k | if (psIter2->eType == CXT_Element && |
417 | 2.42k | EQUAL(psIter2->pszValue, "Element")) |
418 | 2.42k | { |
419 | 2.42k | m_oMapChildrenElementsConstraints[osXPath] |
420 | 2.42k | .push_back(CPLGetXMLValue(psIter2, "", "")); |
421 | 2.42k | } |
422 | 2.42k | } |
423 | 2.42k | } |
424 | 0 | else |
425 | 0 | { |
426 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
427 | 0 | "XPath syntax %s not supported", osXPath.c_str()); |
428 | 0 | } |
429 | 2.42k | } |
430 | 4.85k | } |
431 | 2.42k | } |
432 | | |
433 | 2.42k | CPLXMLNode *psIgnoredXPaths = |
434 | 2.42k | CPLGetXMLNode(psRoot, "=Configuration.IgnoredXPaths"); |
435 | 2.42k | if (psIgnoredXPaths) |
436 | 2.42k | { |
437 | 2.42k | const bool bGlobalWarnIfIgnoredXPathFound = CPLGetXMLBoolValue( |
438 | 2.42k | psIgnoredXPaths, "WarnIfIgnoredXPathFoundInDocInstance", |
439 | 2.42k | WARN_IF_EXCLUDED_XPATH_FOUND_DEFAULT); |
440 | | |
441 | 2.42k | ParseNamespaces(psIgnoredXPaths, m_oMapPrefixToURIIgnoredXPaths); |
442 | | |
443 | 65.5k | for (CPLXMLNode *psIter = psIgnoredXPaths->psChild; psIter != nullptr; |
444 | 63.1k | psIter = psIter->psNext) |
445 | 63.1k | { |
446 | 63.1k | if (psIter->eType == CXT_Element && |
447 | 60.7k | EQUAL(psIter->pszValue, "XPath")) |
448 | 55.8k | { |
449 | 55.8k | const CPLString &osXPath(CPLGetXMLValue(psIter, "", "")); |
450 | 55.8k | if (IsValidXPath(osXPath)) |
451 | 55.8k | { |
452 | 55.8k | m_aosIgnoredXPaths.push_back(osXPath); |
453 | | |
454 | 55.8k | const bool bWarnIfIgnoredXPathFound = CPLGetXMLBoolValue( |
455 | 55.8k | psIter, "warnIfIgnoredXPathFoundInDocInstance", |
456 | 55.8k | bGlobalWarnIfIgnoredXPathFound); |
457 | 55.8k | m_oMapIgnoredXPathToWarn[osXPath] = |
458 | 55.8k | bWarnIfIgnoredXPathFound; |
459 | 55.8k | } |
460 | 0 | else |
461 | 0 | { |
462 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
463 | 0 | "XPath syntax %s not supported", osXPath.c_str()); |
464 | 0 | } |
465 | 55.8k | } |
466 | 63.1k | } |
467 | 2.42k | } |
468 | | |
469 | 2.42k | CPLXMLNode *psXLinkResolutionNode = |
470 | 2.42k | CPLGetXMLNode(psRoot, "=Configuration.XLinkResolution"); |
471 | 2.42k | if (psXLinkResolutionNode != nullptr) |
472 | 2.42k | m_oXLinkResolution.LoadFromXML(psXLinkResolutionNode); |
473 | | |
474 | | // Parse WriterConfig |
475 | 2.42k | CPLXMLNode *psWriterConfig = |
476 | 2.42k | CPLGetXMLNode(psRoot, "=Configuration.WriterConfig"); |
477 | 2.42k | if (psWriterConfig != nullptr) |
478 | 2.42k | { |
479 | 2.42k | m_nIndentSize = |
480 | 2.42k | atoi(CPLGetXMLValue(psWriterConfig, "IndentationSize", |
481 | 2.42k | CPLSPrintf("%d", INDENT_SIZE_DEFAULT))); |
482 | 2.42k | m_nIndentSize = |
483 | 2.42k | std::min(INDENT_SIZE_MAX, std::max(INDENT_SIZE_MIN, m_nIndentSize)); |
484 | | |
485 | 2.42k | m_osComment = CPLGetXMLValue(psWriterConfig, "Comment", ""); |
486 | | |
487 | 2.42k | m_osLineFormat = CPLGetXMLValue(psWriterConfig, "LineFormat", ""); |
488 | | |
489 | 2.42k | m_osSRSNameFormat = CPLGetXMLValue(psWriterConfig, "SRSNameFormat", ""); |
490 | | |
491 | 2.42k | m_osWrapping = CPLGetXMLValue(psWriterConfig, "Wrapping", |
492 | 2.42k | szWFS2_FEATURECOLLECTION); |
493 | | |
494 | 2.42k | m_osTimestamp = CPLGetXMLValue(psWriterConfig, "Timestamp", ""); |
495 | | |
496 | 2.42k | m_osWFS20SchemaLocation = CPLGetXMLValue( |
497 | 2.42k | psWriterConfig, "WFS20SchemaLocation", szWFS20_SCHEMALOCATION); |
498 | 2.42k | } |
499 | | |
500 | 2.42k | Finalize(); |
501 | | |
502 | 2.42k | return true; |
503 | 2.42k | } |
504 | | |
505 | | /************************************************************************/ |
506 | | /* LoadFromXML() */ |
507 | | /************************************************************************/ |
508 | | |
509 | | bool GMLASXLinkResolutionConf::LoadFromXML(CPLXMLNode *psRoot) |
510 | 2.42k | { |
511 | 2.42k | m_nTimeOut = atoi(CPLGetXMLValue(psRoot, "Timeout", "0")); |
512 | | |
513 | 2.42k | m_nMaxFileSize = atoi(CPLGetXMLValue( |
514 | 2.42k | psRoot, "MaxFileSize", CPLSPrintf("%d", MAX_FILE_SIZE_DEFAULT))); |
515 | | |
516 | 2.42k | m_nMaxGlobalResolutionTime = |
517 | 2.42k | atoi(CPLGetXMLValue(psRoot, "MaxGlobalResolutionTime", "0")); |
518 | | |
519 | 2.42k | m_osProxyServerPort = CPLGetXMLValue(psRoot, "ProxyServerPort", ""); |
520 | 2.42k | m_osProxyUserPassword = CPLGetXMLValue(psRoot, "ProxyUserPassword", ""); |
521 | 2.42k | m_osProxyAuth = CPLGetXMLValue(psRoot, "ProxyAuth", ""); |
522 | | |
523 | 2.42k | m_osCacheDirectory = CPLGetXMLValue(psRoot, "CacheDirectory", ""); |
524 | 2.42k | if (m_osCacheDirectory.empty()) |
525 | 2.42k | { |
526 | 2.42k | m_osCacheDirectory = GDALGetCacheDirectory(); |
527 | 2.42k | if (!m_osCacheDirectory.empty()) |
528 | 2.42k | { |
529 | 2.42k | m_osCacheDirectory = CPLFormFilenameSafe( |
530 | 2.42k | m_osCacheDirectory, "xlink_resolved_cache", nullptr); |
531 | 2.42k | } |
532 | 2.42k | } |
533 | | |
534 | 2.42k | m_bDefaultResolutionEnabled = |
535 | 2.42k | CPLGetXMLBoolValue(psRoot, "DefaultResolution.enabled", |
536 | 2.42k | DEFAULT_RESOLUTION_ENABLED_DEFAULT); |
537 | | |
538 | 2.42k | m_bDefaultAllowRemoteDownload = |
539 | 2.42k | CPLGetXMLBoolValue(psRoot, "DefaultResolution.AllowRemoteDownload", |
540 | 2.42k | ALLOW_REMOTE_DOWNLOAD_DEFAULT); |
541 | | |
542 | | // TODO when we support other modes |
543 | | // m_eDefaultResolutionMode = |
544 | | |
545 | 2.42k | m_nDefaultResolutionDepth = |
546 | 2.42k | atoi(CPLGetXMLValue(psRoot, "DefaultResolution.ResolutionDepth", "1")); |
547 | | |
548 | 2.42k | m_bDefaultCacheResults = CPLGetXMLBoolValue( |
549 | 2.42k | psRoot, "DefaultResolution.CacheResults", CACHE_RESULTS_DEFAULT); |
550 | | |
551 | 2.42k | CPLXMLNode *psIterURL = psRoot->psChild; |
552 | 26.7k | for (; psIterURL != nullptr; psIterURL = psIterURL->psNext) |
553 | 24.2k | { |
554 | 24.2k | if (psIterURL->eType == CXT_Element && |
555 | 12.1k | strcmp(psIterURL->pszValue, "URLSpecificResolution") == 0) |
556 | 0 | { |
557 | 0 | GMLASXLinkResolutionConf::URLSpecificResolution oItem; |
558 | 0 | oItem.m_osURLPrefix = CPLGetXMLValue(psIterURL, "URLPrefix", ""); |
559 | |
|
560 | 0 | oItem.m_bAllowRemoteDownload = |
561 | 0 | CPLGetXMLBoolValue(psIterURL, "AllowRemoteDownload", |
562 | 0 | ALLOW_REMOTE_DOWNLOAD_DEFAULT); |
563 | |
|
564 | 0 | const char *pszResolutionModel = |
565 | 0 | CPLGetXMLValue(psIterURL, "ResolutionMode", "RawContent"); |
566 | 0 | if (EQUAL(pszResolutionModel, "RawContent")) |
567 | 0 | oItem.m_eResolutionMode = RawContent; |
568 | 0 | else |
569 | 0 | oItem.m_eResolutionMode = FieldsFromXPath; |
570 | |
|
571 | 0 | oItem.m_nResolutionDepth = |
572 | 0 | atoi(CPLGetXMLValue(psIterURL, "ResolutionDepth", "1")); |
573 | |
|
574 | 0 | oItem.m_bCacheResults = CPLGetXMLBoolValue( |
575 | 0 | psIterURL, "CacheResults", CACHE_RESULTS_DEFAULT); |
576 | |
|
577 | 0 | CPLXMLNode *psIter = psIterURL->psChild; |
578 | 0 | for (; psIter != nullptr; psIter = psIter->psNext) |
579 | 0 | { |
580 | 0 | if (psIter->eType == CXT_Element && |
581 | 0 | strcmp(psIter->pszValue, "HTTPHeader") == 0) |
582 | 0 | { |
583 | 0 | CPLString osName(CPLGetXMLValue(psIter, "Name", "")); |
584 | 0 | CPLString osValue(CPLGetXMLValue(psIter, "Value", "")); |
585 | 0 | oItem.m_aosNameValueHTTPHeaders.push_back( |
586 | 0 | std::pair<CPLString, CPLString>(osName, osValue)); |
587 | 0 | } |
588 | 0 | else if (psIter->eType == CXT_Element && |
589 | 0 | strcmp(psIter->pszValue, "Field") == 0) |
590 | 0 | { |
591 | 0 | URLSpecificResolution::XPathDerivedField oField; |
592 | 0 | oField.m_osName = CPLGetXMLValue(psIter, "Name", ""); |
593 | 0 | oField.m_osType = CPLGetXMLValue(psIter, "Type", ""); |
594 | 0 | oField.m_osXPath = CPLGetXMLValue(psIter, "XPath", ""); |
595 | 0 | oItem.m_aoFields.push_back(std::move(oField)); |
596 | 0 | } |
597 | 0 | } |
598 | |
|
599 | 0 | m_aoURLSpecificRules.push_back(std::move(oItem)); |
600 | 0 | } |
601 | 24.2k | } |
602 | | |
603 | 2.42k | m_bResolveInternalXLinks = CPLGetXMLBoolValue( |
604 | 2.42k | psRoot, "ResolveInternalXLinks", INTERNAL_XLINK_RESOLUTION_DEFAULT); |
605 | | |
606 | 2.42k | return true; |
607 | 2.42k | } |