Сериализация std::list в json с помощью ptree
Хорошо, так что я бьюсь головой об этом последние пару дней, но все же я не могу понять это правильно. У меня есть контейнер std:: list, и я хочу сериализовать его в строку JSON, чтобы я мог отправить его по сети.
ПРИМЕЧАНИЕ: я компилирую свой код, используя следующее:
g++ -std=c++11 -o main main.cpp DBAccess11.cpp -lsqlite3 -lboost_serialization
Ниже мой файл DBAccess1.h.
#ifndef DBAccess1_HH
#define DBAccess1_HH
#include <list> // I have deleted some header for sake of readability
#include <boost/serialization/list.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
using namespace std;
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
//================================//
struct SiteCode
{
int siteID;
int siteCode;
};
inline ostream& operator<< (ostream &out, SiteCode &site)
{
out << "(" << site.siteID << "," << site.siteCode << ")";
return out;
}
//================================//
class sqliteDB {
list<SiteCode> Site_Code_list;
public:
list<SiteCode> GET_ALL_Site_Code();
void printList();
};
#endif**
Ниже приведен файл DBAccess11.cpp, в котором определены все функции.
#include <list> // I have deleted some header for sake of readability
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/serialization/list.hpp>
#include "DBAccess1.h"
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
list<SiteCode> sqliteDB::GET_ALL_Site_Code()
{
sqlite3 *db;
const char *sql;
sqlite3_stmt * stmt;
int rc = sqlite3_open("/path/to/database.db", &db);
sql = "SELECT * FROM SiteCode;";
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
while(sqlite3_step(stmt)==SQLITE_ROW) {
int A = sqlite3_column_int(stmt, 0);
int B = sqlite3_column_int(stmt, 1);
SiteCode info;
info.siteID = A;
info.siteCode = B;
cout<<"Preparing to push data into List"<<endl;
Site_Code_list.push_back(info);
cout<<"Data was pushed successfully"<<endl;
ptree pt;
for (auto& entry: list<SiteCode> Site_Code_list) //<< ERROR LINE80
pt.put(entry.siteID, entry.siteCode);
std::ostringstream buf;
write_json (buf, pt, false);
cout<< buf.str() << endl;
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return Site_Code_list;
}
//====================================================//
void sqliteDB::printList()
{
int s = Site_Code_list.size();
cout << "The size of List is :" << s << endl;
for( list<SiteCode> :: iterator it = Site_Code_list.begin(); it != Site_Code_list.end(); it++)
cout << *it << " ";
}
Ниже main.cpp
#include <list> // I have deleted some header for sake of readability
#include <boost/serialization/list.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
using namespace std;
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
int main()
{
sqliteDB object1;
object1.GET_ALL_Site_Code();
object1.printList();
cout << "\n\nAll the statement were executed properly\n\n";
return 0;
}
Я получаю следующую ошибку:
DBAccess11.cpp: In member function ‘std::list<SiteCode> sqliteDB::GET_ALL_Site_Code()’:
DBAccess11.cpp:80:38: error: expected primary-expression before ‘Site_Code_list’
for (auto& entry: list<SiteCode> Site_Code_list)
^
DBAccess11.cpp:80:38: error: expected ‘)’ before ‘Site_Code_list’
DBAccess11.cpp:80:52: error: expected ‘;’ before ‘)’ token
for (auto& entry: list<SiteCode> Site_Code_list)
^
Мои вопросы:
(1) Это правильный способ конвертировать std:: list в JSON с использованием boost? если НЕТ, то как это сделать? (Примечание: я могу использовать только boost и никакой другой библиотеки)
(2) Если мой подход правильный, то какие изменения я должен внести, чтобы исправить это?
2 ответа
Пути в вашем дереве всегда являются строками. Компилятор сообщит вам об этом в оставшейся части сообщения. Возможно, документация является более читабельным источником:
И то и другое
key_type
а такжеdata_type
настраиваемы, но обычноstd::string
Вот
self_type & put(const path_type & path, const Type & value, Translator tr);
Таким образом, суть исправления
pt.put(std::to_string(entry.id), entry.code);
Я немного потрудился на очистке кода, так что вот так:
Автономный образец
// FILE: some header
#include <ostream>
struct SiteCode {
int id;
int code;
SiteCode(int id, int code) : id(id), code(code)
{ }
friend inline std::ostream &operator<<(std::ostream &out, SiteCode const& site) {
return out << "(" << site.id << "," << site.code << ")";
}
};
#include <list> // I have deleted some header for sake of readability
// FILE: sqliteDB header
class sqliteDB {
using Records = std::list<SiteCode>;
Records _records;
public:
void load();
Records const& get() const { return _records; }
void printList() const;
void writeJson(std::ostream& os) const;
};
// FILE: some sqlpp.hpp utility header (inline implementations only)
#include <memory>
#include <sqlite3.h>
namespace sqlpp {
using database = std::shared_ptr<::sqlite3>;
void perror(int rc) {
if (rc != SQLITE_OK) throw std::runtime_error(::sqlite3_errstr(rc));
}
struct statement {
static statement prepare(database db, std::string const& sql) {
::sqlite3_stmt* stmt = nullptr;
perror(::sqlite3_prepare_v2(db.get(), sql.c_str(), -1, &stmt, 0));
return { handle(stmt, ::sqlite3_finalize), db };
}
int step() { return ::sqlite3_step(_stmt.get()); }
int column_int(int c) { return ::sqlite3_column_int(_stmt.get(), c); }
private:
using handle = std::shared_ptr<::sqlite3_stmt>;
database _db; // keeping it around for the lifetime of _stmt
handle _stmt;
statement(handle&& h, database& db) : _db(db), _stmt(std::move(h)) { }
};
database open(char const* path) {
::sqlite3* db = nullptr;
perror(::sqlite3_open(path, &db));
return database(db, ::sqlite3_close);
}
statement prepare(database db, std::string const& sql) {
return statement::prepare(db, sql);
}
}
// FILE: sqliteDB implementation file
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
void sqliteDB::load() {
using namespace sqlpp;
auto stmt = prepare(open("/tmp/database.db"), "SELECT ID, CODE FROM SiteCode;");
while (stmt.step() == SQLITE_ROW)
_records.emplace_back(stmt.column_int(0), stmt.column_int(1));
}
void sqliteDB::writeJson(std::ostream& os) const {
using namespace boost::property_tree;
ptree pt;
for (auto &entry : _records)
pt.put(std::to_string(entry.id), entry.code);
write_json(os, pt, false);
}
// FILE: main program
template <typename List>
static void printList(List const& list) {
int s = list.size();
std::cout << "The number of Records is: " << s << "\n";
for (auto& r : list) std::cout << r << " ";
}
void dump(sqliteDB const& db) {
printList(db.get());
std::cout << "\n==============[ AS JSON ]===============\n";
db.writeJson(std::cout);
}
int main() {
sqliteDB db;
std::cout << "before loading: \n";
dump(db);
std::cout << "after loading: \n";
db.load();
dump(db);
}
Просто скомпилировать как g++ -std=c++11 -g -Wall -Wextra -pedantic main.cpp -lsqlite3
и получить:
sehe@desktop:/tmp$ sqlite3 database.db <<< "create table SiteCode (id int primary key, code int);"
sehe@desktop:/tmp$ for a in {1..10}; do echo "insert into SiteCode(ID,CODE) VALUES($a, $RANDOM);"; done | sqlite3 database.db
sehe@desktop:/tmp$ ./test
Выход
before loading:
The number of Records is: 0
==============[ AS JSON ]===============
{}
after loading:
The number of Records is: 10
(1,5591) (2,31578) (3,30641) (4,4850) (5,1628) (6,5133) (7,8798) (8,20601) (9,21213) (10,18222)
==============[ AS JSON ]===============
{"1":"5591","2":"31578","3":"30641","4":"4850","5":"1628","6":"5133","7":"8798","8":"20601","9":"21213","10":"18222"}
Хорошо, так что работаем над решением, предоставленным выше. я наконец смог получить правильный вывод. Я должен был изменить его решение согласно моей потребности. здесь ответ как ниже. Все благодарности и спасибо sehe.
Ниже мой файл DBAccess1.h:
#ifndef DBAccess1_HH
#define DBAccess1_HH
#include <sqlite3.h>
#include <list>
#include <boost/serialization/list.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
using namespace std;
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
//=========================//
struct SiteCode
{
int siteID;
int siteCode;
friend inline std::ostream &operator<<(std::ostream &out, SiteCode const& site) {
return out << "(" << site.siteID << "," << site.siteCode << ")";
}
};
//=========================//
class sqliteDB {
using Records = std::list<SiteCode>;
Records Site_Code_list;
public:
list<SiteCode> GET_ALL_Site_Code();
Records const& get() const { return Site_Code_list; }
void writeJson(std::ostream& os) const;
void printList() const;
};
#endif
Ниже находится DBAccess11.cpp
#include <ostream>
#include <boost/serialization/list.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "DBAccess1.h"
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
list<SiteCode> sqliteDB::GET_ALL_Site_Code()
{
sqlite3 *db;
const char *sql;
sqlite3_stmt * stmt;
int rc = sqlite3_open("/path.to/database.db", &db);
sql = "SELECT * FROM SiteCode;";
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
while(sqlite3_step(stmt)==SQLITE_ROW) {
int A = sqlite3_column_int(stmt, 0);
int B = sqlite3_column_int(stmt, 1);
SiteCode info;
info.siteID = A;
info.siteCode = B;
cout<<"Preparing to push data into List"<<endl;
Site_Code_list.push_back(info);
cout<<"Data was pushed successfully"<<endl;
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return Site_Code_list;
}
//==============================================================//
void sqliteDB::writeJson(std::ostream& os) const
{
using namespace boost::property_tree;
ptree pt;
for (auto &entry : Site_Code_list)
pt.put(std::to_string(entry.siteID), entry.siteCode);
write_json(os, pt, false);
}
//=========================================================//
Ниже main.cpp
#include <ostream>
#include <boost/serialization/list.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "DBAccess1.h"
using namespace std ;
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
template <typename List>
static void printList(List const& list) {
int s = list.size();
std::cout << "The number of Records is: " << s << "\n";
for (auto& r : list) std::cout << r << " ";
}
void dump(sqliteDB const& db) {
printList(db.get());
std::cout << "\n==============[ AS JSON ]===============\n";
db.writeJson(std::cout);
}
int main()
{
sqliteDB object1;
std::cout << "before loading: \n";
dump(object1);
std::cout << "after loading: \n";
object1.GET_ALL_Site_Code();
dump(object1);
return 0;
}
скомпилировал вышесказанное, используя
g++ -std=c++11 -o main main.cpp DBAccess11.cpp -lsqlite3 -lboost_serialization
И следующий вывод я получаю:
before loading:
The number of Records is: 0
==============[ AS JSON ]===============
{}
after loading:
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
The number of Records is: 10
(7,786) (8,78) (9,785) (10,998) (11,656) (13,23) (14,7) (15,74) (16,954) (17,752)
==============[ AS JSON ]===============
{"7":"786","8":"78","9":"785","10":"998","11":"656","13":"23","14":"7","15":"74","16":"954","17":"752"}