xml_loader.cpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2018, University of Edinburgh
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of nor the names of its contributors may be used to
14 // endorse or promote products derived from this software without specific
15 // prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
28 //
29 
30 #include <tinyxml2.h>
31 
33 #include <exotica_core/setup.h>
34 
35 namespace exotica
36 {
37 std::shared_ptr<XMLLoader> XMLLoader::instance_ = nullptr;
38 
39 XMLLoader::XMLLoader() = default;
40 
41 bool parseXML(tinyxml2::XMLHandle& tag, Initializer& parent, const std::string& prefix);
42 
43 void appendChildXML(Initializer& parent, std::string& name, bool isAttribute, tinyxml2::XMLHandle& tag, const std::string& prefix)
44 {
45  if (isAttribute)
46  {
47  // Attributes are always a regular property
48  std::string value = tag.ToElement()->Attribute(name.c_str());
49  parent.AddProperty(Property(name, true, value));
50  }
51  else
52  {
53  int count = 0;
54  for (tinyxml2::XMLHandle child = tag.FirstChild(); child.ToNode(); child = child.NextSibling())
55  if (child.ToElement() != nullptr) ++count;
56  if (count == 0)
57  {
58  if (tag.ToElement() == nullptr) return;
59 
60  if (!tag.ToElement()->GetText())
61  {
62  // No child tags = this is an empty vector of properties
63  return;
64  }
65  const std::string value = tag.ToElement()->GetText();
66  parent.AddProperty(Property(name, true, value));
67  }
68  else
69  {
70  // Child tags found = this is an initializer
71  // All initializers are treated as a vector
72  std::vector<Initializer> ret;
73  tinyxml2::XMLHandle child_tag = tag.FirstChild();
74  while (child_tag.ToNode())
75  {
76  if (child_tag.ToElement() == nullptr)
77  {
78  child_tag = child_tag.NextSibling();
79  continue;
80  }
81  ret.push_back(Initializer("New" + name));
82  if (!parseXML(child_tag, ret[ret.size() - 1], prefix + "- "))
83  {
84  ret.pop_back();
85  }
86  else
87  {
88  //HIGHLIGHT(prefix<<". Adding parsed vector element "<<name<<" to " << parent.GetName());
89  }
90  child_tag = child_tag.NextSibling();
91  }
92  parent.AddProperty(Property(name, true, ret));
93  }
94  }
95 }
96 
97 // Parses an Initializer parameters from ints attributes and child tags
98 bool parseXML(tinyxml2::XMLHandle& tag, Initializer& parent, const std::string& prefix)
99 {
100  // Get the name
101  std::string name = std::string(tag.ToElement()->Name());
102  //HIGHLIGHT(prefix<<name<<" added");
103  parent.SetName("exotica/" + name);
104 
105  // Parse values stored in attributes
106  tinyxml2::XMLAttribute* attr = const_cast<tinyxml2::XMLAttribute*>(tag.ToElement()->FirstAttribute());
107  while (attr)
108  {
109  std::string member_name = attr->Name();
110  appendChildXML(parent, member_name, true, tag, prefix + "- ");
111  attr = const_cast<tinyxml2::XMLAttribute*>(attr->Next());
112  }
113 
114  // Parse values stored in tags
115  tinyxml2::XMLHandle member_tag = tag.FirstChild();
116  while (member_tag.ToNode())
117  {
118  if (member_tag.ToElement() == nullptr)
119  {
120  member_tag = member_tag.NextSibling();
121  continue;
122  }
123  std::string member_name = std::string(member_tag.ToElement()->Name());
124  appendChildXML(parent, member_name, false, member_tag, prefix + "- ");
125  member_tag = member_tag.NextSibling();
126  }
127  //HIGHLIGHT(prefix<<name<<" finished parsing");
128  return true;
129 }
130 
131 Initializer XMLLoader::LoadXML(std::string file_name, bool parsePathAsXML)
132 {
133  tinyxml2::XMLDocument xml_file;
134  if (parsePathAsXML)
135  {
136  if (xml_file.Parse(file_name.c_str()) != tinyxml2::XML_SUCCESS)
137  {
138  ThrowPretty("Can't load file!\nFile: '" + file_name + "'");
139  }
140  }
141  else
142  {
143  std::string xml = LoadFile(file_name); // assume it is a null-terminated string
144  if (xml_file.Parse(xml.c_str()) != tinyxml2::XML_SUCCESS)
145  {
146  ThrowPretty("Can't load file!\nFile: '" + ParsePath(file_name) + "'");
147  }
148  }
149 
150  Initializer ret("TopLevel");
151  tinyxml2::XMLHandle root_tag(xml_file.RootElement()->FirstChildElement());
152  if (!parseXML(root_tag, ret, ""))
153  {
154  ThrowPretty("Can't parse XML!\nFile: '" + file_name + "'");
155  }
156  return ret;
157 }
158 
159 void XMLLoader::LoadXML(std::string file_name, Initializer& solver, Initializer& problem, const std::string& solver_name, const std::string& problem_name, bool parsePathAsXML)
160 {
161  tinyxml2::XMLDocument xml_file;
162  if (parsePathAsXML)
163  {
164  if (xml_file.Parse(file_name.c_str()) != tinyxml2::XML_SUCCESS)
165  {
166 #ifdef TINYXML_HAS_ERROR_STR
167  ThrowPretty("Can't load file!\n"
168  << xml_file.ErrorStr() << "\nFile: '" + file_name + "'");
169 #else
170  ThrowPretty("Can't load file!"
171  << "\nFile: '" + file_name + "'");
172 #endif
173  }
174  }
175  else
176  {
177  std::string xml = LoadFile(file_name); // assume LoadFile returns a null-terminated string
178  tinyxml2::XMLError return_code = xml_file.Parse(xml.c_str());
179  if (xml_file.Error())
180  {
181 #ifdef TINYXML_HAS_ERROR_STR
182  ThrowPretty("Can't load file! Return code: " << return_code << "\n"
183  << xml_file.ErrorStr() << "\nFile: '" + ParsePath(file_name) + "'");
184 #else
185  ThrowPretty("Can't load file! Return code: " << return_code << "\n"
186  << "File: '" + ParsePath(file_name) + "'");
187 #endif
188  }
189  }
190 
191  std::vector<Initializer> initializers;
192  tinyxml2::XMLHandle root_tag(xml_file.RootElement()->FirstChild());
193  while (root_tag.ToNode())
194  {
195  if (root_tag.ToElement() == nullptr)
196  {
197  root_tag = root_tag.NextSibling();
198  continue;
199  }
200  initializers.push_back(Initializer("TopLevel"));
201  if (!parseXML(root_tag, initializers[initializers.size() - 1], ""))
202  {
203  initializers.pop_back();
204  }
205  root_tag = root_tag.NextSibling();
206  }
207  bool found_solver = false;
208  bool found_problem = false;
209  if (solver_name.empty() || solver_name == "")
210  {
211  for (Initializer& i : initializers)
212  {
213  std::string initializer_type = i.GetName();
214  if (!found_solver)
215  {
216  for (std::string known_type : Setup::GetSolvers())
217  {
218  if (known_type == initializer_type)
219  {
220  solver = i;
221  found_solver = true;
222  break;
223  }
224  }
225  }
226  if (!found_problem)
227  {
228  for (std::string known_type : Setup::GetProblems())
229  {
230  if (known_type == initializer_type)
231  {
232  problem = i;
233  found_problem = true;
234  break;
235  }
236  }
237  }
238  }
239  }
240  else
241  {
242  for (Initializer& i : initializers)
243  {
244  std::string name = boost::any_cast<std::string>(i.GetProperty("Name"));
245  if (name == solver_name)
246  {
247  solver = i;
248  found_solver = true;
249  }
250  if (name == problem_name)
251  {
252  problem = i;
253  found_problem = true;
254  }
255  }
256  }
257  if (!found_solver) ThrowPretty("Can't find solver '" + solver_name + "' in '" + file_name + "'!");
258  if (!found_problem) ThrowPretty("Can't find problem '" + problem_name + "' in '" + file_name + "'!");
259 }
260 } // namespace exotica
static std::shared_ptr< XMLLoader > instance_
Definition: xml_loader.h:91
#define ThrowPretty(m)
Definition: exception.h:36
std::string LoadFile(const std::string &path)
Definition: tools.cpp:184
void appendChildXML(Initializer &parent, std::string &name, bool isAttribute, tinyxml2::XMLHandle &tag, const std::string &prefix)
Definition: xml_loader.cpp:43
void SetName(const std::string &name)
Definition: property.cpp:108
static std::vector< std::string > GetProblems()
Definition: setup.cpp:162
Initializer LoadXML(std::string file_name, bool parsePathAsXML=false)
Definition: xml_loader.cpp:131
void AddProperty(const Property &prop)
Definition: property.cpp:80
std::string ParsePath(const std::string &path)
Definition: tools.cpp:145
bool parseXML(tinyxml2::XMLHandle &tag, Initializer &parent, const std::string &prefix)
Definition: xml_loader.cpp:98
static std::vector< std::string > GetSolvers()
Definition: setup.cpp:161


exotica_core
Author(s): Yiming Yang, Michael Camilleri
autogenerated on Sat Apr 10 2021 02:34:49