XMLEnvironmentLoader.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2018 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "XMLEnvironmentLoader.hpp"
  14. #include "XSDSchemaParser.hpp"
  15. #include "Exceptions.hpp"
  16. std::vector<std::shared_ptr<EnvironmentNode>> XMLEnvironmentLoader::load(std::istream &in, const std::shared_ptr<SchemaItem> &pSchemaItem) const
  17. {
  18. std::vector<std::shared_ptr<EnvironmentNode>> envNodes;
  19. std::shared_ptr<EnvironmentNode> pEnvNode;
  20. pt::ptree envTree;
  21. try
  22. {
  23. pt::read_xml(in, envTree, pt::xml_parser::trim_whitespace | pt::xml_parser::no_comments);
  24. //auto rootIt = envTree.begin();
  25. // if root, want to start with rootIt, but auto match rootIt first with schemaItem, then parse on down, but want to return
  26. // envNode for the root
  27. // if not root, to through rootIt with schema item as parent for each elemement, return envNode of each item iterated
  28. std::shared_ptr<SchemaItem> pParseRootSchemaItem;
  29. for (auto envIt = envTree.begin(); envIt != envTree.end(); ++envIt)
  30. {
  31. if (envIt->first == pSchemaItem->getProperty("name"))
  32. {
  33. pParseRootSchemaItem = pSchemaItem;
  34. }
  35. else
  36. {
  37. std::vector<std::shared_ptr<SchemaItem>> children;
  38. pSchemaItem->getChildren(children, envIt->first);
  39. if (children.empty())
  40. {
  41. throw (ParseException("Unable to start parsing environment, root node element " + envIt->first + " not found"));
  42. }
  43. pParseRootSchemaItem = children[0];
  44. }
  45. pEnvNode = std::make_shared<EnvironmentNode>(pParseRootSchemaItem, envIt->first); // caller may need to set the parent
  46. parse(envIt->second, pParseRootSchemaItem, pEnvNode);
  47. envNodes.push_back(pEnvNode);
  48. }
  49. }
  50. catch (const std::exception &e)
  51. {
  52. std::string xmlError = e.what();
  53. std::string msg = "Unable to read/parse Environment file. Error = " + xmlError;
  54. throw (ParseException(msg));
  55. }
  56. return envNodes;
  57. }
  58. void XMLEnvironmentLoader::parse(const pt::ptree &envTree, const std::shared_ptr<SchemaItem> &pConfigItem, std::shared_ptr<EnvironmentNode> &pEnvNode) const
  59. {
  60. //
  61. // First see if the node has a value
  62. std::string value;
  63. try
  64. {
  65. value = envTree.get<std::string>("");
  66. if (!value.empty())
  67. {
  68. std::shared_ptr<SchemaValue> pCfgValue = pConfigItem->getItemSchemaValue();
  69. if (!pCfgValue)
  70. {
  71. pCfgValue = std::make_shared<SchemaValue>("", false);
  72. pCfgValue->setType(pConfigItem->getSchemaValueType("default"));
  73. pConfigItem->setItemSchemaValue(pCfgValue);
  74. }
  75. std::shared_ptr<EnvironmentValue> pEnvValue = std::make_shared<EnvironmentValue>(pEnvNode, pCfgValue, ""); // node's value has no name
  76. pEnvValue->setValue(value, nullptr);
  77. pEnvNode->setLocalEnvValue(pEnvValue);
  78. }
  79. }
  80. catch (...)
  81. {
  82. // do nothing
  83. }
  84. //
  85. // Find elements in environment tree cooresponding to this config item, then parse each
  86. for (auto it = envTree.begin(); it != envTree.end(); ++it)
  87. {
  88. std::string elemName = it->first;
  89. //
  90. // First see if there are attributes for this element (<xmlattr> === <element attr1="xx" attr2="yy" ...></element> The attr1 and attr2 are in this)
  91. if (elemName == "<xmlattr>")
  92. {
  93. for (auto attrIt = it->second.begin(); attrIt != it->second.end(); ++attrIt)
  94. {
  95. std::shared_ptr<SchemaValue> pSchemaValue = pConfigItem->getAttribute(attrIt->first); // note, undefined attributes in schema will return a generic schema value
  96. std::string curValue = attrIt->second.get_value<std::string>();
  97. std::shared_ptr<EnvironmentValue> pEnvValue = std::make_shared<EnvironmentValue>(pEnvNode, pSchemaValue, attrIt->first, curValue); // this is where we would use a variant
  98. pSchemaValue->addEnvironmentValue(pEnvValue);
  99. pEnvNode->addAttribute(attrIt->first, pEnvValue);
  100. // todo This is where noOutput attributes would be filled in with a value if needed, for example a component
  101. // todo element may have an informational only attribute (like IP address in thor sub elements) that is useful
  102. // todo the user, but not saved. Here is where we would fill those in.
  103. }
  104. }
  105. else
  106. {
  107. std::string typeName = it->second.get("<xmlattr>.buildSet", "");
  108. std::vector<std::shared_ptr<SchemaItem>> children;
  109. std::shared_ptr<SchemaItem> pSchemaItem;
  110. pConfigItem->getChildren(children, elemName, typeName);
  111. if (children.empty())
  112. {
  113. pSchemaItem = std::make_shared<SchemaItem>(elemName, "default", pConfigItem); // default item if none found
  114. }
  115. else if (children.size() > 1)
  116. {
  117. throw (ParseException("Ambiguous element found during parsing, unable to find schema item, element name = " + elemName + ", itemType = " + typeName));
  118. }
  119. else
  120. {
  121. pSchemaItem = children[0];
  122. }
  123. // If no schema item is found, that's ok, the node just has no defined configuration
  124. std::shared_ptr<EnvironmentNode> pElementNode = std::make_shared<EnvironmentNode>(pSchemaItem, elemName, pEnvNode);
  125. parse(it->second, pSchemaItem, pElementNode);
  126. pEnvNode->addChild(pElementNode);
  127. }
  128. }
  129. }