C ++使用for循环将对象列表序列化为XML
C++ serialize an object list to XML with for loop
我有一个对象列表,想将其序列化为 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++,我不得不这样做来序列化我的对象。这是我的老问题:
我的对象头是这样的:
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);
}
};
};
这个结构可以成功地将对象序列化为xml。为了清楚起见,这里是我的例子:
PingLogDto pingLog;
pingLog.HardwareHostID = 1;
pingLog.PingLogRoundtripTime = "45";
如果我序列化此 pingLog 对象:
保护程序(_doc.root(),"PingLog",pingLog);
打印会是这样的:
<?xml version="1.0"?>
<PingLog>
<PingLogID>0</PingLogID>
<HardwareHostID>1</HardwareHostID>
<PingLogRoundtripTime>45</PingLogRoundtripTime>
</PingLog>
我的问题是,当我序列化一个数组时,我得到了每个对象的 xml 标签。这里有一个例子 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>
我该如何解决这个问题,我的错是什么?
如果有人遇到这样的问题;这是我的解决方案:
感谢@Scheff,我刚刚添加了另一个结构,他现在是我的导师。
我的新Xml保护程序是这样的:
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。你可以试试我的库,可以在 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>
我有一个对象列表,想将其序列化为 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++,我不得不这样做来序列化我的对象。这是我的老问题:
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);
}
};
};
这个结构可以成功地将对象序列化为xml。为了清楚起见,这里是我的例子:
PingLogDto pingLog;
pingLog.HardwareHostID = 1;
pingLog.PingLogRoundtripTime = "45";
如果我序列化此 pingLog 对象: 保护程序(_doc.root(),"PingLog",pingLog);
打印会是这样的:
<?xml version="1.0"?>
<PingLog>
<PingLogID>0</PingLogID>
<HardwareHostID>1</HardwareHostID>
<PingLogRoundtripTime>45</PingLogRoundtripTime>
</PingLog>
我的问题是,当我序列化一个数组时,我得到了每个对象的 xml 标签。这里有一个例子 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>
我该如何解决这个问题,我的错是什么?
如果有人遇到这样的问题;这是我的解决方案:
感谢@Scheff,我刚刚添加了另一个结构,他现在是我的导师。
我的新Xml保护程序是这样的:
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。你可以试试我的库,可以在 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>