如何更改或删除升压序列化中的标签?
How to change or delete tags in boost serialization?
我正在尝试将我的 classes 序列化为 xml。我的 classes;
class HardwareDto{
friend class boost::serialization::access;
template<class Archive> void serialize(Archive & ar, const unsigned int version) {
ar & BOOST_SERIALIZATION_NVP(HardwareID);
ar & BOOST_SERIALIZATION_NVP(HardwareHostID);
ar & BOOST_SERIALIZATION_NVP(HardwareFriendlyName);
}
public:
int HardwareID;
int HardwareHostID;
string HardwareFriendlyName;
inline HardwareDto(int HardwareHostID, int HardwareID, string HardwareFriendlyName) {
this->HardwareHostID = HardwareHostID;
this->HardwareID = HardwareID;
this->HardwareFriendlyName = HardwareFriendlyName;
}
};
还有一个 class,其中包含一个 HardwareDto
列表。
class HardwareHostDto {
private:
friend class boost::serialization::access;
template<class Archive> void serialize(Archive & ar, const unsigned int version) {
ar & BOOST_SERIALIZATION_NVP(HardwareHostID);
ar & BOOST_SERIALIZATION_NVP(BranchID);
ar & BOOST_SERIALIZATION_NVP(HardwareHostFriendlyName);
ar & BOOST_SERIALIZATION_NVP(HardwareList);
}
public:
int HardwareHostID;
int BranchID;
string HardwareHostFriendlyName ;
HardwareDto* HardwareList[20];
inline HardwareHostDto(int HardwareHostID, int BranchID, string HardwareHostFriendlyName, HardwareDto* HardwareList[20]) {
this->HardwareHostID = HardwareHostID;
this->BranchID = BranchID;
this->HardwareHostFriendlyName = HardwareHostFriendlyName;
this->HardwareList[0] = HardwareList[0];
}
};
和
HardwareDto *HardwareList[20];
是我的全球 hardwaredto 列表。在这个例子中,我只插入了一个 hardwarehostdto 对象到这个列表中。
我正在尝试通过 boost 函数对其进行序列化:
std::ofstream ofs("filename.xml");
unsigned int flags = boost::archive::no_header;
boost::archive::xml_iarchive ia(is, boost::archive::no_header);
boost::archive::xml_oarchive oa(ofs, flags);
HardwareHostDto* HardwareHost = new HardwareHostDto(1, 1, "kiosk", HardwareList);
oa << BOOST_SERIALIZATION_NVP(HardwareHost);
执行这段代码后,我得到了这个filename.xml:
<HardwareHost class_id="0">
<HardwareHostID>1</HardwareHostID>
<BranchID>1</BranchID>
<HardwareHostFriendlyName>kiosk</HardwareHostFriendlyName>
<HardwareList>
<count>20</count>
<item class_id="1">
<HardwareID>2</HardwareID>
<HardwareHostID>2</HardwareHostID>
<HardwareFriendlyName>Ankara</HardwareFriendlyName>
</item>
</HardwareList>
</HardwareHost>
<item>
标签应该是 <Hardware>
但我无法更改它。
我的问题是:有什么方法可以更改 <item>
标签,或者可以自定义此 xml 结构,比如没有 <count>
标签或标志?我在 boost 网站上找到了一些方法,但无法处理。
谢谢。
是的,你可以破解它。可能是。在一定程度上。参见:
不,你不应该。使用 XML 库编写任意 XML.
Boost Serialization 只做序列化。存档格式是实现细节。
坏榜样
不要做什么(它破坏了非默认的可构造类型,它破坏了版本控制)。
好的一面是,此代码不会泄漏内存。
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
class HardwareDto {
friend class boost::serialization::access;
template <class Archive> void serialize(Archive &ar, unsigned) {
ar &BOOST_SERIALIZATION_NVP(HardwareID);
ar &BOOST_SERIALIZATION_NVP(HardwareHostID);
ar &BOOST_SERIALIZATION_NVP(HardwareFriendlyName);
}
public:
int HardwareHostID;
int HardwareID;
std::string HardwareFriendlyName;
HardwareDto(int HardwareHostID = -1, int HardwareID = -1, std::string HardwareFriendlyName = {})
: HardwareHostID(HardwareHostID),
HardwareID(HardwareID),
HardwareFriendlyName(HardwareFriendlyName)
{ }
};
using HardwareDtoList = std::vector<HardwareDto>;
class HardwareHostDto {
private:
friend class boost::serialization::access;
template <class Archive> void serialize(Archive &ar, unsigned) {
ar &BOOST_SERIALIZATION_NVP(HardwareHostID);
ar &BOOST_SERIALIZATION_NVP(BranchID);
ar &BOOST_SERIALIZATION_NVP(HardwareHostFriendlyName);
ar &BOOST_SERIALIZATION_NVP(HardwareList);
}
public:
int HardwareHostID;
int BranchID;
std::string HardwareHostFriendlyName;
HardwareDtoList HardwareList;
HardwareHostDto(int HardwareHostID, int BranchID, std::string HardwareHostFriendlyName, HardwareDtoList HardwareList)
: HardwareHostID(HardwareHostID),
BranchID(BranchID),
HardwareHostFriendlyName(HardwareHostFriendlyName),
HardwareList(HardwareList)
{ }
};
namespace boost { namespace serialization {
template <typename Ar>
void serialize(Ar& ar, std::vector<HardwareDto>& v, unsigned) {
size_t count = v.size();
ar & BOOST_SERIALIZATION_NVP(count);
v.resize(count);
for (auto& el : v)
ar & boost::serialization::make_nvp("Hardware", el);
}
} }
#include <fstream>
#include <iostream>
int main() {
unsigned int flags = boost::archive::no_header;
{
HardwareDtoList HardwareList;
HardwareList.emplace_back(1, 2, "friendly");
std::ofstream ofs("filename.xml");
boost::archive::xml_oarchive oa(ofs, flags);
HardwareHostDto host(1, 1, "kiosk", HardwareList);
oa << boost::serialization::make_nvp("HardwareHost", host);
}
{
HardwareHostDto roundtrip(-1, -1, "", {});
std::ifstream ifs("filename.xml");
boost::archive::xml_iarchive ia(ifs, flags);
ia >> boost::serialization::make_nvp("HardwareHost", roundtrip);
std::cout << "Read back: " << roundtrip.HardwareHostID << "\n";
std::cout << "Read back: " << roundtrip.BranchID << "\n";
std::cout << "Read back: " << roundtrip.HardwareHostFriendlyName << "\n";
for (auto& h: roundtrip.HardwareList) {
std::cout << "Item: " << h.HardwareID << ", " << h.HardwareHostID << ", " << h.HardwareFriendlyName << "\n";
}
}
}
版画
Read back: 1
Read back: 1
Read back: kiosk
Item: 2, 1, friendly
并将 XML 写为:
<HardwareHost class_id="0" tracking_level="0" version="0">
<HardwareHostID>1</HardwareHostID>
<BranchID>1</BranchID>
<HardwareHostFriendlyName>kiosk</HardwareHostFriendlyName>
<HardwareList class_id="1" tracking_level="0" version="0">
<count>1</count>
<Hardware class_id="2" tracking_level="0" version="0">
<HardwareID>2</HardwareID>
<HardwareHostID>1</HardwareHostID>
<HardwareFriendlyName>friendly</HardwareFriendlyName>
</Hardware>
</HardwareList>
</HardwareHost>
做什么
使用 XML 库。这需要(很多)概括,但这里是使用 PugiXML:
的开始
#include <pugixml.hpp>
#include <iostream>
#include <vector>
struct HardwareDto {
int HardwareHostID;
int HardwareID;
std::string HardwareFriendlyName;
};
struct HardwareHostDto {
int HardwareHostID;
int BranchID;
std::string HardwareHostFriendlyName;
std::vector<HardwareDto> HardwareList;
};
struct 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, HardwareDto const& o) const {
auto dto = named_child(parent, name);
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "HardwareID", o.HardwareID);
operator()(dto, "HardwareFriendlyName", o.HardwareFriendlyName);
}
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, HardwareHostDto const& o) const {
auto dto = named_child(parent, name);
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "BranchID", o.BranchID);
operator()(dto, "HardwareHostFriendlyName", o.HardwareHostFriendlyName);
operator()(dto, "HardwareList", "Hardware", o.HardwareList);
}
private:
// serialization
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();
}
void operator()(pugi::xml_node dto, HardwareDto& o) const {
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "HardwareID", o.HardwareID);
operator()(dto, "HardwareFriendlyName", o.HardwareFriendlyName);
}
void operator()(pugi::xml_node parent, std::string const& name, HardwareDto& o) const {
auto dto = parent.first_element_by_path(name.c_str());
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "HardwareID", o.HardwareID);
operator()(dto, "HardwareFriendlyName", o.HardwareFriendlyName);
}
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, HardwareHostDto& o) const {
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "BranchID", o.BranchID);
operator()(dto, "HardwareHostFriendlyName", o.HardwareHostFriendlyName);
operator()(dto, "HardwareList", "Hardware", o.HardwareList);
}
void operator()(pugi::xml_node parent, std::string const& name, HardwareHostDto& o) const {
operator()(parent.first_element_by_path(name.c_str()), o);
}
};
};
int main() {
{
pugi::xml_document _doc;
Xml::Saver saver;
HardwareHostDto host = { 1, 1, "kiosk", { { 1, 2, "friendly" } } };
saver(_doc.root(), "HardwareHost", host);
_doc.save_file("test.xml");
}
{
HardwareHostDto roundtrip;
{
pugi::xml_document _doc;
_doc.load_file("test.xml");
Xml::Loader loader;
loader(_doc.root(), "HardwareHost", roundtrip);
}
std::cout << "Read back: " << roundtrip.HardwareHostID << "\n";
std::cout << "Read back: " << roundtrip.BranchID << "\n";
std::cout << "Read back: " << roundtrip.HardwareHostFriendlyName << "\n";
for (auto& h: roundtrip.HardwareList) {
std::cout << "Item: " << h.HardwareID << ", " << h.HardwareHostID << ", " << h.HardwareFriendlyName << "\n";
}
}
}
这也打印
Read back: 1
Read back: 1
Read back: kiosk
Item: 2, 1, friendly
并写一个test.xml
:
<?xml version="1.0"?>
<HardwareHost>
<HardwareHostID>1</HardwareHostID>
<BranchID>1</BranchID>
<HardwareHostFriendlyName>kiosk</HardwareHostFriendlyName>
<HardwareList>
<Hardware>
<HardwareHostID>1</HardwareHostID>
<HardwareID>2</HardwareID>
<HardwareFriendlyName>friendly</HardwareFriendlyName>
</Hardware>
</HardwareList>
</HardwareHost>
为了完全自定义来自 boost 序列化的 XML 输出,您可以编写自己的 XML 存档。这是一个三步过程:
- 定义一个 class 来编写基本类型,比方说
TextOPrimitiveOnXML
。
- 定义一个 class 写入复合类型:
BasicXMLOArchive
。这是将写入 XML 标签的 class。
- 将所有内容粘在一起成为
XMLOArchive
。
优点是不仅可以重复使用 serialize
代码,还可以使用不同的后端。例如,您可以拥有一个立即创建 DOM 而不仅仅是文本输出的存档。
这是我提到的 classes 的骨架。
TextOPrimitiveOnXML
,它的save
方法定义了原始类型的写法。
class TextOPrimitiveOnXML
{
protected:
TextOPrimitiveOnXML()
{}
template <class T>
void save(const T & t) {
}
void save(const bool t) {
}
void save(const signed char t) {
}
void save(const unsigned char t) {
}
void save(const char t) {
}
void save(const wchar_t t) {
}
void save(const char *t) {
}
void save(const wchar_t *t) {
}
void save(const std::string &t) {
}
void save(const std::wstring &t) {
}
void save_binary(const void *address, std::size_t count);
};
BasicXMLOArchive
,这是你操作标签和属性的地方:
template <class Archive>
class BasicXMLOArchive :
public boost::archive::detail::common_oarchive<Archive>
{
friend class boost::archive::detail::interface_oarchive<Archive>;
friend class boost::archive::save_access;
typedef boost::archive::detail::common_oarchive<Archive> base;
protected:
void init() {
}
BasicXMLOArchive(unsigned int flags)
: base(flags)
{}
template <class T>
void save_override(T & t, int)
{
// If your program fails to compile here, its most likely due to
// not specifying an nvp wrapper around the variable to
// be serialized.
BOOST_MPL_ASSERT((boost::serialization::is_wrapper<T>));
this->base::save_override(t, 0);
}
// special treatment for name-value pairs.
template <class T>
void save_override(const boost::serialization::nvp<T> &t, int)
{
}
void save_override(const boost::archive::object_id_type & t);
void save_override(const boost::archive::object_reference_type & t);
void save_override(const boost::archive::version_type & t);
void save_override(const boost::archive::class_id_type & t);
void save_override(const boost::archive::class_id_optional_type & t);
void save_override(const boost::archive::class_id_reference_type & t);
void save_override(const boost::archive::class_name_type & t);
void save_override(const boost::archive::tracking_type & t);
public:
boost::archive::library_version_type get_library_version() const {
return boost::archive::library_version_type(0);
}
};
最终胶水:
template <class Archive>
class XMLOArchiveImpl :
public TextOPrimitiveOnXML
, public BasicXMLOArchive<Archive>
{
friend class boost::archive::save_access;
public:
XMLOArchiveImpl(unsigned int flags)
: TextOPrimitiveOnXML()
, BasicXMLOArchive<Archive>(flags)
{
init();
}
void save_binary(const void *address, std::size_t count){
this->TextOPrimitiveOnXML::save_binary(address, count);
}
};
class XMLOArchive :
public XMLOArchiveImpl<XMLOArchive>
{
friend class BasicXMLOArchive<XMLOArchive>;
public:
XMLOArchive(unsigned int flags)
: XMLOArchiveImpl(flags)
{}
};
我正在尝试将我的 classes 序列化为 xml。我的 classes;
class HardwareDto{
friend class boost::serialization::access;
template<class Archive> void serialize(Archive & ar, const unsigned int version) {
ar & BOOST_SERIALIZATION_NVP(HardwareID);
ar & BOOST_SERIALIZATION_NVP(HardwareHostID);
ar & BOOST_SERIALIZATION_NVP(HardwareFriendlyName);
}
public:
int HardwareID;
int HardwareHostID;
string HardwareFriendlyName;
inline HardwareDto(int HardwareHostID, int HardwareID, string HardwareFriendlyName) {
this->HardwareHostID = HardwareHostID;
this->HardwareID = HardwareID;
this->HardwareFriendlyName = HardwareFriendlyName;
}
};
还有一个 class,其中包含一个 HardwareDto
列表。
class HardwareHostDto {
private:
friend class boost::serialization::access;
template<class Archive> void serialize(Archive & ar, const unsigned int version) {
ar & BOOST_SERIALIZATION_NVP(HardwareHostID);
ar & BOOST_SERIALIZATION_NVP(BranchID);
ar & BOOST_SERIALIZATION_NVP(HardwareHostFriendlyName);
ar & BOOST_SERIALIZATION_NVP(HardwareList);
}
public:
int HardwareHostID;
int BranchID;
string HardwareHostFriendlyName ;
HardwareDto* HardwareList[20];
inline HardwareHostDto(int HardwareHostID, int BranchID, string HardwareHostFriendlyName, HardwareDto* HardwareList[20]) {
this->HardwareHostID = HardwareHostID;
this->BranchID = BranchID;
this->HardwareHostFriendlyName = HardwareHostFriendlyName;
this->HardwareList[0] = HardwareList[0];
}
};
和
HardwareDto *HardwareList[20];
是我的全球 hardwaredto 列表。在这个例子中,我只插入了一个 hardwarehostdto 对象到这个列表中。
我正在尝试通过 boost 函数对其进行序列化:
std::ofstream ofs("filename.xml");
unsigned int flags = boost::archive::no_header;
boost::archive::xml_iarchive ia(is, boost::archive::no_header);
boost::archive::xml_oarchive oa(ofs, flags);
HardwareHostDto* HardwareHost = new HardwareHostDto(1, 1, "kiosk", HardwareList);
oa << BOOST_SERIALIZATION_NVP(HardwareHost);
执行这段代码后,我得到了这个filename.xml:
<HardwareHost class_id="0">
<HardwareHostID>1</HardwareHostID>
<BranchID>1</BranchID>
<HardwareHostFriendlyName>kiosk</HardwareHostFriendlyName>
<HardwareList>
<count>20</count>
<item class_id="1">
<HardwareID>2</HardwareID>
<HardwareHostID>2</HardwareHostID>
<HardwareFriendlyName>Ankara</HardwareFriendlyName>
</item>
</HardwareList>
</HardwareHost>
<item>
标签应该是 <Hardware>
但我无法更改它。
我的问题是:有什么方法可以更改 <item>
标签,或者可以自定义此 xml 结构,比如没有 <count>
标签或标志?我在 boost 网站上找到了一些方法,但无法处理。
谢谢。
是的,你可以破解它。可能是。在一定程度上。参见:
不,你不应该。使用 XML 库编写任意 XML.
Boost Serialization 只做序列化。存档格式是实现细节。
坏榜样
不要做什么(它破坏了非默认的可构造类型,它破坏了版本控制)。
好的一面是,此代码不会泄漏内存。
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
class HardwareDto {
friend class boost::serialization::access;
template <class Archive> void serialize(Archive &ar, unsigned) {
ar &BOOST_SERIALIZATION_NVP(HardwareID);
ar &BOOST_SERIALIZATION_NVP(HardwareHostID);
ar &BOOST_SERIALIZATION_NVP(HardwareFriendlyName);
}
public:
int HardwareHostID;
int HardwareID;
std::string HardwareFriendlyName;
HardwareDto(int HardwareHostID = -1, int HardwareID = -1, std::string HardwareFriendlyName = {})
: HardwareHostID(HardwareHostID),
HardwareID(HardwareID),
HardwareFriendlyName(HardwareFriendlyName)
{ }
};
using HardwareDtoList = std::vector<HardwareDto>;
class HardwareHostDto {
private:
friend class boost::serialization::access;
template <class Archive> void serialize(Archive &ar, unsigned) {
ar &BOOST_SERIALIZATION_NVP(HardwareHostID);
ar &BOOST_SERIALIZATION_NVP(BranchID);
ar &BOOST_SERIALIZATION_NVP(HardwareHostFriendlyName);
ar &BOOST_SERIALIZATION_NVP(HardwareList);
}
public:
int HardwareHostID;
int BranchID;
std::string HardwareHostFriendlyName;
HardwareDtoList HardwareList;
HardwareHostDto(int HardwareHostID, int BranchID, std::string HardwareHostFriendlyName, HardwareDtoList HardwareList)
: HardwareHostID(HardwareHostID),
BranchID(BranchID),
HardwareHostFriendlyName(HardwareHostFriendlyName),
HardwareList(HardwareList)
{ }
};
namespace boost { namespace serialization {
template <typename Ar>
void serialize(Ar& ar, std::vector<HardwareDto>& v, unsigned) {
size_t count = v.size();
ar & BOOST_SERIALIZATION_NVP(count);
v.resize(count);
for (auto& el : v)
ar & boost::serialization::make_nvp("Hardware", el);
}
} }
#include <fstream>
#include <iostream>
int main() {
unsigned int flags = boost::archive::no_header;
{
HardwareDtoList HardwareList;
HardwareList.emplace_back(1, 2, "friendly");
std::ofstream ofs("filename.xml");
boost::archive::xml_oarchive oa(ofs, flags);
HardwareHostDto host(1, 1, "kiosk", HardwareList);
oa << boost::serialization::make_nvp("HardwareHost", host);
}
{
HardwareHostDto roundtrip(-1, -1, "", {});
std::ifstream ifs("filename.xml");
boost::archive::xml_iarchive ia(ifs, flags);
ia >> boost::serialization::make_nvp("HardwareHost", roundtrip);
std::cout << "Read back: " << roundtrip.HardwareHostID << "\n";
std::cout << "Read back: " << roundtrip.BranchID << "\n";
std::cout << "Read back: " << roundtrip.HardwareHostFriendlyName << "\n";
for (auto& h: roundtrip.HardwareList) {
std::cout << "Item: " << h.HardwareID << ", " << h.HardwareHostID << ", " << h.HardwareFriendlyName << "\n";
}
}
}
版画
Read back: 1
Read back: 1
Read back: kiosk
Item: 2, 1, friendly
并将 XML 写为:
<HardwareHost class_id="0" tracking_level="0" version="0">
<HardwareHostID>1</HardwareHostID>
<BranchID>1</BranchID>
<HardwareHostFriendlyName>kiosk</HardwareHostFriendlyName>
<HardwareList class_id="1" tracking_level="0" version="0">
<count>1</count>
<Hardware class_id="2" tracking_level="0" version="0">
<HardwareID>2</HardwareID>
<HardwareHostID>1</HardwareHostID>
<HardwareFriendlyName>friendly</HardwareFriendlyName>
</Hardware>
</HardwareList>
</HardwareHost>
做什么
使用 XML 库。这需要(很多)概括,但这里是使用 PugiXML:
的开始#include <pugixml.hpp>
#include <iostream>
#include <vector>
struct HardwareDto {
int HardwareHostID;
int HardwareID;
std::string HardwareFriendlyName;
};
struct HardwareHostDto {
int HardwareHostID;
int BranchID;
std::string HardwareHostFriendlyName;
std::vector<HardwareDto> HardwareList;
};
struct 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, HardwareDto const& o) const {
auto dto = named_child(parent, name);
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "HardwareID", o.HardwareID);
operator()(dto, "HardwareFriendlyName", o.HardwareFriendlyName);
}
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, HardwareHostDto const& o) const {
auto dto = named_child(parent, name);
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "BranchID", o.BranchID);
operator()(dto, "HardwareHostFriendlyName", o.HardwareHostFriendlyName);
operator()(dto, "HardwareList", "Hardware", o.HardwareList);
}
private:
// serialization
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();
}
void operator()(pugi::xml_node dto, HardwareDto& o) const {
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "HardwareID", o.HardwareID);
operator()(dto, "HardwareFriendlyName", o.HardwareFriendlyName);
}
void operator()(pugi::xml_node parent, std::string const& name, HardwareDto& o) const {
auto dto = parent.first_element_by_path(name.c_str());
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "HardwareID", o.HardwareID);
operator()(dto, "HardwareFriendlyName", o.HardwareFriendlyName);
}
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, HardwareHostDto& o) const {
operator()(dto, "HardwareHostID", o.HardwareHostID);
operator()(dto, "BranchID", o.BranchID);
operator()(dto, "HardwareHostFriendlyName", o.HardwareHostFriendlyName);
operator()(dto, "HardwareList", "Hardware", o.HardwareList);
}
void operator()(pugi::xml_node parent, std::string const& name, HardwareHostDto& o) const {
operator()(parent.first_element_by_path(name.c_str()), o);
}
};
};
int main() {
{
pugi::xml_document _doc;
Xml::Saver saver;
HardwareHostDto host = { 1, 1, "kiosk", { { 1, 2, "friendly" } } };
saver(_doc.root(), "HardwareHost", host);
_doc.save_file("test.xml");
}
{
HardwareHostDto roundtrip;
{
pugi::xml_document _doc;
_doc.load_file("test.xml");
Xml::Loader loader;
loader(_doc.root(), "HardwareHost", roundtrip);
}
std::cout << "Read back: " << roundtrip.HardwareHostID << "\n";
std::cout << "Read back: " << roundtrip.BranchID << "\n";
std::cout << "Read back: " << roundtrip.HardwareHostFriendlyName << "\n";
for (auto& h: roundtrip.HardwareList) {
std::cout << "Item: " << h.HardwareID << ", " << h.HardwareHostID << ", " << h.HardwareFriendlyName << "\n";
}
}
}
这也打印
Read back: 1
Read back: 1
Read back: kiosk
Item: 2, 1, friendly
并写一个test.xml
:
<?xml version="1.0"?>
<HardwareHost>
<HardwareHostID>1</HardwareHostID>
<BranchID>1</BranchID>
<HardwareHostFriendlyName>kiosk</HardwareHostFriendlyName>
<HardwareList>
<Hardware>
<HardwareHostID>1</HardwareHostID>
<HardwareID>2</HardwareID>
<HardwareFriendlyName>friendly</HardwareFriendlyName>
</Hardware>
</HardwareList>
</HardwareHost>
为了完全自定义来自 boost 序列化的 XML 输出,您可以编写自己的 XML 存档。这是一个三步过程:
- 定义一个 class 来编写基本类型,比方说
TextOPrimitiveOnXML
。 - 定义一个 class 写入复合类型:
BasicXMLOArchive
。这是将写入 XML 标签的 class。 - 将所有内容粘在一起成为
XMLOArchive
。
优点是不仅可以重复使用 serialize
代码,还可以使用不同的后端。例如,您可以拥有一个立即创建 DOM 而不仅仅是文本输出的存档。
这是我提到的 classes 的骨架。
TextOPrimitiveOnXML
,它的save
方法定义了原始类型的写法。
class TextOPrimitiveOnXML
{
protected:
TextOPrimitiveOnXML()
{}
template <class T>
void save(const T & t) {
}
void save(const bool t) {
}
void save(const signed char t) {
}
void save(const unsigned char t) {
}
void save(const char t) {
}
void save(const wchar_t t) {
}
void save(const char *t) {
}
void save(const wchar_t *t) {
}
void save(const std::string &t) {
}
void save(const std::wstring &t) {
}
void save_binary(const void *address, std::size_t count);
};
BasicXMLOArchive
,这是你操作标签和属性的地方:
template <class Archive>
class BasicXMLOArchive :
public boost::archive::detail::common_oarchive<Archive>
{
friend class boost::archive::detail::interface_oarchive<Archive>;
friend class boost::archive::save_access;
typedef boost::archive::detail::common_oarchive<Archive> base;
protected:
void init() {
}
BasicXMLOArchive(unsigned int flags)
: base(flags)
{}
template <class T>
void save_override(T & t, int)
{
// If your program fails to compile here, its most likely due to
// not specifying an nvp wrapper around the variable to
// be serialized.
BOOST_MPL_ASSERT((boost::serialization::is_wrapper<T>));
this->base::save_override(t, 0);
}
// special treatment for name-value pairs.
template <class T>
void save_override(const boost::serialization::nvp<T> &t, int)
{
}
void save_override(const boost::archive::object_id_type & t);
void save_override(const boost::archive::object_reference_type & t);
void save_override(const boost::archive::version_type & t);
void save_override(const boost::archive::class_id_type & t);
void save_override(const boost::archive::class_id_optional_type & t);
void save_override(const boost::archive::class_id_reference_type & t);
void save_override(const boost::archive::class_name_type & t);
void save_override(const boost::archive::tracking_type & t);
public:
boost::archive::library_version_type get_library_version() const {
return boost::archive::library_version_type(0);
}
};
最终胶水:
template <class Archive>
class XMLOArchiveImpl :
public TextOPrimitiveOnXML
, public BasicXMLOArchive<Archive>
{
friend class boost::archive::save_access;
public:
XMLOArchiveImpl(unsigned int flags)
: TextOPrimitiveOnXML()
, BasicXMLOArchive<Archive>(flags)
{
init();
}
void save_binary(const void *address, std::size_t count){
this->TextOPrimitiveOnXML::save_binary(address, count);
}
};
class XMLOArchive :
public XMLOArchiveImpl<XMLOArchive>
{
friend class BasicXMLOArchive<XMLOArchive>;
public:
XMLOArchive(unsigned int flags)
: XMLOArchiveImpl(flags)
{}
};