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