Line data Source code
1 : /******************************************************************************
2 : * Project: OGR
3 : * Purpose: OGRGMLASDriver implementation
4 : * Author: Even Rouault, <even dot rouault at spatialys dot com>
5 : *
6 : * Initial development funded by the European Earth observation programme
7 : * Copernicus
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "ogr_gmlas.h"
32 :
33 : #include "cpl_minixml.h"
34 :
35 : #include <algorithm>
36 :
37 : /************************************************************************/
38 : /* GetBaseCacheDirectory() */
39 : /************************************************************************/
40 :
41 273 : CPLString GMLASConfiguration::GetBaseCacheDirectory()
42 : {
43 : #ifdef _WIN32
44 : const char *pszHome = CPLGetConfigOption("USERPROFILE", nullptr);
45 : #else
46 273 : const char *pszHome = CPLGetConfigOption("HOME", nullptr);
47 : #endif
48 273 : if (pszHome != nullptr)
49 : {
50 273 : return CPLFormFilename(pszHome, ".gdal", nullptr);
51 : }
52 : else
53 : {
54 0 : const char *pszDir = CPLGetConfigOption("CPL_TMPDIR", nullptr);
55 :
56 0 : if (pszDir == nullptr)
57 0 : pszDir = CPLGetConfigOption("TMPDIR", nullptr);
58 :
59 0 : if (pszDir == nullptr)
60 0 : pszDir = CPLGetConfigOption("TEMP", nullptr);
61 :
62 0 : const char *pszUsername = CPLGetConfigOption("USERNAME", nullptr);
63 0 : if (pszUsername == nullptr)
64 0 : pszUsername = CPLGetConfigOption("USER", nullptr);
65 :
66 0 : if (pszDir != nullptr && pszUsername != nullptr)
67 : {
68 : return CPLFormFilename(pszDir, CPLSPrintf(".gdal_%s", pszUsername),
69 0 : nullptr);
70 : }
71 : }
72 0 : return CPLString();
73 : }
74 :
75 : /************************************************************************/
76 : /* Finalize() */
77 : /************************************************************************/
78 :
79 207 : void GMLASConfiguration::Finalize()
80 : {
81 207 : if (m_bAllowXSDCache && m_osXSDCacheDirectory.empty())
82 : {
83 158 : m_osXSDCacheDirectory = GetBaseCacheDirectory();
84 158 : if (m_osXSDCacheDirectory.empty())
85 : {
86 0 : CPLError(CE_Warning, CPLE_AppDefined,
87 : "Could not determine a directory for GMLAS XSD cache");
88 : }
89 : else
90 : {
91 : m_osXSDCacheDirectory = CPLFormFilename(m_osXSDCacheDirectory,
92 158 : "gmlas_xsd_cache", nullptr);
93 158 : CPLDebug("GMLAS", "XSD cache directory: %s",
94 : m_osXSDCacheDirectory.c_str());
95 : }
96 : }
97 207 : }
98 :
99 : /************************************************************************/
100 : /* CPLGetXMLBoolValue() */
101 : /************************************************************************/
102 :
103 6355 : static bool CPLGetXMLBoolValue(CPLXMLNode *psNode, const char *pszKey,
104 : bool bDefault)
105 : {
106 6355 : const char *pszVal = CPLGetXMLValue(psNode, pszKey, nullptr);
107 6355 : if (pszVal)
108 2624 : return CPLTestBool(pszVal);
109 : else
110 3731 : return bDefault;
111 : }
112 :
113 : /************************************************************************/
114 : /* IsValidXPath() */
115 : /************************************************************************/
116 :
117 2786 : static bool IsValidXPath(const CPLString &osXPath)
118 : {
119 : // Check that the XPath syntax belongs to the subset we
120 : // understand
121 2786 : bool bOK = !osXPath.empty();
122 59526 : for (size_t i = 0; i < osXPath.size(); ++i)
123 : {
124 56750 : const char chCur = osXPath[i];
125 56750 : if (chCur == '/')
126 : {
127 : // OK
128 : }
129 1502 : else if (chCur == '@' && (i == 0 || osXPath[i - 1] == '/') &&
130 58244 : i < osXPath.size() - 1 &&
131 1501 : isalpha(static_cast<unsigned char>(osXPath[i + 1])))
132 : {
133 : // OK
134 : }
135 53741 : else if (chCur == '_' || isalpha(static_cast<unsigned char>(chCur)))
136 : {
137 : // OK
138 : }
139 5664 : else if (isdigit(static_cast<unsigned char>(chCur)) && i > 0 &&
140 1035 : (isalnum(static_cast<unsigned char>(osXPath[i - 1])) ||
141 0 : osXPath[i - 1] == '_'))
142 : {
143 : // OK
144 : }
145 3588 : else if (chCur == ':' && i > 0 &&
146 3587 : (isalnum(static_cast<unsigned char>(osXPath[i - 1])) ||
147 1 : osXPath[i - 1] == '_') &&
148 10767 : i < osXPath.size() - 1 &&
149 3585 : isalpha(static_cast<unsigned char>(osXPath[i + 1])))
150 : {
151 : // OK
152 : }
153 : else
154 : {
155 10 : bOK = false;
156 10 : break;
157 : }
158 : }
159 2786 : return bOK;
160 : }
161 :
162 : /************************************************************************/
163 : /* GMLASConfigurationErrorHandler() */
164 : /************************************************************************/
165 :
166 0 : static void CPL_STDCALL GMLASConfigurationErrorHandler(CPLErr /*eErr*/,
167 : CPLErrorNum /*nType*/,
168 : const char *pszMsg)
169 : {
170 : std::vector<CPLString> *paosErrors =
171 0 : static_cast<std::vector<CPLString> *>(CPLGetErrorHandlerUserData());
172 0 : paosErrors->push_back(pszMsg);
173 0 : }
174 :
175 : /************************************************************************/
176 : /* ParseNamespaces() */
177 : /************************************************************************/
178 :
179 364 : static void ParseNamespaces(CPLXMLNode *psContainerNode,
180 : std::map<CPLString, CPLString> &oMap)
181 : {
182 364 : CPLXMLNode *psNamespaces = CPLGetXMLNode(psContainerNode, "Namespaces");
183 364 : if (psNamespaces != nullptr)
184 : {
185 1046 : for (CPLXMLNode *psIter = psNamespaces->psChild; psIter != nullptr;
186 696 : psIter = psIter->psNext)
187 : {
188 696 : if (psIter->eType == CXT_Element &&
189 696 : EQUAL(psIter->pszValue, "Namespace"))
190 : {
191 : const std::string osPrefix =
192 1392 : CPLGetXMLValue(psIter, "prefix", "");
193 1392 : const std::string osURI = CPLGetXMLValue(psIter, "uri", "");
194 696 : if (!osPrefix.empty() && !osURI.empty())
195 : {
196 696 : if (oMap.find(osPrefix) == oMap.end())
197 : {
198 695 : oMap[osPrefix] = osURI;
199 : }
200 : else
201 : {
202 2 : CPLError(CE_Warning, CPLE_AppDefined,
203 : "Prefix %s was already mapped to %s. "
204 : "Attempt to map it to %s ignored",
205 2 : osPrefix.c_str(), oMap[osPrefix].c_str(),
206 : osURI.c_str());
207 : }
208 : }
209 : }
210 : }
211 : }
212 364 : }
213 :
214 : /************************************************************************/
215 : /* Load() */
216 : /************************************************************************/
217 :
218 207 : bool GMLASConfiguration::Load(const char *pszFilename)
219 : {
220 : // Allow configuration to be inlined
221 207 : CPLXMLNode *psRoot = STARTS_WITH(pszFilename, "<Configuration")
222 207 : ? CPLParseXMLString(pszFilename)
223 119 : : CPLParseXMLFile(pszFilename);
224 207 : if (psRoot == nullptr)
225 : {
226 3 : Finalize();
227 3 : return false;
228 : }
229 204 : CPLXMLTreeCloser oCloser(psRoot);
230 204 : CPL_IGNORE_RET_VAL(oCloser);
231 :
232 : // Validate the configuration file
233 204 : if (CPLTestBool(CPLGetConfigOption("GDAL_XML_VALIDATION", "YES")))
234 : {
235 44 : const char *pszXSD = CPLFindFile("gdal", "gmlasconf.xsd");
236 44 : if (pszXSD != nullptr)
237 : {
238 88 : std::vector<CPLString> aosErrors;
239 44 : const CPLErr eErrClass = CPLGetLastErrorType();
240 44 : const CPLErrorNum nErrNum = CPLGetLastErrorNo();
241 88 : const CPLString osErrMsg = CPLGetLastErrorMsg();
242 44 : CPLPushErrorHandlerEx(GMLASConfigurationErrorHandler, &aosErrors);
243 44 : int bRet = CPLValidateXML(pszFilename, pszXSD, nullptr);
244 44 : CPLPopErrorHandler();
245 44 : if (!bRet && !aosErrors.empty() &&
246 0 : strstr(aosErrors[0].c_str(), "missing libxml2 support") ==
247 : nullptr)
248 : {
249 0 : for (size_t i = 0; i < aosErrors.size(); i++)
250 : {
251 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s",
252 0 : aosErrors[i].c_str());
253 : }
254 : }
255 : else
256 : {
257 44 : CPLErrorSetState(eErrClass, nErrNum, osErrMsg);
258 : }
259 : }
260 : }
261 :
262 204 : m_bAllowRemoteSchemaDownload =
263 204 : CPLGetXMLBoolValue(psRoot, "=Configuration.AllowRemoteSchemaDownload",
264 : ALLOW_REMOTE_SCHEMA_DOWNLOAD_DEFAULT);
265 :
266 204 : m_bAllowXSDCache = CPLGetXMLBoolValue(
267 : psRoot, "=Configuration.SchemaCache.enabled", ALLOW_XSD_CACHE_DEFAULT);
268 204 : if (m_bAllowXSDCache)
269 : {
270 : m_osXSDCacheDirectory =
271 204 : CPLGetXMLValue(psRoot, "=Configuration.SchemaCache.Directory", "");
272 : }
273 :
274 204 : m_bSchemaFullChecking = CPLGetXMLBoolValue(
275 : psRoot, "=Configuration.SchemaAnalysisOptions.SchemaFullChecking",
276 : SCHEMA_FULL_CHECKING_DEFAULT);
277 :
278 204 : m_bHandleMultipleImports = CPLGetXMLBoolValue(
279 : psRoot, "=Configuration.SchemaAnalysisOptions.HandleMultipleImports",
280 : HANDLE_MULTIPLE_IMPORTS_DEFAULT);
281 :
282 204 : m_bValidate = CPLGetXMLBoolValue(
283 : psRoot, "=Configuration.Validation.enabled", VALIDATE_DEFAULT);
284 :
285 204 : if (m_bValidate)
286 : {
287 1 : m_bFailIfValidationError =
288 1 : CPLGetXMLBoolValue(psRoot, "=Configuration.Validation.FailIfError",
289 : FAIL_IF_VALIDATION_ERROR_DEFAULT);
290 : }
291 :
292 204 : m_bExposeMetadataLayers =
293 204 : CPLGetXMLBoolValue(psRoot, "=Configuration.ExposeMetadataLayers",
294 : EXPOSE_METADATA_LAYERS_DEFAULT);
295 :
296 204 : m_bAlwaysGenerateOGRId = CPLGetXMLBoolValue(
297 : psRoot, "=Configuration.LayerBuildingRules.AlwaysGenerateOGRId",
298 : ALWAYS_GENERATE_OGR_ID_DEFAULT);
299 :
300 204 : m_bRemoveUnusedLayers = CPLGetXMLBoolValue(
301 : psRoot, "=Configuration.LayerBuildingRules.RemoveUnusedLayers",
302 : REMOVE_UNUSED_LAYERS_DEFAULT);
303 :
304 204 : m_bRemoveUnusedFields = CPLGetXMLBoolValue(
305 : psRoot, "=Configuration.LayerBuildingRules.RemoveUnusedFields",
306 : REMOVE_UNUSED_FIELDS_DEFAULT);
307 :
308 204 : m_bUseArrays = CPLGetXMLBoolValue(
309 : psRoot, "=Configuration.LayerBuildingRules.UseArrays",
310 : USE_ARRAYS_DEFAULT);
311 204 : m_bUseNullState = CPLGetXMLBoolValue(
312 : psRoot, "=Configuration.LayerBuildingRules.UseNullState",
313 : USE_NULL_STATE_DEFAULT);
314 204 : m_bIncludeGeometryXML = CPLGetXMLBoolValue(
315 : psRoot, "=Configuration.LayerBuildingRules.GML.IncludeGeometryXML",
316 : INCLUDE_GEOMETRY_XML_DEFAULT);
317 204 : m_bInstantiateGMLFeaturesOnly = CPLGetXMLBoolValue(
318 : psRoot,
319 : "=Configuration.LayerBuildingRules.GML.InstantiateGMLFeaturesOnly",
320 : INSTANTIATE_GML_FEATURES_ONLY_DEFAULT);
321 204 : m_nIdentifierMaxLength = atoi(CPLGetXMLValue(
322 : psRoot, "=Configuration.LayerBuildingRules.IdentifierMaxLength", "0"));
323 204 : m_bCaseInsensitiveIdentifier = CPLGetXMLBoolValue(
324 : psRoot, "=Configuration.LayerBuildingRules.CaseInsensitiveIdentifier",
325 : CASE_INSENSITIVE_IDENTIFIER_DEFAULT);
326 204 : m_bPGIdentifierLaundering = CPLGetXMLBoolValue(
327 : psRoot,
328 : "=Configuration.LayerBuildingRules.PostgreSQLIdentifierLaundering",
329 : PG_IDENTIFIER_LAUNDERING_DEFAULT);
330 :
331 204 : CPLXMLNode *psFlatteningRules = CPLGetXMLNode(
332 : psRoot, "=Configuration.LayerBuildingRules.FlatteningRules");
333 204 : if (psFlatteningRules)
334 : {
335 115 : m_nMaximumFieldsForFlattening = atoi(CPLGetXMLValue(
336 : psFlatteningRules, "MaximumNumberOfFields",
337 : CPLSPrintf("%d", MAXIMUM_FIELDS_FLATTENING_DEFAULT)));
338 :
339 115 : ParseNamespaces(psFlatteningRules, m_oMapPrefixToURIFlatteningRules);
340 :
341 920 : for (CPLXMLNode *psIter = psFlatteningRules->psChild; psIter != nullptr;
342 805 : psIter = psIter->psNext)
343 : {
344 805 : if (psIter->eType == CXT_Element &&
345 345 : EQUAL(psIter->pszValue, "ForceFlatteningXPath"))
346 : {
347 115 : m_osForcedFlattenedXPath.push_back(
348 : CPLGetXMLValue(psIter, "", ""));
349 : }
350 690 : else if (psIter->eType == CXT_Element &&
351 230 : EQUAL(psIter->pszValue, "DisableFlatteningXPath"))
352 : {
353 0 : m_osDisabledFlattenedXPath.push_back(
354 : CPLGetXMLValue(psIter, "", ""));
355 : }
356 : }
357 : }
358 :
359 204 : const char *pszSWEProcessingActivation = CPLGetXMLValue(
360 : psRoot, "=Configuration.LayerBuildingRules.SWEProcessing.Activation",
361 : "ifSWENamespaceFoundInTopElement");
362 204 : if (EQUAL(pszSWEProcessingActivation, "ifSWENamespaceFoundInTopElement"))
363 204 : m_eSWEActivationMode = SWE_ACTIVATE_IF_NAMESPACE_FOUND;
364 0 : else if (CPLTestBool(pszSWEProcessingActivation))
365 0 : m_eSWEActivationMode = SWE_ACTIVATE_TRUE;
366 : else
367 0 : m_eSWEActivationMode = SWE_ACTIVATE_FALSE;
368 204 : m_bSWEProcessDataRecord = CPLTestBool(CPLGetXMLValue(
369 : psRoot,
370 : "=Configuration.LayerBuildingRules.SWEProcessing.ProcessDataRecord",
371 : "true"));
372 204 : m_bSWEProcessDataArray = CPLTestBool(CPLGetXMLValue(
373 : psRoot,
374 : "=Configuration.LayerBuildingRules.SWEProcessing.ProcessDataArray",
375 : "true"));
376 :
377 : CPLXMLNode *psTypingConstraints =
378 204 : CPLGetXMLNode(psRoot, "=Configuration.TypingConstraints");
379 204 : if (psTypingConstraints)
380 : {
381 118 : ParseNamespaces(psTypingConstraints, m_oMapPrefixToURITypeConstraints);
382 :
383 118 : for (CPLXMLNode *psIter = psTypingConstraints->psChild;
384 354 : psIter != nullptr; psIter = psIter->psNext)
385 : {
386 236 : if (psIter->eType == CXT_Element &&
387 236 : EQUAL(psIter->pszValue, "ChildConstraint"))
388 : {
389 : const CPLString &osXPath(
390 236 : CPLGetXMLValue(psIter, "ContainerXPath", ""));
391 : CPLXMLNode *psChildrenTypes =
392 118 : CPLGetXMLNode(psIter, "ChildrenElements");
393 118 : if (IsValidXPath(osXPath))
394 : {
395 118 : for (CPLXMLNode *psIter2 = psChildrenTypes
396 118 : ? psChildrenTypes->psChild
397 : : nullptr;
398 237 : psIter2 != nullptr; psIter2 = psIter2->psNext)
399 : {
400 119 : if (psIter2->eType == CXT_Element &&
401 119 : EQUAL(psIter2->pszValue, "Element"))
402 : {
403 119 : m_oMapChildrenElementsConstraints[osXPath]
404 119 : .push_back(CPLGetXMLValue(psIter2, "", ""));
405 : }
406 : }
407 : }
408 : else
409 : {
410 0 : CPLError(CE_Warning, CPLE_AppDefined,
411 : "XPath syntax %s not supported", osXPath.c_str());
412 : }
413 : }
414 : }
415 : }
416 :
417 : CPLXMLNode *psIgnoredXPaths =
418 204 : CPLGetXMLNode(psRoot, "=Configuration.IgnoredXPaths");
419 204 : if (psIgnoredXPaths)
420 : {
421 131 : const bool bGlobalWarnIfIgnoredXPathFound = CPLGetXMLBoolValue(
422 : psIgnoredXPaths, "WarnIfIgnoredXPathFoundInDocInstance",
423 : WARN_IF_EXCLUDED_XPATH_FOUND_DEFAULT);
424 :
425 131 : ParseNamespaces(psIgnoredXPaths, m_oMapPrefixToURIIgnoredXPaths);
426 :
427 3163 : for (CPLXMLNode *psIter = psIgnoredXPaths->psChild; psIter != nullptr;
428 3032 : psIter = psIter->psNext)
429 : {
430 3032 : if (psIter->eType == CXT_Element &&
431 2913 : EQUAL(psIter->pszValue, "XPath"))
432 : {
433 5336 : const CPLString &osXPath(CPLGetXMLValue(psIter, "", ""));
434 2668 : if (IsValidXPath(osXPath))
435 : {
436 2657 : m_aosIgnoredXPaths.push_back(osXPath);
437 :
438 2657 : const bool bWarnIfIgnoredXPathFound = CPLGetXMLBoolValue(
439 : psIter, "warnIfIgnoredXPathFoundInDocInstance",
440 : bGlobalWarnIfIgnoredXPathFound);
441 2657 : m_oMapIgnoredXPathToWarn[osXPath] =
442 : bWarnIfIgnoredXPathFound;
443 : }
444 : else
445 : {
446 11 : CPLError(CE_Warning, CPLE_AppDefined,
447 : "XPath syntax %s not supported", osXPath.c_str());
448 : }
449 : }
450 : }
451 : }
452 :
453 : CPLXMLNode *psXLinkResolutionNode =
454 204 : CPLGetXMLNode(psRoot, "=Configuration.XLinkResolution");
455 204 : if (psXLinkResolutionNode != nullptr)
456 124 : m_oXLinkResolution.LoadFromXML(psXLinkResolutionNode);
457 :
458 : // Parse WriterConfig
459 : CPLXMLNode *psWriterConfig =
460 204 : CPLGetXMLNode(psRoot, "=Configuration.WriterConfig");
461 204 : if (psWriterConfig != nullptr)
462 : {
463 115 : m_nIndentSize =
464 115 : atoi(CPLGetXMLValue(psWriterConfig, "IndentationSize",
465 : CPLSPrintf("%d", INDENT_SIZE_DEFAULT)));
466 115 : m_nIndentSize =
467 115 : std::min(INDENT_SIZE_MAX, std::max(INDENT_SIZE_MIN, m_nIndentSize));
468 :
469 115 : m_osComment = CPLGetXMLValue(psWriterConfig, "Comment", "");
470 :
471 115 : m_osLineFormat = CPLGetXMLValue(psWriterConfig, "LineFormat", "");
472 :
473 115 : m_osSRSNameFormat = CPLGetXMLValue(psWriterConfig, "SRSNameFormat", "");
474 :
475 : m_osWrapping = CPLGetXMLValue(psWriterConfig, "Wrapping",
476 115 : szWFS2_FEATURECOLLECTION);
477 :
478 115 : m_osTimestamp = CPLGetXMLValue(psWriterConfig, "Timestamp", "");
479 :
480 : m_osWFS20SchemaLocation = CPLGetXMLValue(
481 115 : psWriterConfig, "WFS20SchemaLocation", szWFS20_SCHEMALOCATION);
482 : }
483 :
484 204 : Finalize();
485 :
486 204 : return true;
487 : }
488 :
489 : /************************************************************************/
490 : /* LoadFromXML() */
491 : /************************************************************************/
492 :
493 124 : bool GMLASXLinkResolutionConf::LoadFromXML(CPLXMLNode *psRoot)
494 : {
495 124 : m_nTimeOut = atoi(CPLGetXMLValue(psRoot, "Timeout", "0"));
496 :
497 124 : m_nMaxFileSize = atoi(CPLGetXMLValue(
498 : psRoot, "MaxFileSize", CPLSPrintf("%d", MAX_FILE_SIZE_DEFAULT)));
499 :
500 124 : m_nMaxGlobalResolutionTime =
501 124 : atoi(CPLGetXMLValue(psRoot, "MaxGlobalResolutionTime", "0"));
502 :
503 124 : m_osProxyServerPort = CPLGetXMLValue(psRoot, "ProxyServerPort", "");
504 124 : m_osProxyUserPassword = CPLGetXMLValue(psRoot, "ProxyUserPassword", "");
505 124 : m_osProxyAuth = CPLGetXMLValue(psRoot, "ProxyAuth", "");
506 :
507 124 : m_osCacheDirectory = CPLGetXMLValue(psRoot, "CacheDirectory", "");
508 124 : if (m_osCacheDirectory.empty())
509 : {
510 115 : m_osCacheDirectory = GMLASConfiguration::GetBaseCacheDirectory();
511 115 : if (!m_osCacheDirectory.empty())
512 : {
513 : m_osCacheDirectory = CPLFormFilename(
514 115 : m_osCacheDirectory, "xlink_resolved_cache", nullptr);
515 : }
516 : }
517 :
518 124 : m_bDefaultResolutionEnabled =
519 124 : CPLGetXMLBoolValue(psRoot, "DefaultResolution.enabled",
520 : DEFAULT_RESOLUTION_ENABLED_DEFAULT);
521 :
522 124 : m_bDefaultAllowRemoteDownload =
523 124 : CPLGetXMLBoolValue(psRoot, "DefaultResolution.AllowRemoteDownload",
524 : ALLOW_REMOTE_DOWNLOAD_DEFAULT);
525 :
526 : // TODO when we support other modes
527 : // m_eDefaultResolutionMode =
528 :
529 124 : m_nDefaultResolutionDepth =
530 124 : atoi(CPLGetXMLValue(psRoot, "DefaultResolution.ResolutionDepth", "1"));
531 :
532 124 : m_bDefaultCacheResults = CPLGetXMLBoolValue(
533 : psRoot, "DefaultResolution.CacheResults", CACHE_RESULTS_DEFAULT);
534 :
535 124 : CPLXMLNode *psIterURL = psRoot->psChild;
536 1295 : for (; psIterURL != nullptr; psIterURL = psIterURL->psNext)
537 : {
538 1171 : if (psIterURL->eType == CXT_Element &&
539 596 : strcmp(psIterURL->pszValue, "URLSpecificResolution") == 0)
540 : {
541 10 : GMLASXLinkResolutionConf::URLSpecificResolution oItem;
542 5 : oItem.m_osURLPrefix = CPLGetXMLValue(psIterURL, "URLPrefix", "");
543 :
544 5 : oItem.m_bAllowRemoteDownload =
545 5 : CPLGetXMLBoolValue(psIterURL, "AllowRemoteDownload",
546 : ALLOW_REMOTE_DOWNLOAD_DEFAULT);
547 :
548 : const char *pszResolutionModel =
549 5 : CPLGetXMLValue(psIterURL, "ResolutionMode", "RawContent");
550 5 : if (EQUAL(pszResolutionModel, "RawContent"))
551 1 : oItem.m_eResolutionMode = RawContent;
552 : else
553 4 : oItem.m_eResolutionMode = FieldsFromXPath;
554 :
555 5 : oItem.m_nResolutionDepth =
556 5 : atoi(CPLGetXMLValue(psIterURL, "ResolutionDepth", "1"));
557 :
558 5 : oItem.m_bCacheResults = CPLGetXMLBoolValue(
559 : psIterURL, "CacheResults", CACHE_RESULTS_DEFAULT);
560 :
561 5 : CPLXMLNode *psIter = psIterURL->psChild;
562 45 : for (; psIter != nullptr; psIter = psIter->psNext)
563 : {
564 40 : if (psIter->eType == CXT_Element &&
565 40 : strcmp(psIter->pszValue, "HTTPHeader") == 0)
566 : {
567 8 : CPLString osName(CPLGetXMLValue(psIter, "Name", ""));
568 4 : CPLString osValue(CPLGetXMLValue(psIter, "Value", ""));
569 4 : oItem.m_aosNameValueHTTPHeaders.push_back(
570 12 : std::pair<CPLString, CPLString>(osName, osValue));
571 : }
572 36 : else if (psIter->eType == CXT_Element &&
573 36 : strcmp(psIter->pszValue, "Field") == 0)
574 : {
575 32 : URLSpecificResolution::XPathDerivedField oField;
576 16 : oField.m_osName = CPLGetXMLValue(psIter, "Name", "");
577 16 : oField.m_osType = CPLGetXMLValue(psIter, "Type", "");
578 16 : oField.m_osXPath = CPLGetXMLValue(psIter, "XPath", "");
579 16 : oItem.m_aoFields.push_back(oField);
580 : }
581 : }
582 :
583 5 : m_aoURLSpecificRules.push_back(oItem);
584 : }
585 : }
586 :
587 124 : m_bResolveInternalXLinks = CPLGetXMLBoolValue(
588 : psRoot, "ResolveInternalXLinks", INTERNAL_XLINK_RESOLUTION_DEFAULT);
589 :
590 124 : return true;
591 : }
|