appkit  1.5.1
RoadNarrows Robotics Application Kit
Xml.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: RoadNarrows Robotics Application Tool Kit
4 //
5 // Library: librnr_appkit
6 //
7 // File: Xml.cxx
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2015-07-09 17:18:10 -0600 (Thu, 09 Jul 2015) $
12  * $Rev: 4025 $
13  *
14  * \brief XML base class implementation.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  * \author Daniel Packard (daniel@roadnarrows.com)
18  *
19  * \par Copyright
20  * \h_copy 2012-2017. RoadNarrows LLC.\n
21  * http://www.roadnarrows.com\n
22  * All Rights Reserved
23  */
24 /*
25  * @EulaBegin@
26  *
27  * Permission is hereby granted, without written agreement and without
28  * license or royalty fees, to use, copy, modify, and distribute this
29  * software and its documentation for any purpose, provided that
30  * (1) The above copyright notice and the following two paragraphs
31  * appear in all copies of the source code and (2) redistributions
32  * including binaries reproduces these notices in the supporting
33  * documentation. Substantial modifications to this software may be
34  * copyrighted by their authors and need not follow the licensing terms
35  * described here, provided that the new terms are clearly indicated in
36  * all files where they apply.
37  *
38  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
39  * OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
40  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
41  * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
42  * EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
43  * THE POSSIBILITY OF SUCH DAMAGE.
44  *
45  * THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
46  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
47  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
48  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
49  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
50  *
51  * @EulaEnd@
52  */
53 ////////////////////////////////////////////////////////////////////////////////
54 
55 #include <stdio.h>
56 #include <stdarg.h>
57 #include <unistd.h>
58 #include <string.h>
59 #include <errno.h>
60 
61 #include <sstream>
62 #include <string>
63 
64 #include "rnr/tinyxml/tinyxml.h"
65 
66 #include "rnr/rnrconfig.h"
67 #include "rnr/log.h"
68 
69 #include "rnr/appkit/Xml.h"
70 
71 using namespace std;
72 using namespace rnr;
73 
74 
75 //------------------------------------------------------------------------------
76 // Xml Base Class
77 //------------------------------------------------------------------------------
78 
79 Xml::Xml(const string &strRootElem,
80  const string &strXsiUrl,
81  const string &strXslUrl) :
82  m_strRootElemName(strRootElem),
83  m_strXsiUrl(strXsiUrl),
84  m_strXslUrl(strXslUrl)
85 {
86  m_pElemRoot = NULL;
87  m_bModified = false;
88  m_bufErrMsg[0] = 0;
89 }
90 
92 {
93 }
94 
95 int Xml::loadFile(const string &strXmlFileName)
96 {
97  if( strXmlFileName.empty() )
98  {
99  setErrorMsg("No file name.");
100  LOGERROR("%s", m_bufErrMsg);
101  return RC_ERROR;
102  }
103 
104  m_strXmlFileName = strXmlFileName;
105 
106  // load and parse xml file
107  if( !m_xmlDoc.LoadFile(m_strXmlFileName.c_str()) )
108  {
109  setErrorMsg("%s[r%d,c%d]: %s.",
110  m_strXmlFileName.c_str(), m_xmlDoc.ErrorRow(),
111  m_xmlDoc.ErrorCol(), m_xmlDoc.ErrorDesc());
112  LOGERROR("%s", m_bufErrMsg);
113  return RC_ERROR;
114  }
115 
116  // <rootelem> ... </rootelem>
117  m_pElemRoot = m_xmlDoc.RootElement();
118 
119  if( m_pElemRoot == NULL )
120  {
121  setErrorMsg("Not a valid %s XML document: No root <%s> element found.",
122  m_strXmlFileName.c_str(), m_strRootElemName.c_str());
123  LOGERROR("%s", m_bufErrMsg);
124  return RC_ERROR;
125  }
126 
127  else if( strcasecmp(m_pElemRoot->Value(), m_strRootElemName.c_str()) )
128  {
129  setErrorMsg("Not a valid %s XML document: Root <%s> element not <%s>.",
130  m_strXmlFileName.c_str(), m_pElemRoot->Value(),
131  m_strRootElemName.c_str());
132  LOGERROR("%s", m_bufErrMsg);
133  return RC_ERROR;
134  }
135 
136  setModifiedState(false);
137 
138  LOGDIAG3("XMl document %s loaded.", m_strXmlFileName.c_str());
139 
140  return OK;
141 }
142 
143 int Xml::saveFile(const string &strXmlFileName)
144 {
145  if( strXmlFileName.empty() )
146  {
147  setErrorMsg("No file name.");
148  LOGERROR("%s", m_bufErrMsg);
149  return RC_ERROR;
150  }
151 
152  m_strXmlFileName = strXmlFileName;
153 
154  // save xml file
155  if( !m_xmlDoc.SaveFile(m_strXmlFileName.c_str()) )
156  {
157  setErrorMsg("%s[r%d,c%d]: %s.",
158  m_strXmlFileName.c_str(), m_xmlDoc.ErrorRow(),
159  m_xmlDoc.ErrorCol(), m_xmlDoc.ErrorDesc());
160  LOGERROR("%s", m_bufErrMsg);
161  return RC_ERROR;
162  }
163 
164  setModifiedState(false);
165 
166  LOGDIAG3("XMl document %s saved.", m_strXmlFileName.c_str());
167 
168  return OK;
169 }
170 
171 int Xml::createTemplateFile(const string &strXmlFileName,
172  const string &strMajorElemName)
173 {
174  FILE *fp;
175 
176  if( strXmlFileName.empty() )
177  {
178  setErrorMsg("No file name.");
179  LOGERROR("%s", m_bufErrMsg);
180  return RC_ERROR;
181  }
182 
183  m_strXmlFileName = strXmlFileName;
184 
185  // open file
186  if( (fp = fopen(m_strXmlFileName.c_str(), "w+")) == NULL )
187  {
188  setErrorMsg("%s: %s(errno=%d).",
189  m_strXmlFileName.c_str(), strerror(errno), errno);
190  LOGERROR("%s", m_bufErrMsg);
191  return RC_ERROR;
192  }
193 
194  makeXmlHead();
195  makeXmlTail();
196 
197  // create template of document
198  fprintf(fp, "%s", m_strXmlHead.c_str());
199  fprintf(fp, "<%s>\n</%s>\n",
200  strMajorElemName.c_str(), strMajorElemName.c_str());
201  fprintf(fp, "%s", m_strXmlTail.c_str());
202 
203  fclose(fp);
204 
205  LOGDIAG3("Created file %s.", m_strXmlFileName.c_str());
206 
207  return OK;
208 }
209 
210 bool Xml::fileExists(const string &strXmlFileName, bool bRequired)
211 {
212  bool bAccess;
213 
214  if( strXmlFileName.empty() )
215  {
216  setErrorMsg("No file name.");
217  LOGERROR("%s", m_bufErrMsg);
218  bAccess = false;
219  }
220  else
221  {
222  bAccess = access(strXmlFileName.c_str(), F_OK|R_OK|W_OK) == 0;
223  }
224 
225  if( !bAccess && bRequired )
226  {
227  setErrorMsg("%s: %s(errno=%d).",
228  strXmlFileName.c_str(), strerror(errno), errno);
229  LOGERROR("%s", m_bufErrMsg);
230  }
231 
232  return bAccess;
233 }
234 
235 TiXmlElement *Xml::getMajorElem(const string &strMajorElemName)
236 {
237  TiXmlElement *pElem;
238  const char *sValue;
239 
240  if( strMajorElemName.empty() )
241  {
242  return NULL;
243  }
244 
245  if( m_pElemRoot == NULL )
246  {
247  return NULL;
248  }
249 
250  // major secion elements
251  for(pElem = m_pElemRoot->FirstChildElement();
252  pElem != NULL;
253  pElem = pElem->NextSiblingElement())
254  {
255  sValue = pElem->Value();
256 
257  if( sValue == NULL )
258  {
259  continue;
260  }
261  else if( !strcasecmp(sValue, strMajorElemName.c_str()) )
262  {
263  return pElem;
264  }
265  }
266 
267  return NULL;
268 }
269 
270 string Xml::elemText(TiXmlElement *pElem)
271 {
272  std::string str;
273  const char *s;
274 
275  if( (pElem != NULL) && ((s = pElem->GetText()) != NULL) )
276  {
277  str = s;
278  }
279 
280  return str;
281 }
282 
283 string Xml::elemAttr(TiXmlElement *pElem, const string &strAttrName)
284 {
285  std::string str;
286  const char *s;
287 
288  if( (pElem != NULL) &&
289  !strAttrName.empty() &&
290  ((s = pElem->Attribute(strAttrName.c_str())) != NULL) )
291  {
292  str = s;
293  }
294 
295  return str;
296 }
297 
298 int Xml::strToInt(const string &str, int &val)
299 {
300  long long int val1; // must use 64-bit for linaro 32bit
301 
302  if( sscanf(str.c_str(), "%lli", &val1) != 1 )
303  {
304  LOGERROR("%s: Bad integer string representation.", str.c_str());
305  return RC_ERROR;
306  }
307 
308  val = (int)val1;
309 
310  return OK;
311 }
312 
313 int Xml::intToStr(const int val, string &str, int base)
314 {
315  char buf[64];
316 
317  switch( base )
318  {
319  case 16:
320  snprintf(buf, sizeof(buf), "0x%x", val);
321  break;
322  case 10:
323  snprintf(buf, sizeof(buf), "%d", val);
324  break;
325  case 8:
326  snprintf(buf, sizeof(buf), "0%o", val);
327  break;
328  default:
329  LOGERROR("%d: Unsupported base conversion.", base);
330  return RC_ERROR;
331  }
332 
333  buf[sizeof(buf)-1] = 0;
334 
335  str = buf;
336 
337  return OK;
338 }
339 
340 int Xml::strToDouble(const string &str, double &val)
341 {
342  if( sscanf(str.c_str(), "%lf", &val) != 1 )
343  {
344  LOGERROR("%s: Bad floating-point number string representation.",
345  str.c_str());
346  return RC_ERROR;
347  }
348 
349 
350  return OK;
351 }
352 
353 int Xml::doubleToStr(const double val, string &str)
354 {
355  char buf[64];
356 
357  snprintf(buf, sizeof(buf), "%lf", val);
358 
359  buf[sizeof(buf)-1] = 0;
360 
361  str = buf;
362 
363  return OK;
364 }
365 
367 {
368  stringstream ssStylesheetStmt;
369  stringstream ssRootStmt;
370  stringstream ssHead;
371 
372  // no stylesheet
373  if( m_strXslUrl.empty() )
374  {
375  ssStylesheetStmt << "";
376  }
377 
378  // xslt stylesheet
379  else
380  {
381  ssStylesheetStmt << "<?xml-stylestheet type=\"text/xsl\" href=\""
382  << m_strXslUrl
383  << "\"?>\n";
384  }
385 
386  // no schema
387  if( m_strXsiUrl.empty() )
388  {
389  ssRootStmt << "<" << m_strRootElemName << ">";
390  }
391 
392  // validation schema
393  else
394  {
395  ssRootStmt << "<" << m_strRootElemName << " " << XmlNsXsi << "\n"
396  << " xsi:noNamespaceSchemaLocation=\"" << m_strXsiUrl << "\">";
397  }
398 
399  ssHead << XmlDecl << "\n"
400  << ssStylesheetStmt.str() << "\n"
401  << ssRootStmt.str() << ">\n\n";
402 
403  m_strXmlHead = ssHead.str();
404 }
405 
407 {
408  m_strXmlTail = "\n</" + m_strRootElemName + ">\n";
409 }
410 
411 void Xml::setErrorMsg(const char *sFmt, ...)
412 {
413  va_list ap;
414 
415  // format error message
416  va_start(ap, sFmt);
417  vsnprintf(m_bufErrMsg, sizeof(m_bufErrMsg), sFmt, ap);
418  m_bufErrMsg[sizeof(m_bufErrMsg)-1] = 0;
419  va_end(ap);
420 }
const char *const XmlNsXsi
Definition: Xml.h:76
virtual int loadFile(const std::string &strXmlFileName)
Load XML file into DOM.
Definition: Xml.cxx:95
virtual void makeXmlHead()
Make XML document head string.
Definition: Xml.cxx:366
int intToStr(const int val, std::string &str, int base=10)
Convert integer to string.
Definition: Xml.cxx:313
std::string m_strXmlTail
xml document tail
Definition: Xml.h:325
std::string m_strXsiUrl
xml schema instance
Definition: Xml.h:319
virtual int saveFile(const std::string &strXmlFileName)
Save DOM to XML file.
Definition: Xml.cxx:143
char m_bufErrMsg[256]
error message buffer
Definition: Xml.h:330
TiXmlDocument m_xmlDoc
parsed xml DOM
Definition: Xml.h:327
std::string m_strXmlFileName
xml file path name
Definition: Xml.h:322
std::string elemText(TiXmlElement *pElem)
Get element&#39;s text.
Definition: Xml.cxx:270
virtual int createTemplateFile(const std::string &strXmlFileName, const std::string &strMajorElemName)
Create XML file with the given major element name under the root element.
Definition: Xml.cxx:171
std::string m_strRootElemName
xml top-level root element name
Definition: Xml.h:318
std::string elemAttr(TiXmlElement *pElem, const std::string &strAttrName)
Get element&#39;s attribute value.
Definition: Xml.cxx:283
int strToDouble(const std::string &str, double &val)
Convert string to double-precision floating-point number.
Definition: Xml.cxx:340
std::string m_strXslUrl
xml style sheet
Definition: Xml.h:320
void setErrorMsg(const char *sFmt,...)
Set XML error message.
Definition: Xml.cxx:411
virtual ~Xml()
Destructor.
Definition: Xml.cxx:91
bool fileExists(const std::string &strXmlFileName, bool bRequired=false)
Check that the XML file exists and has read/write access.
Definition: Xml.cxx:210
virtual void makeXmlTail()
Make XML document tail string.
Definition: Xml.cxx:406
bool m_bModified
xml [not] modified
Definition: Xml.h:329
void setModifiedState(bool bModified)
Set DOM modified state.
Definition: Xml.h:216
std::string m_strXmlHead
xml document head
Definition: Xml.h:324
TiXmlElement * m_pElemRoot
top-level root element
Definition: Xml.h:328
int doubleToStr(const double val, std::string &str)
Convert double to string.
Definition: Xml.cxx:353
TiXmlElement * getMajorElem(const std::string &strMajorElemName)
Get the major element in the DOM.
Definition: Xml.cxx:235
RoadNarrows Robotics.
Definition: Camera.h:74
int strToInt(const std::string &str, int &val)
Convert string to integer.
Definition: Xml.cxx:298
const char *const XmlDecl
Definition: Xml.h:73
XML base class.