RcsPySim
A robot control and simulation library
PropertySourceXml.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright (c) 2020, Fabio Muratore, Honda Research Institute Europe GmbH, and
3  Technical University of Darmstadt.
4  All rights reserved.
5 
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions are met:
8  1. Redistributions of source code must retain the above copyright
9  notice, this list of conditions and the following disclaimer.
10  2. 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  3. Neither the name of Fabio Muratore, Honda Research Institute Europe GmbH,
14  or Technical University of Darmstadt, nor the names of its contributors may
15  be used to endorse or promote products derived from this software without
16  specific prior written permission.
17 
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  DISCLAIMED. IN NO EVENT SHALL FABIO MURATORE, HONDA RESEARCH INSTITUTE EUROPE GMBH,
22  OR TECHNICAL UNIVERSITY OF DARMSTADT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
26  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  POSSIBILITY OF SUCH DAMAGE.
29 *******************************************************************************/
30 
31 #include "PropertySourceXml.h"
32 
33 #include <Rcs_parser.h>
34 #include <Rcs_stlParser.h>
35 #include <Rcs_macros.h>
36 #include <Rcs_resourcePath.h>
37 
38 #include <stdexcept>
39 #include <sstream>
40 
41 namespace Rcs
42 {
43 
44 
45 PropertySourceXml::PropertySourceXml(const char* configFile)
46 {
47  // Determine absolute file name of config file and copy the XML file name
48  char filename[256] = "";
49  bool fileExists = Rcs_getAbsoluteFileName(configFile, filename);
50 
51  if (!fileExists) {
52  RMSG("Resource path is:");
53  Rcs_printResourcePath();
54  RFATAL("Experiment configuration file \"%s\" not found in "
55  "ressource path - exiting", configFile ? configFile : "NULL");
56  }
57 
58  // load xml tree
59  node = parseXMLFile(filename, "Experiment", &doc);
60 }
61 
63  node(node), doc(doc)
64 {
65  RCHECK(node != NULL);
66 }
67 
69 {
70  // delete children where needed
71  for (auto& it: children) {
72  if (it.second != empty()) {
73  delete it.second;
74  }
75  }
76  for (auto& it: listChildren) {
77  for (auto le : it.second) {
78  delete le;
79  }
80  }
81  // delete doc if any
82  if (doc != NULL) {
83  xmlFreeDoc(doc);
84  }
85 }
86 
88 {
89  // will return empty() if it doesn't exist
90  return true;
91 }
92 
93 bool PropertySourceXml::getProperty(std::string& out, const char* property)
94 {
95  // check if exists
96  if (!getXMLNodeProperty(node, property)) {
97  return false;
98  }
99  // get value string
100  getXMLNodePropertySTLString(node, property, out);
101  return true;
102 }
103 
104 
105 bool PropertySourceXml::getProperty(std::vector<std::string> &out, const char *property) {
106  // check if exists
107  if (!getXMLNodeProperty(node, property)) {
108  return false;
109  }
110  getXMLNodePropertyVecSTLString(node, property, out);
111  return true;
112 }
113 
114 bool PropertySourceXml::getProperty(double& out, const char* property)
115 {
116  // check if exists
117  if (!getXMLNodeProperty(node, property)) {
118  return false;
119  }
120  // read it
121  if (!getXMLNodePropertyDouble(node, property, &out)) {
122  std::ostringstream os;
123  os << "Invalid double value: ";
124  std::string value;
125  getXMLNodePropertySTLString(node, property, value);
126  os << value;
127  throw std::invalid_argument(os.str());
128  }
129  return true;
130 }
131 
132 bool PropertySourceXml::getProperty(int& out, const char* property)
133 {
134  // check if exists
135  if (!getXMLNodeProperty(node, property)) {
136  return false;
137  }
138  // read it
139  if (!getXMLNodePropertyInt(node, property, &out)) {
140  std::ostringstream os;
141  os << "Invalid double value: ";
142  std::string value;
143  getXMLNodePropertySTLString(node, property, value);
144  os << value;
145  throw std::invalid_argument(os.str());
146  }
147  return true;
148 }
149 
150 bool PropertySourceXml::getProperty(MatNd*& out, const char* property)
151 {
152  // check if exists
153  if (!getXMLNodeProperty(node, property)) {
154  return false;
155  }
156  // split into stl vector first
157  std::vector<std::string> entries;
158  getXMLNodePropertyVecSTLString(node, property, entries);
159 
160  // create output matrix using entry count
161  out = MatNd_create(entries.size(), 1);
162 
163  // convert entries
164  for (std::size_t i = 0; i < entries.size(); ++i) {
165  // try parsing locale independently
166  std::istringstream is(entries[i]);
167  is.imbue(std::locale("C"));
168 
169  if (!(is >> out->ele[i])) {
170  // invalid format
171 
172  // be sure to destroy the allocated storage before throwing
173  MatNd_destroy(out);
174  out = NULL;
175 
176  std::ostringstream os;
177  os << "Invalid matrix entry value # " << i << ": " << entries[i];
178  throw std::invalid_argument(os.str());
179  }
180  }
181  return true;
182 }
183 
184 bool PropertySourceXml::getPropertyBool(const char* property, bool def)
185 {
186  // check if exists
187  if (!getXMLNodeProperty(node, property)) {
188  return def;
189  }
190  // read it
191  bool res;
192  getXMLNodePropertyBoolString(node, property, &res);
193  return res;
194 }
195 
197 {
198  std::string prefixStr = prefix;
199  // check if it exists already
200  auto iter = children.find(prefixStr);
201  if (iter != children.end()) {
202  return iter->second;
203  }
204  // try to get child node
205  xmlNodePtr childNode = getXMLChildByName(node, prefix);
206 
207  PropertySource* result;
208  if (childNode == NULL) {
209  result = empty();
210  }
211  else {
212  result = new PropertySourceXml(childNode);
213  }
214  children[prefixStr] = result;
215  return result;
216 }
217 
218 const std::vector<PropertySource*>& PropertySourceXml::getChildList(const char* prefix)
219 {
220  std::string prefixStr = prefix;
221  // Check if it exists already
222  auto iter = listChildren.find(prefixStr);
223  if (iter != listChildren.end()) {
224  return iter->second;
225  }
226  // Create new entry
227  auto& list = listChildren[prefixStr];
228 
229  // Find matching children
230  xmlNodePtr child = node->children;
231  while (child) {
232  if (STRCASEEQ((const char*) BAD_CAST child->name, prefix)) {
233  list.push_back(new PropertySourceXml(child));
234  }
235  child = child->next;
236  }
237 
238  return list;
239 }
240 
242 {
243  // copy subtree recursively, store in new doc.
244  xmlDocPtr cpdoc = xmlNewDoc(NULL);
245  xmlNodePtr cpnode = xmlDocCopyNode(node, cpdoc, 1);
246  xmlDocSetRootElement(cpdoc, cpnode);
247 
248  return new PropertySourceXml(node, doc);
249 }
250 
251 void PropertySourceXml::saveXML(const char* fileName, const char* rootNodeName)
252 {
253  // simple, we are already xml
254  // might need to create a temporary doc if we are a sub node
255  xmlDocPtr writeDoc = doc;
256  if (writeDoc == NULL || !isXMLNodeName(node, rootNodeName)) {
257  // use a temporary doc for writing
258  writeDoc = xmlNewDoc(NULL);
259  xmlNodePtr cpnode = xmlDocCopyNode(node, writeDoc, 1);
260  xmlNodeSetName(cpnode, BAD_CAST rootNodeName);
261  xmlDocSetRootElement(writeDoc, cpnode);
262  }
263 
264  // perform save
265  xmlIndentTreeOutput = 1;
266  xmlSaveFormatFile(fileName, writeDoc, 1);
267 
268  // delete temp doc if any
269  if (writeDoc != doc) {
270  xmlFreeDoc(writeDoc);
271  }
272 }
273 
274 
275 } /* namespace Rcs */
virtual const std::vector< PropertySource * > & getChildList(const char *prefix)
std::map< std::string, PropertySource * > children
virtual void saveXML(const char *fileName, const char *rootNodeName)
virtual bool getProperty(std::string &out, const char *property)
static PropertySource * empty()
virtual PropertySource * clone() const
virtual PropertySource * getChild(const char *prefix)
std::map< std::string, std::vector< PropertySource * > > listChildren
PropertySourceXml(xmlNodePtr node, xmlDocPtr doc=NULL)
virtual bool getPropertyBool(const char *property, bool def=false)