【发布时间】:2017-12-12 09:35:24
【问题描述】:
我有一个对象列表,想将其序列化为 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\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 对象: 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>
我该如何解决这个问题,我的错是什么?
【问题讨论】:
-
如果没有更深入的知识,您似乎可以输出 XML 文档。在一个循环中。相反,您需要具有多个节点的 一个 文档。为此,您必须解决另一个问题:一个 XML 文档可能只有一个根节点。可能,您必须插入一个额外的根节点。 (这表示要记住 XML 一般是如何工作的,因为我不知道 pugixml...)
-
你看到pugixml 1.8 quick start guide了吗?我特别推荐Modifying document data,因为它显示了节点是如何插入到文档中的。
-
@Scheff 是的,尽管如此。但问题是;服务器以这种方式接受daha。如果有任何方法可以做到这一点,我更喜欢这个版本,否则我也必须更改服务器代码。
-
第二个
saver::operator()()呢? (我的意思是接受两个节点名称和一个容器的那个?) -
我猜,
RequestHandler::SendPingServerLog()中的循环已经过时了。相反,您可以直接使用容器pingLogList调用saver::operator()。 (请注意,此运算符 确实 已经包含循环。其余的应该与“模板魔术”一起使用......)
标签: c++ xml for-loop serialization pugixml