Main MRPT website > C++ reference for MRPT 1.9.9
CSimpleDatabase.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "base-precomp.h" // Precompiled headers
11 
13 #include <mrpt/utils/CStream.h>
14 #include <mrpt/system/os.h>
15 
16 using namespace mrpt::utils;
17 using namespace mrpt::system;
18 using namespace std;
19 
20 #undef _UNICODE // JLBC
21 
22 #include "xmlparser/xmlParser.h"
23 
24 #include <iostream>
25 
26 // This must be added to any CSerializable class implementation file.
29 
30 /*---------------------------------------------------------------
31  writeToStream
32  ---------------------------------------------------------------*/
33 void CSimpleDatabase::writeToStream(
34  mrpt::utils::CStream& out, int* out_Version) const
35 {
36  if (out_Version)
37  *out_Version = 0;
38  else
39  {
40  // Save all tables in DB:
41  uint32_t n = (uint32_t)m_tables.size();
42  out << n;
43 
44  for (const_iterator i = m_tables.begin(); i != m_tables.end(); ++i)
45  {
46  out << i->first; //.c_str();
47  out << *i->second;
48  }
49  }
50 }
51 /*---------------------------------------------------------------
52  readFromStream
53  ---------------------------------------------------------------*/
55 {
56  switch (version)
57  {
58  case 0:
59  {
60  std::string aux;
61 
62  // Clear existing tables:
63  clear();
64 
65  // Load all tables in DB:
66  uint32_t n;
67  in >> n;
68 
69  for (uint32_t i = 0; i < n; i++)
70  {
71  in >> aux;
72 
74  mrpt::make_aligned_shared<CSimpleDatabaseTable>();
75  in >> (*newTb);
76 
77  m_tables[aux] = newTb;
78  }
79  }
80  break;
81  default:
83  };
84 }
85 
86 /*---------------------------------------------------------------
87  writeToStream
88  ---------------------------------------------------------------*/
90  mrpt::utils::CStream& out, int* out_Version) const
91 {
92  if (out_Version)
93  *out_Version = 0;
94  else
95  {
96  uint32_t row, col, nRec = (uint32_t)getRecordCount(),
97  nFie = (uint32_t)fieldsCount();
98 
99  out << nRec << nFie;
100 
101  for (col = 0; col < nFie; col++) out << field_names[col]; //.c_str();
102 
103  for (row = 0; row < nRec; row++)
104  for (col = 0; col < nFie; col++) out << data[row][col]; //.c_str();
105  }
106 }
107 /*---------------------------------------------------------------
108  readFromStream
109  ---------------------------------------------------------------*/
111 {
112  switch (version)
113  {
114  case 0:
115  {
116  uint32_t row, col, nRec, nFie;
117  // char str[10000];
118 
119  in >> nRec >> nFie;
120 
121  data.resize(nRec);
122  field_names.resize(nFie);
123 
124  for (col = 0; col < nFie; col++) in >> field_names[col];
125 
126  for (row = 0; row < nRec; row++)
127  {
128  data[row].resize(nFie);
129 
130  for (col = 0; col < nFie; col++) in >> data[row][col];
131  }
132  }
133  break;
134  default:
136  };
137 }
138 
139 /*---------------------------------------------------------------
140  Constructor
141  ---------------------------------------------------------------*/
143 /*---------------------------------------------------------------
144  Destructor
145  ---------------------------------------------------------------*/
147 /*---------------------------------------------------------------
148  Clear the DB
149  ---------------------------------------------------------------*/
150 void CSimpleDatabase::clear() { m_tables.clear(); }
151 /*---------------------------------------------------------------
152  getTable
153  ---------------------------------------------------------------*/
155  const std::string& tableName)
156 {
157  MRPT_START
158 
159  iterator it = m_tables.find(tableName);
160  if (it != m_tables.end()) return it->second;
161 
162  THROW_EXCEPTION_FMT("Table '%s' was not found", tableName.c_str())
163 
164  MRPT_END
165 }
166 
167 /*---------------------------------------------------------------
168  getTable
169  ---------------------------------------------------------------*/
171 {
172  MRPT_START
173 
174  ASSERT_(tableIndex < tablesCount())
175 
176  iterator it = m_tables.begin();
177  std::advance(it, tableIndex);
178  return it->second;
179 
180  MRPT_END
181 }
182 
183 /*---------------------------------------------------------------
184  tablesCount
185  ---------------------------------------------------------------*/
186 size_t CSimpleDatabase::tablesCount() const { return m_tables.size(); }
187 /*---------------------------------------------------------------
188  tablesName
189  ---------------------------------------------------------------*/
190 string CSimpleDatabase::tablesName(size_t tableIndex) const
191 {
192  MRPT_START
193 
194  ASSERT_(tableIndex < tablesCount())
195  const_iterator it = m_tables.begin();
196  std::advance(it, tableIndex);
197  return it->first;
198 
199  MRPT_END
200 }
201 
202 /*---------------------------------------------------------------
203  createTable
204  ---------------------------------------------------------------*/
206 {
208  mrpt::make_aligned_shared<CSimpleDatabaseTable>();
209  m_tables[name] = table;
210  return table;
211 }
212 
213 /*---------------------------------------------------------------
214  Constructor
215  ---------------------------------------------------------------*/
217 /*---------------------------------------------------------------
218  Destructor
219  ---------------------------------------------------------------*/
221 /*---------------------------------------------------------------
222  fieldsCount
223  ---------------------------------------------------------------*/
224 size_t CSimpleDatabaseTable::fieldsCount() const { return field_names.size(); }
225 /*---------------------------------------------------------------
226  addField
227  ---------------------------------------------------------------*/
228 void CSimpleDatabaseTable::addField(const char* fieldName)
229 {
230  field_names.push_back(string(fieldName));
231  data.clear();
232 }
233 
234 /*---------------------------------------------------------------
235  getFieldName
236  ---------------------------------------------------------------*/
237 string CSimpleDatabaseTable::getFieldName(size_t fieldIndex) const
238 {
239  MRPT_START
240 
241  ASSERT_(fieldIndex < fieldsCount());
242  return field_names[fieldIndex];
243 
244  MRPT_END
245 }
246 
247 /*---------------------------------------------------------------
248  fieldIndex
249  ---------------------------------------------------------------*/
250 size_t CSimpleDatabaseTable::fieldIndex(const char* fieldName) const
251 {
252  MRPT_START
253 
254  size_t i, n = field_names.size();
255 
256  for (i = 0; i < n; i++)
257  if (!os::_strcmpi(fieldName, field_names[i].c_str())) return (int)i;
258 
259  THROW_EXCEPTION_FMT("fieldIndex: Field '%s' not found", fieldName);
260 
261  MRPT_END
262 }
263 
264 /*---------------------------------------------------------------
265  getRecordCount
266  ---------------------------------------------------------------*/
267 size_t CSimpleDatabaseTable::getRecordCount() const { return data.size(); }
268 /*---------------------------------------------------------------
269  get
270  ---------------------------------------------------------------*/
271 string CSimpleDatabaseTable::get(size_t recordIndex, string field) const
272 {
273  MRPT_START
274  ASSERT_(recordIndex < getRecordCount());
275  return data[recordIndex][fieldIndex(field.c_str())];
276  MRPT_END
277 }
278 
279 /*---------------------------------------------------------------
280  get
281  ---------------------------------------------------------------*/
282 string CSimpleDatabaseTable::get(size_t recordIndex, size_t fieldIndex) const
283 {
284  MRPT_START
285  ASSERT_(recordIndex < getRecordCount());
286  ASSERT_(fieldIndex < fieldsCount());
287  return data[recordIndex][fieldIndex];
288  MRPT_END
289 }
290 
291 /*---------------------------------------------------------------
292  set
293  ---------------------------------------------------------------*/
294 void CSimpleDatabaseTable::set(size_t recordIndex, string field, string value)
295 {
296  MRPT_START
297 
298  ASSERT_(recordIndex < getRecordCount());
299  data[recordIndex][fieldIndex(field.c_str())] = value;
300 
301  MRPT_END
302 }
303 
304 /*---------------------------------------------------------------
305  set
306  ---------------------------------------------------------------*/
308  size_t recordIndex, size_t fieldIndex, string value)
309 {
310  MRPT_START
311 
312  ASSERT_(recordIndex < getRecordCount());
313  ASSERT_(fieldIndex < fieldsCount());
314  data[recordIndex][fieldIndex] = value;
315 
316  MRPT_END
317 }
318 
319 /*---------------------------------------------------------------
320  query
321  ---------------------------------------------------------------*/
322 int CSimpleDatabaseTable::query(string field, string value) const
323 {
324  int fieldInd, i, n = (uint32_t)getRecordCount();
325 
326  try
327  {
328  fieldInd = (uint32_t)fieldIndex(field.c_str());
329  }
330  catch (...)
331  {
332  return -1;
333  }
334 
335  for (i = 0; i < n; i++)
336  {
337  if (!os::_strcmpi(value.c_str(), data[i][fieldInd].c_str())) return i;
338  }
339 
340  // Do not found:
341  return -1;
342 }
343 
344 /*---------------------------------------------------------------
345  appendRecord
346  ---------------------------------------------------------------*/
348 {
349  vector_string new_rec;
350 
351  new_rec.resize(fieldsCount());
352  data.push_back(new_rec);
353 
354  return data.size() - 1;
355 }
356 
357 /*---------------------------------------------------------------
358  deleteRecord
359  ---------------------------------------------------------------*/
360 void CSimpleDatabaseTable::deleteRecord(size_t recordIndex)
361 {
362  MRPT_START
363  ASSERT_(recordIndex < getRecordCount())
364 
366  std::advance(it, recordIndex);
367  data.erase(it);
368 
369  MRPT_END
370 }
371 
372 /*---------------------------------------------------------------
373  saveAsXML
374  ---------------------------------------------------------------*/
375 bool CSimpleDatabase::saveAsXML(const string& fileName) const
376 {
377  try
378  {
379  // Root node:
380  XMLNode rootXml =
381  XMLNode::createXMLTopNode("CSimpleDatabase-MRPT-Object");
382 
383  // For each table:
384  for (const_iterator it = m_tables.begin(); it != m_tables.end(); ++it)
385  {
386  CSimpleDatabaseTable::Ptr t = it->second;
387  XMLNode tabNod = rootXml.addChild("table");
388  tabNod.addAttribute("name", it->first.c_str());
389 
390  // Add field descriptions:
391  // ------------------------
392  size_t nFields = t->fieldsCount();
393  size_t nRecs = t->getRecordCount();
394 
395  XMLNode fNod = tabNod.addChild("fields");
396  for (unsigned int i = 0; i < nFields; i++)
397  fNod.addChild(t->getFieldName(i).c_str());
398 
399  // Add record contents:
400  // ------------------------
401  for (unsigned int i = 0; i < nRecs; i++)
402  {
403  XMLNode recNod = tabNod.addChild("record");
404  for (size_t j = 0; j < nFields; j++)
405  {
406  XMLNode recContent =
407  recNod.addChild(t->getFieldName(j).c_str());
408  recContent.addText(t->get(i, j).c_str());
409  }
410  }
411 
412  } // end for each table.
413 
414  rootXml.writeToFile(fileName.c_str());
415 
416  return true; // Ok
417  }
418  catch (exception& e)
419  {
420  cerr << "[CSimpleDatabase::saveAsXML] Exception ignored:" << endl
421  << e.what() << endl;
422  return false; // Errors found
423  }
424  catch (...)
425  {
426  return false; // Errors found
427  }
428 }
429 
430 /*---------------------------------------------------------------
431  loadFromXML
432  ---------------------------------------------------------------*/
433 bool CSimpleDatabase::loadFromXML(const string& fileName)
434 {
435  try
436  {
437  XMLResults results;
438  XMLNode root = XMLNode::parseFile(fileName.c_str(), nullptr, &results);
439 
440  if (results.error != eXMLErrorNone)
441  {
442  cerr << "[CSimpleDatabase::loadFromXML] Error loading XML file: "
443  << XMLNode::getError(results.error) << " at line "
444  << results.nLine << ":" << results.nColumn << endl;
445  return false;
446  }
447 
448  root = root.getChildNode("CSimpleDatabase-MRPT-Object");
449  if (root.isEmpty())
450  {
451  cerr << "[CSimpleDatabase::loadFromXML] Loaded XML file does not "
452  "have a 'CSimpleDatabase-MRPT-Object' tag";
453  return false;
454  }
455 
456  // Clear previous contents:
457  clear();
458 
459  // Get tables:
460  size_t i, j, nTables = root.nChildNode("table");
461  for (i = 0; i < nTables; i++)
462  {
463  XMLNode tabNod = root.getChildNode("table", (int)i);
464  ASSERT_(!tabNod.isEmpty())
465 
466  // Create table:
468  createTable(tabNod.getAttribute("name"));
469 
470  // Create fields:
471  XMLNode fNod = tabNod.getChildNode("fields");
472  ASSERT_(!fNod.isEmpty())
473 
474  size_t nFields = fNod.nChildNode();
475  for (j = 0; j < nFields; j++)
476  {
477  t->addField(fNod.getChildNode((int)j).getName());
478  } // end for each field
479 
480  // Add record data:
481  size_t nRecs = tabNod.nChildNode("record");
482  for (size_t k = 0; k < nRecs; k++)
483  {
484  size_t recIdx = t->appendRecord();
485 
486  XMLNode recNod = tabNod.getChildNode("record", (int)k);
487  ASSERT_(!recNod.isEmpty())
488 
489  for (j = 0; j < nFields; j++)
490  {
491  XMLCSTR str =
492  recNod.getChildNode(t->getFieldName(j).c_str())
493  .getText();
494  t->set(recIdx, j, str != nullptr ? string(str) : string());
495  }
496 
497  } // end for each record
498 
499  } // for each table
500 
501  return true; // Ok
502  }
503  catch (exception& e)
504  {
505  cerr << "[CSimpleDatabase::loadFromXML] Exception ignored:" << endl
506  << e.what() << endl;
507  return false; // Errors found
508  }
509  catch (...)
510  {
511  return false; // Errors found
512  }
513 }
514 
515 /*---------------------------------------------------------------
516  dropTable
517  ---------------------------------------------------------------*/
519 {
520  MRPT_START
521 
522  iterator it = m_tables.find(tableName);
523  if (it == m_tables.end())
524  THROW_EXCEPTION_FMT("Table '%s' was not found", tableName.c_str())
525 
526  m_tables.erase(it);
527 
528  MRPT_END
529 }
530 
531 /*---------------------------------------------------------------
532  renameTable
533  ---------------------------------------------------------------*/
535  const std::string& tableName, const std::string& newTableName)
536 {
537  MRPT_START
538 
539  if (tableName == newTableName) return; // done
540 
541  iterator it = m_tables.find(tableName);
542  if (it == m_tables.end())
543  THROW_EXCEPTION_FMT("Table '%s' was not found", tableName.c_str())
544 
545  {
546  iterator itNew = m_tables.find(newTableName);
547  if (itNew != m_tables.end())
549  "A table with the name '%s' already exists",
550  newTableName.c_str())
551  }
552 
553  CSimpleDatabaseTable::Ptr tb = it->second;
554 
555  m_tables.erase(it);
556  m_tables[newTableName] = tb;
557 
558  MRPT_END
559 }
std::map< std::string, CSimpleDatabaseTable::Ptr >::const_iterator const_iterator
size_t tablesCount() const
Returns the tables count in the DB.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
GLdouble GLdouble t
Definition: glext.h:3689
std::string getFieldName(size_t fieldIndex) const
Get the name of a field by its index.
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const override
Introduces a pure virtual method responsible for writing to a CStream.
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
Definition: math_frwds.h:30
Main Class representing a XML node.
Definition: xmlParser.h:314
int nColumn
Definition: xmlParser.h:278
The virtual base class which provides a unified interface for all persistent objects in MRPT...
Definition: CSerializable.h:44
std::string get(size_t recordIndex, std::string field) const
Returns the cell content of the record indicates by its index, and the field indicated in "field"...
XMLError writeToFile(XMLCSTR filename, const char *encoding=nullptr, char nFormat=1) const
Save the content of an xmlNode inside a file.
Definition: xmlParser.cpp:806
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
This must be inserted in all CSerializable classes implementation files.
void deleteRecord(size_t recordIndex)
Delete the record at the given index.
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
GLenum GLsizei n
Definition: glext.h:5074
Scalar * iterator
Definition: eigen_plugins.h:26
bool loadFromXML(const std::string &fileName)
Loads the content of this database from a a XML file.
virtual ~CSimpleDatabase()
Destructor.
char isEmpty() const
is this node Empty?
Definition: xmlParser.cpp:3417
GLenum GLsizei GLenum GLenum const GLvoid * table
Definition: glext.h:3531
size_t fieldsCount() const
Get the count of fields.
static XMLNode createXMLTopNode(XMLCSTR lpszName, char isDeclaration=FALSE)
Create the top node of an XMLNode structure.
Definition: xmlParser.cpp:1414
STL namespace.
CSimpleDatabase()
Default constructor.
#define XMLCSTR
Definition: xmlParser.h:227
bool saveAsXML(const std::string &fileName) const
Saves this database as a XML file.
void readFromStream(mrpt::utils::CStream &in, int version) override
Introduces a pure virtual method responsible for loading from a CStream This can not be used directly...
void clear()
Clear the contents of this container.
Definition: ts_hash_map.h:189
static XMLCSTR getError(XMLError error)
this gives you a
Definition: xmlParser.cpp:83
CSimpleDatabaseTable()
Default constructor.
std::map< std::string, CSimpleDatabaseTable::Ptr >::iterator iterator
void renameTable(const std::string &tableName, const std::string &newTableName)
Changes the name of a given table.
std::vector< std::string > vector_string
A type for passing a vector of strings.
Definition: types_simple.h:33
void addField(const char *fieldName)
Add a new field to the table.
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:41
This class implements the tables of databases.
XMLAttribute getAttribute(int i=0) const
return ith attribute
Definition: xmlParser.cpp:3382
void dropTable(const std::string &tableName)
Deletes the given table.
#define MRPT_END
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
std::string tablesName(size_t tableIndex) const
Returns the tables names in the DB.
std::shared_ptr< CSimpleDatabaseTable > Ptr
CSimpleDatabaseTable::Ptr getTable(const std::string &tableName)
Returns the table with the indicated name.
GLsizei const GLchar ** string
Definition: glext.h:4101
size_t getRecordCount() const
Get the records count in the table.
This class impements a very simple database system.
static XMLNode parseFile(XMLCSTR filename, XMLCSTR tag=nullptr, XMLResults *pResults=nullptr)
Parse an XML file and return the root of a XMLNode tree representing the file.
Definition: xmlParser.cpp:2283
#define MRPT_START
XMLCSTR addText(XMLCSTR lpszValue, XMLElementPosition pos=-1)
Add a new text content.
Definition: xmlParser.cpp:3437
size_t appendRecord()
Append a new and empty record at the end of the table, and return the index of the newly added record...
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
virtual ~CSimpleDatabaseTable()
Destructor.
GLenum GLenum GLvoid * row
Definition: glext.h:3576
void set(size_t recordIndex, std::string field, std::string value)
Sets the cell content of the record indicates by its index, and the field indicated in "field"...
GLuint in
Definition: glext.h:7274
GLuint const GLchar * name
Definition: glext.h:4054
#define ASSERT_(f)
int query(std::string field, std::string value) const
Executes a query in the table, returning the record index which a given field has a given value...
enum XMLError error
Definition: xmlParser.h:277
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
XMLNode addChild(XMLCSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1)
Add a new child node.
Definition: xmlParser.cpp:3419
void readFromStream(mrpt::utils::CStream &in, int version) override
Introduces a pure virtual method responsible for loading from a CStream This can not be used directly...
GLsizei const GLfloat * value
Definition: glext.h:4117
unsigned __int32 uint32_t
Definition: rptypes.h:47
void clear()
Clears the DB.
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3546
CSimpleDatabaseTable::Ptr createTable(const std::string &name)
Creates a new table in the DB, initially empty.
size_t fieldIndex(const char *fieldName) const
Get the index for a given field name.
int nChildNode(XMLCSTR name) const
return the number of child node with specific name
Definition: xmlParser.cpp:3097
Structure used to obtain error details if the parse fails.
Definition: xmlParser.h:275
XMLNode getChildNode(int i=0) const
return ith child node
Definition: xmlParser.cpp:3402
XMLAttribute * addAttribute(XMLCSTR lpszName, XMLCSTR lpszValuev)
it will be detached from it&#39;s parents before being attached to the current XMLNode ...
Definition: xmlParser.cpp:3429
int _strcmpi(const char *str1, const char *str2) noexcept
An OS-independent version of strcmpi.
Definition: os.cpp:319



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019