I have an object list and wanna serialize it to xml. My object is:
struct PingLogDto
{
int PingLogID;
int HardwareHostID;
std::string PingLogRoundtripTime;
};
And here i make my list just like this:
vector<PingLogDto> pingLogList;
for(int i = 0; i < 3; i++)
{
PingLogDto pingLog;
pingLog.HardwareHostID = 1;
pingLog.PingLogRoundtripTime = std::to_string(i);
pingLogList.push_back(pingLog);
}
And i send this list to a method which will serialize my object:
RequestHandler().SendPingServerLog(pingLogList);
And my method is:
void RequestHandler::SendPingServerLog(vector<PingLogDto> pingLogList)
{
std::string xml = "";
for (auto &pingLog : pingLogList)
{
std::string docStringValue;
PingLogDto pingLogDto;
PingLogDtoXml::Saver saver;
pugi::xml_document _doc;
saver(_doc.root(), "PingLog", pingLog);
std::stringstream ss;
_doc.save(ss);
docStringValue = ss.str();
xml += docStringValue;
}
std::cout<<"xml: "<<xml<<std::endl;
}
In this method; i use pugixml library for serialization. Because of non-reflection language c++, i had to do this to serialize my object. Here is my old question: How to change or delete tags in boost serialization? And my object header like this:
struct PingLogDtoXml {
struct Saver {
template <typename T>
void operator()(pugi::xml_node parent, std::string const& name, T const& value) const {
auto node = named_child(parent, name);
node.text().set(to_xml(value));
}
template <typename C>
void operator()(pugi::xml_node parent, std::string const& name, std::string const& item_name, C const& container) const {
auto list = named_child(parent, name);
for (auto& item : container)
operator()(list, item_name, item);
}
void operator()(pugi::xml_node parent, std::string const& name, PingLogDto const& o) const {
auto dto = named_child(parent, name);
operator()(dto, "PingLogID", o.PingLogID);
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "PingLogRoundtripTime", o.PingLogRoundtripTime);
}
private:
template <typename T> static T const& to_xml(T const& v) { return v; }
static char const* to_xml(std::string const& v) { return v.c_str(); }
pugi::xml_node named_child(pugi::xml_node parent, std::string const& name) const {
auto child = parent.append_child();
child.set_name(name.c_str());
return child;
}
};
struct Loader {
void operator()(pugi::xml_node parent, std::string const& name, std::string& value) const {
auto node = parent.first_element_by_path(name.c_str());
value = node.text().as_string();
}
void operator()(pugi::xml_node parent, std::string const& name, int& value) const {
auto node = parent.first_element_by_path(name.c_str());
value = node.text().as_int();
}
template <typename C>
void operator()(pugi::xml_node parent, std::string const& name, std::string const& item_name, C& container) const {
auto list = parent.first_element_by_path(name.c_str());
for (auto& node : list) {
if (node.type() != pugi::xml_node_type::node_element) {
std::cerr << "Warning: unexpected child node type ignored\n";
continue;
}
if (node.name() != item_name) {
std::cerr << "Warning: unexpected child node ignored (" << node.name() << ")\n";
continue;
}
container.emplace_back();
operator()(node, container.back());
}
}
void operator()(pugi::xml_node dto, PingLogDto& o) const {
operator()(dto, "PingLogID", o.PingLogID);
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "PingLogRoundtripTime", o.PingLogRoundtripTime);
}
void operator()(pugi::xml_node parent, std::string const& name, PingLogDto& o) const {
operator()(parent.first_element_by_path(name.c_str()), o);
}
};
};
This struct can serialize object to xml successfully. Just for clear, here my example:
PingLogDto pingLog;
pingLog.HardwareHostID = 1;
pingLog.PingLogRoundtripTime = "45";
if i serialize this pingLog object: saver(_doc.root(), "PingLog", pingLog);
print will be like this:
<?xml version="1.0"?>
<PingLog>
<PingLogID>0</PingLogID>
<HardwareHostID>1</HardwareHostID>
<PingLogRoundtripTime>45</PingLogRoundtripTime>
</PingLog>
My question is, when i serialize an array i got xml tags for each object. Here an example xml print:
<?xml version="1.0"?>
<PingLog>
<PingLogID>0</PingLogID>
<HardwareHostID>1</HardwareHostID>
<PingLogRoundtripTime>0</PingLogRoundtripTime>
<PingLogDate>123</PingLogDate>
</PingLog>
<?xml version="1.0"?>
<PingLog>
<PingLogID>0</PingLogID>
<HardwareHostID>1</HardwareHostID>
<PingLogRoundtripTime>1</PingLogRoundtripTime>
</PingLog>
<?xml version="1.0"?>
<PingLog>
<PingLogID>0</PingLogID>
<HardwareHostID>1</HardwareHostID>
<PingLogRoundtripTime>2</PingLogRoundtripTime>
</PingLog>
How can i fix this, what is my fault?
if anyone would have a problem like this; here is my solution:
i have just added another struct thanks to @Scheff who is my mentor now.
My new Xml Saver is like this:
struct Saver {
template <typename T>
void operator()(pugi::xml_node parent, std::string const& name, T const& value) const {
auto node = named_child(parent, name);
node.text().set(to_xml(value));
}
void operator()(pugi::xml_node parent, std::string const& name, PingLogDto const& o) const {
auto dto = named_child(parent, name);
operator()(dto, "PingLogID", o.PingLogID);
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "PingLogRoundtripTime", o.PingLogRoundtripTime);
}
template <typename C>
void operator()(pugi::xml_node parent, std::string const& name, std::string const& item_name, C const& container) const {
auto list = named_child(parent, name);
for (auto& item : container)
operator()(list, item_name, item);
}
void operator()(pugi::xml_node parent, std::string const& name, SendServerPingLogDto const& o) const {
auto dto = named_child(parent, name);
operator()(dto, "PingLogList", "PingLog", o.PingLogList);
}
private:
template <typename T> static T const& to_xml(T const& v) { return v; }
static char const* to_xml(std::string const& v) { return v.c_str(); }
pugi::xml_node named_child(pugi::xml_node parent, std::string const& name) const {
auto child = parent.append_child();
child.set_name(name.c_str());
return child;
}
};
And my new struct is:
struct SendServerPingLogDto {
std::vector<PingLogDto> PingLogList;
};
I'm using this struct like this:
SendServerPingLogDto sendServerPingLog;
for(int i = 0; i < 10; i++)
{
PingLogDto pingLog;
namespace pt = boost::posix_time;
pt::ptime now = pt::second_clock::local_time();
std::stringstream ss;
ss << static_cast<int>(now.date().month()) << "/" << now.date().day() << "/" << now.date().year();
pingLog.HardwareHostID = 1;
pingLog.PingLogDate = ss.str();
pingLog.PingLogID = i + 1;
pingLog.PingLogRoundtripTime = std::to_string(i);
sendServerPingLog.PingLogList.push_back(pingLog);
}
pugi::xml_document _doc;
Xml::Saver saver;
saver(_doc.root(), "SendServerPingLog", sendServerPingLog);
_doc.save_file("SendServerPingLog.xml");
The only problem is in the xml we have an unnecessary tag "" thats why i had to change my server side code too.
Anyway thank you for your comments and support.