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 }
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
This must be inserted in all CSerializable classes implementation files.
The virtual base class which provides a unified interface for all persistent objects in MRPT.
Definition: CSerializable.h:45
This class impements a very simple database system.
virtual ~CSimpleDatabase()
Destructor.
std::string tablesName(size_t tableIndex) const
Returns the tables names in the DB.
std::map< std::string, CSimpleDatabaseTable::Ptr >::const_iterator const_iterator
bool saveAsXML(const std::string &fileName) const
Saves this database as a XML file.
void renameTable(const std::string &tableName, const std::string &newTableName)
Changes the name of a given table.
std::map< std::string, CSimpleDatabaseTable::Ptr >::iterator iterator
bool loadFromXML(const std::string &fileName)
Loads the content of this database from a a XML file.
CSimpleDatabaseTable::Ptr getTable(const std::string &tableName)
Returns the table with the indicated name.
CSimpleDatabaseTable::Ptr createTable(const std::string &name)
Creates a new table in the DB, initially empty.
void dropTable(const std::string &tableName)
Deletes the given table.
CSimpleDatabase()
Default constructor.
size_t tablesCount() const
Returns the tables count in the DB.
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...
This class implements the tables of databases.
size_t fieldIndex(const char *fieldName) const
Get the index for a given field name.
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const override
Introduces a pure virtual method responsible for writing to a CStream.
void addField(const char *fieldName)
Add a new field to the table.
size_t fieldsCount() const
Get the count of fields.
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".
void deleteRecord(size_t recordIndex)
Delete the record at the given index.
std::shared_ptr< CSimpleDatabaseTable > Ptr
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,...
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".
CSimpleDatabaseTable()
Default constructor.
size_t getRecordCount() const
Get the records count in the table.
std::string getFieldName(size_t fieldIndex) const
Get the name of a field by its index.
size_t appendRecord()
Append a new and empty record at the end of the table, and return the index of the newly added record...
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...
virtual ~CSimpleDatabaseTable()
Destructor.
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:42
Scalar * iterator
Definition: eigen_plugins.h:26
GLdouble GLdouble t
Definition: glext.h:3689
GLenum GLsizei n
Definition: glext.h:5074
GLenum GLenum GLvoid * row
Definition: glext.h:3576
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3547
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
GLenum GLsizei GLenum GLenum const GLvoid * table
Definition: glext.h:3532
GLuint in
Definition: glext.h:7274
GLuint const GLchar * name
Definition: glext.h:4054
GLsizei const GLfloat * value
Definition: glext.h:4117
GLsizei const GLchar ** string
Definition: glext.h:4101
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
static XMLCSTR getError(XMLError error)
this gives you a
Definition: xmlParser.cpp:83
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
XMLCSTR addText(XMLCSTR lpszValue, XMLElementPosition pos=-1)
Add a new text content.
Definition: xmlParser.cpp:3437
XMLNode addChild(XMLCSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1)
Add a new child node.
Definition: xmlParser.cpp:3419
static XMLNode createXMLTopNode(XMLCSTR lpszName, char isDeclaration=FALSE)
Create the top node of an XMLNode structure.
Definition: xmlParser.cpp:1414
XMLAttribute * addAttribute(XMLCSTR lpszName, XMLCSTR lpszValuev)
it will be detached from it's parents before being attached to the current XMLNode
Definition: xmlParser.cpp:3429
std::vector< std::string > vector_string
A type for passing a vector of strings.
Definition: types_simple.h:33
int _strcmpi(const char *str1, const char *str2) noexcept
An OS-independent version of strcmpi.
Definition: os.cpp:319
int nChildNode(XMLCSTR name) const
return the number of child node with specific name
Definition: xmlParser.cpp:3097
XMLAttribute getAttribute(int i=0) const
return ith attribute
Definition: xmlParser.cpp:3382
XMLCSTR getName() const
name of the node
Definition: xmlParser.cpp:3347
char isEmpty() const
is this node Empty?
Definition: xmlParser.cpp:3417
XMLNode getChildNode(int i=0) const
return ith child node
Definition: xmlParser.cpp:3402
XMLCSTR getText(int i=0) const
return ith text field
Definition: xmlParser.cpp:3397
#define MRPT_START
Definition: mrpt_macros.h:425
#define ASSERT_(f)
Definition: mrpt_macros.h:309
#define MRPT_END
Definition: mrpt_macros.h:429
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
Definition: mrpt_macros.h:181
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
Definition: mrpt_macros.h:121
This namespace provides a OS-independent interface to many useful functions: filenames manipulation,...
Definition: math_frwds.h:31
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values,...
void clear()
Clear the contents of this container.
Definition: ts_hash_map.h:189
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
unsigned __int32 uint32_t
Definition: rptypes.h:47
Main Class representing a XML node.
Definition: xmlParser.h:315
Structure used to obtain error details if the parse fails.
Definition: xmlParser.h:276
enum XMLError error
Definition: xmlParser.h:277
int nColumn
Definition: xmlParser.h:278
@ eXMLErrorNone
Definition: xmlParser.h:240
#define XMLCSTR
Definition: xmlParser.h:227



Page generated by Doxygen 1.9.1 for MRPT 1.9.9 Git: 63ea9d1f1 Thu Nov 23 00:06:53 2017 +0100 at mar 26 may 2026 12:19:29 CEST