Сериализация std::list в json с помощью boost 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) Если мой подход правильный, то какие изменения я должен внести, чтобы исправить его?


person K.K    schedule 25.03.2015    source источник
comment
Должно быть только для (auto& entry: Site_Code_list)   -  person ForEveR    schedule 25.03.2015
comment
@ForEveR: я уже пробовал это. Я получаю следующую ошибку. DBAccess11.cpp:80:40: ошибка: нет соответствующей функции для вызова 'boost::property_tree::basic_ptree‹std::basic_string‹char›, std::basic_string‹char› ›::add(int&, int&)' pt.add(entry.siteID, entry.siteCode);   -  person K.K    schedule 25.03.2015


Ответы (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"}
person sehe    schedule 25.03.2015
comment
эй. Есть так много вещей, которые мне нужно поглотить. Я вернусь к тебе. и огромное спасибо, что нашли время ответить. - person K.K; 25.03.2015
comment
PS. основные элементы, которые я рассмотрел: время жизни объекта, безопасность исключений и DRY с использованием RAII (в основном приемы shared_ptr); разделение команд/запросов; const-корректность; правильное наименование; (модульность кода) - person sehe; 25.03.2015
comment
Я хотел бы дать вам 1000 голосов. Ваш ответ безупречен. Я изменил ваш ответ в соответствии со своими потребностями и получил желаемые результаты. Я опубликую свой ответ завтра на этой странице. У меня тоже есть несколько вопросов. - person K.K; 25.03.2015

хорошо, так что работайте над решением, предоставленным sehe выше. я, наконец, в состоянии получить правильный вывод. Мне пришлось изменить его решение в соответствии с моими потребностями. здесь ответ, как показано ниже. Все заслуги и спасибо 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"}
person K.K    schedule 26.03.2015