yaml_utils.cpp
Go to the documentation of this file.
1 
29 #include <yaml-cpp/yaml.h>
30 #include <fstream>
32 
33 #include <tesseract_common/utils.h>
35 
36 namespace tesseract_common
37 {
52 YAML::Node processYamlIncludeDirective(const YAML::Node& node, const ResourceLocator& locator)
53 {
54  if (node.Tag() == "!include")
55  {
56  // Ensure the node is scalar and contains a file path
57  if (!node.IsScalar())
58  throw std::runtime_error("!include tag must be a scalar containing the file path");
59 
60  // Resolve the file path and load the included file
61  auto included_file = node.as<std::string>();
62  auto resource = locator.locateResource(included_file);
63  if (resource == nullptr)
64  throw std::runtime_error("Unable to locate resource: " + included_file);
65 
66  return processYamlIncludeDirective(YAML::LoadFile(resource->getFilePath()), *resource);
67  }
68 
69  if (node.IsMap())
70  {
71  // Create a new map and process each key-value pair
72  YAML::Node processed_map = YAML::Node(YAML::NodeType::Map);
73  for (auto it = node.begin(); it != node.end(); ++it)
74  processed_map[it->first] = processYamlIncludeDirective(it->second, locator);
75 
76  return processed_map;
77  }
78 
79  if (node.IsSequence())
80  {
81  // Create a new sequence and process each element
82  YAML::Node processed_sequence = YAML::Node(YAML::NodeType::Sequence);
83  for (const auto& child : node)
84  processed_sequence.push_back(processYamlIncludeDirective(child, locator));
85 
86  return processed_sequence;
87  }
88 
89  // Return the node as-is for scalars and unsupported types
90  return node;
91 }
92 
93 YAML::Node loadYamlFile(const std::string& file_path, const ResourceLocator& locator)
94 {
95  auto resource = locator.locateResource(file_path);
96  YAML::Node root = YAML::LoadFile(resource->getFilePath());
97  return processYamlIncludeDirective(root, *resource);
98 }
99 
100 YAML::Node loadYamlString(const std::string& yaml_string, const ResourceLocator& locator)
101 {
102  YAML::Node root = YAML::Load(yaml_string);
103  return processYamlIncludeDirective(root, locator);
104 }
105 
106 void writeYamlToFile(const YAML::Node& node, const std::string& file_path)
107 {
108  YAML::Emitter out;
109  out << node;
110 
111  if (!out.good())
112  throw std::runtime_error("Failed to serialize YAML node: " + std::string(out.GetLastError()));
113 
114  std::ofstream file(file_path);
115  if (!file.is_open())
116  throw std::runtime_error("Failed to open file: " + file_path);
117 
118  file << out.c_str();
119  file.close();
120 }
121 
122 void checkForUnknownKeys(const YAML::Node& node, const std::set<std::string>& expected_keys)
123 {
124  if (!node.IsMap())
125  throw std::runtime_error("checkForUnknownKeys, node should be a map");
126 
127  for (YAML::const_iterator it = node.begin(); it != node.end(); ++it)
128  {
129  auto key = it->first.as<std::string>();
130  if (expected_keys.find(key) == expected_keys.end())
131  throw std::runtime_error("checkForUnknownKeys, unknown key: " + key);
132  }
133 }
134 
135 std::string toYAMLString(const YAML::Node& node)
136 {
137  std::stringstream stream;
138  stream << node;
139  return stream.str();
140 }
141 
142 YAML::Node fromYAMLString(const std::string& string) { return YAML::Load(string); }
143 
144 bool compareYAML(const YAML::Node& node1, const YAML::Node& node2)
145 {
146  if (node1.is(node2))
147  return true;
148 
149  if (node1.Type() != node2.Type())
150  return false;
151 
152  switch (node1.Type())
153  {
154  case YAML::NodeType::Scalar:
155  {
156  try
157  {
158  auto v1 = node1.as<bool>();
159  auto v2 = node2.as<bool>();
160  return (v1 == v2);
161  }
162  catch (YAML::TypedBadConversion<bool>& /*e*/)
163  {
164  try
165  {
166  auto v1 = node1.as<int>();
167  auto v2 = node2.as<int>();
168  return (v1 == v2);
169  }
170  catch (YAML::TypedBadConversion<int>& /*e*/)
171  {
172  try
173  {
174  auto v1 = node1.as<double>();
175  auto v2 = node2.as<double>();
176  return almostEqualRelativeAndAbs(v1, v2, 1e-6, std::numeric_limits<float>::epsilon());
177  }
178  catch (YAML::TypedBadConversion<double>& /*e*/)
179  {
180  try
181  {
182  auto v1 = node1.as<std::string>();
183  auto v2 = node2.as<std::string>();
184  return (v1 == v2);
185  }
186  catch (YAML::TypedBadConversion<std::string>& /*e*/)
187  {
188  return false;
189  }
190  }
191  }
192  }
193  }
194  case YAML::NodeType::Null:
195  return true;
196  case YAML::NodeType::Undefined:
197  return false;
198  case YAML::NodeType::Map:
199  case YAML::NodeType::Sequence:
200  if (node1.size() != node2.size())
201  return false;
202  }
203 
204  if (node1.IsMap())
205  {
206  bool result = true;
207  for (YAML::const_iterator it1 = node1.begin(), it2; it1 != node1.end() && result; ++it1)
208  {
209  for (it2 = node2.begin(); it2 != node2.end(); ++it2)
210  {
211  if (compareYAML(it1->first, it2->first))
212  break;
213  }
214  if (it2 == node2.end())
215  return false;
216 
217  result = compareYAML(it1->second, it2->second);
218  }
219  return result;
220  }
221 
222  return std::equal(node1.begin(), node1.end(), node2.begin(), compareYAML);
223 }
224 } // namespace tesseract_common
tesseract_common::processYamlIncludeDirective
YAML::Node processYamlIncludeDirective(const YAML::Node &node, const ResourceLocator &locator)
Recursively processes a YAML node to resolve !include directives.
Definition: yaml_utils.cpp:52
tesseract_common::writeYamlToFile
void writeYamlToFile(const YAML::Node &node, const std::string &file_path)
Writes a YAML::Node to a file.
Definition: yaml_utils.cpp:106
tesseract_common
Definition: allowed_collision_matrix.h:19
tesseract_common::compareYAML
bool compareYAML(const YAML::Node &node1, const YAML::Node &node2)
Checks if the YAML::Nodes are identical.
Definition: yaml_utils.cpp:144
macros.h
Common Tesseract Macros.
tesseract_common::ResourceLocator::locateResource
virtual std::shared_ptr< Resource > locateResource(const std::string &url) const =0
Locate a resource based on a URL.
TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
#define TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
Definition: macros.h:71
tesseract_common::checkForUnknownKeys
void checkForUnknownKeys(const YAML::Node &node, const std::set< std::string > &expected_keys)
Check node map for unknown keys.
Definition: yaml_utils.cpp:122
tesseract_common::almostEqualRelativeAndAbs
bool almostEqualRelativeAndAbs(double a, double b, double max_diff=1e-6, double max_rel_diff=std::numeric_limits< double >::epsilon())
Check if two double are relatively equal.
Definition: utils.cpp:445
utils.h
Common Tesseract Utility Functions.
tesseract_common::ResourceLocator
Abstract class for resource loaders.
Definition: resource_locator.h:53
tesseract_common::loadYamlString
YAML::Node loadYamlString(const std::string &yaml_string, const ResourceLocator &locator)
Definition: yaml_utils.cpp:100
tesseract_common::loadYamlFile
YAML::Node loadYamlFile(const std::string &file_path, const ResourceLocator &locator)
Loads a YAML file and processes !include directives recursively.
Definition: yaml_utils.cpp:93
tesseract_common::fromYAMLString
YAML::Node fromYAMLString(const std::string &string)
Converts yaml string to a YAML::Node.
Definition: yaml_utils.cpp:142
TESSERACT_COMMON_IGNORE_WARNINGS_POP
#define TESSERACT_COMMON_IGNORE_WARNINGS_POP
Definition: macros.h:72
resource_locator.h
Locate and retrieve resource data.
tesseract_common::toYAMLString
std::string toYAMLString(const YAML::Node &node)
Converts a YAML::Node to a yaml string.
Definition: yaml_utils.cpp:135


tesseract_common
Author(s): Levi Armstrong
autogenerated on Sun May 18 2025 03:01:40