Serializing std::list into json with boost ptree

2019-07-27 10:33发布

okay, so I am banging my head on this for last couple of days but still I am unable to get it right. I have a std::list container and I want to serialize it into JSON string so that I can send it over network.

NOTE: I compile my code using following:

g++ -std=c++11 -o main main.cpp DBAccess11.cpp -lsqlite3 -lboost_serialization

I took help of this and this

Below is my DBAccess1.h file.

#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**

Below is the DBAccess11.cpp file where all the functions are defined

#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 << " ";
}

Below is 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;
}

The error I get is as follows:

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)
                                                ^

My Questions:

(1)Is this the right way to convert std::list into JSON using boost ? if NO then how should it be done ? (Note- I can only use boost and no other library )

(2) If my approach is right then what changes shall I make to correct it ?

2条回答
够拽才男人
2楼-- · 2019-07-27 10:53

Paths in your tree are always strings. The compiler will tell you this in the remainder of the message. Arguably the documentation is a more readable source:

Both key_type and data_type are configurable, but will usually be std::string here

The self_type & put(const path_type & path, const Type & value, Translator tr);

So the essence of the fix is

pt.put(std::to_string(entry.id), entry.code);

I got a little bit side-tracked cleaning up the code, so here goes:

Self Contained Sample

// 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);
}

Just compile as g++ -std=c++11 -g -Wall -Wextra -pedantic main.cpp -lsqlite3 and get:

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

Output

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"}
查看更多
Ridiculous、
3楼-- · 2019-07-27 11:05

ok so working on the solution provide above by sehe. i finally able to get the output right. I had to modify his solution as per my need. here the answer is as per below. All credit and thanks to sehe.

Below is my DBAccess1.h file:

#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

Below is 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);
}
//=========================================================//

Below is 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;
}

compiled the above using:

g++ -std=c++11 -o main main.cpp DBAccess11.cpp -lsqlite3 -lboost_serialization 

And the following is the output I get:

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"}
查看更多
登录 后发表回答