C ++使用for循环将对象列表序列化为XML
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C ++使用for循环将对象列表序列化为XML相关的知识,希望对你有一定的参考价值。
我有一个对象列表,并想将其序列化为xml。我的目标是:
struct PingLogDto
{
int PingLogID;
int HardwareHostID;
std::string PingLogRoundtripTime;
};
在这里我将我的列表如下:
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);
}
我将此列表发送到将序列化我的对象的方法:
RequestHandler().SendPingServerLog(pingLogList);
我的方法是:
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;
}
在这种方法中;我使用pugixml库进行序列化。由于非反射语言c ++,我不得不这样做来序列化我的对象。这是我的老问题:How to change or delete tags in boost serialization?和我的对象标题如下:
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
";
continue;
}
if (node.name() != item_name) {
std::cerr << "Warning: unexpected child node ignored (" << node.name() << ")
";
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);
}
};
};
此结构可以成功将对象序列化为xml。只是为了清楚,这是我的例子:
PingLogDto pingLog;
pingLog.HardwareHostID = 1;
pingLog.PingLogRoundtripTime = "45";
如果我序列化这个pingLog对象:saver(_doc.root(),“PingLog”,pingLog);
打印将是这样的:
<?xml version="1.0"?>
<PingLog>
<PingLogID>0</PingLogID>
<HardwareHostID>1</HardwareHostID>
<PingLogRoundtripTime>45</PingLogRoundtripTime>
</PingLog>
我的问题是,当我序列化一个数组时,我得到了每个对象的xml标签。这里有一个xml打印示例:
<?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>
我怎么能解决这个问题,我的错是什么?
答案
如果有人会有这样的问题;这是我的解决方案:
我刚刚添加了另一个结构,感谢@Scheff,他现在是我的导师。
我的新Xml Saver是这样的:
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;
}
};
我的新结构是:
struct SendServerPingLogDto {
std::vector<PingLogDto> PingLogList;
};
我正在使用这样的结构:
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");
唯一的问题是在xml中我们有一个不必要的标签“”这就是为什么我不得不改变我的服务器端代码。
无论如何,谢谢你的意见和支持。
另一答案
如果你能够在结构中添加一些小修改,并且你有C ++ 11.你可以尝试我的lib,可以在https://github.com/incoder1/IO找到:
你的一个例子:
#include <iostream>
#include <files.hpp>
#include <stream.hpp>
#include <xml_types.hpp>
static const char* PROLOGUE = "<?xml version="1.0" encoding="UTF-8" ?>";
// optional used to open an xml file, can be cached to std::fostream
static io::s_write_channel create_file_channel(const char* path) {
io::file f( path );
std::error_code ec;
io::s_write_channel ret = f.open_for_write(ec, io::write_open_mode::overwrite);
io::check_error_code(ec);
return ret;
}
struct PingLogDto
{
int PingLogID;
int HardwareHostID;
std::string PingLogRoundtripTime; // you can use std::chrono instead
// A meta-programming type to serialize type into XML
typedef io::xml::complex_type<PingLogDto,
std::tuple<>, // this one is for XML attributes
std::tuple<io::xml::int_element,io::xml::int_element,
io::xml::string_element> > xml_type;
// need to be a method to be used in list type
// and needs to be logically const
xml_type to_xml_type() const {
io::xml::int_element idEl("PingLogID", PingLogID);
io::xml::int_element hostIdEl("HardwareHostID", HardwareHostID);
io::xml::string_element pingLogRoundtripEl("PingLogRoundtripTime",PingLogRoundtripTime);
return xml_type("PingLog", std::tuple<>(), std::make_tuple(idEl,hostIdEl,pingLogRoundtripEl));
}
};
int main()
{
// open a xml file to write into
io::channel_ostream<char> xml( create_file_channel("pinlogs.xml"));
xml << PROLOGUE << std::endl;
// a meta type for serializing STL container of a specific element
typedef io::xml::list_type< PingLogDto::xml_type > PinLogsXMLType;
// a vector of structures to serialize
std::vector<PingLogDto> logs( {{0,0,"3.1.2018"},{1,1,"4.1.2018"}} );
// call XML root element as PingLogs
PinLogsXMLType xt("PingLogs");
// serialize vector, and name each tag as PingLog
xt.add_elements( "PingLog", logs.begin(), logs.end() );
// write serialized data into stream and pretty-pint XML
xt.marshal(xml,1);
// write same into console
std::cout << PROLOGUE << std::endl;
xt.marshal(std::cout,1);
return 0;
}
结果如下:
<?xml version="1.0" encoding="UTF-8" ?>
<PingLogs>
<PingLog>
<PingLogID>0</PingLogID>
<HardwareHostID>0</HardwareHostID>
<PingLogRoundtripTime>3.1.2018</PingLogRoundtripTime>
</PingLog>
<PingLog>
<PingLogID>1</PingLogID>
<HardwareHostID>1</HardwareHostID>
<PingLogRoundtripTime>4.1.2018</PingLogRoundtripTime>
</PingLog>
</PingLogs>
以上是关于C ++使用for循环将对象列表序列化为XML的主要内容,如果未能解决你的问题,请参考以下文章