我正在使用 C++
boost::serialization
库来读取和写入配置 XML。为了向用户提供向后兼容性,在读取 XML 时如果缺少某些 XML 元素,则需要有默认值。如果它尝试读取的 xml 元素丢失,它将抛出 input stream error
。
我尝试使用 Try-Catch 块来解决这个问题,但这样我也得到了
input stream error
。
void XmlAttributes::serialize(Archive & ar, const unsigned int file_version ){
ar & boost::serialization::make_nvp("Attr1",attr1);
try {
ar & boost::serialization::make_nvp("Attr2", attr2);
}
catch (boost::archive::archive_exception const& e) {
// XML element not found, set default value
attr2 = true; // Set a default value, for example, true
}
}
在上面的代码中,“Attr1”在 XML 中是强制元素,但“Attr2”是可选元素,因此如果 XML 中不存在该元素且没有任何输入流错误,则应默认为“true”。有没有办法使用
boost optional
库来解决这个问题。
Boost Serialization 不处理 XML 属性。它处理 XML 档案。
您可以通过为您的类型定义序列化来控制序列化。
如果您需要向后兼容,您需要对该定义进行版本控制。幸运的是,Boost Serialization 可以让您做到这一点:https://www.boost.org/doc/libs/1_84_0/libs/serialization/doc/
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <fstream>
#include <iostream>
#include <set>
using boost::serialization::make_nvp;
struct XmlAttributes {
XmlAttributes(std::string attr1 = {}, bool attr2 = false) //
: attr1(std::move(attr1))
, attr2(attr2) {}
private:
std::string attr1;
bool attr2;
friend class boost::serialization::access;
template <typename Archive> void serialize(Archive& ar, unsigned version) {
if (Archive::is_loading::value)
std::cout << "Loading version: " << version << std::endl;
else
std::cout << "Saving version: " << version << std::endl;
ar& make_nvp("Attr1", attr1);
if (version >= 1)
ar& make_nvp("Attr2", attr2);
else
attr2 = true; // Set a default value, for example, true
}
friend std::ostream& operator<<(std::ostream& os, XmlAttributes const& attr) {
return os << "Attr1: " << attr.attr1 << ", Attr2: " << attr.attr2;
}
};
#ifdef NEWVERSION
BOOST_CLASS_VERSION(XmlAttributes, 1)
#endif
int main(int argc, char** argv) {
std::cout << "\n---\nProgram Version: " << boost::serialization::version<XmlAttributes>::value << std::endl;
std::set<std::string_view> args(argv, argv + argc);
if (args.contains("load")) {
XmlAttributes attr;
std::ifstream ifs("test.xml");
boost::archive::xml_iarchive(ifs) >> make_nvp("test", attr);
std::cout << attr << std::endl;
}
if (args.contains("save")) {
XmlAttributes attr
{"Hello", false};
std::ofstream ofs("test.xml");
boost::archive::xml_oarchive(ofs) << make_nvp("test", attr);
}
}
用旧版本保存,用新版本再次加载并保存进行测试:
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp -lboost_serialization -o oldversion
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp -lboost_serialization -o newversion -DNEWVERSION
./oldversion save
nl test.xml
./newversion load save
nl test.xml
./oldversion load
演出
---
Program Version: 0
Saving version: 0
1 <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
2 <!DOCTYPE boost_serialization>
3 <boost_serialization signature="serialization::archive" version="20">
4 <test class_id="0" tracking_level="0" version="0">
5 <Attr1>Hello</Attr1>
6 </test>
7 </boost_serialization>
---
Program Version: 1
Loading version: 0
Attr1: Hello, Attr2: 1
Saving version: 1
1 <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
2 <!DOCTYPE boost_serialization>
3 <boost_serialization signature="serialization::archive" version="20">
4 <test class_id="0" tracking_level="0" version="1">
5 <Attr1>Hello</Attr1>
6 <Attr2>0</Attr2>
7 </test>
8 </boost_serialization>
---
Program Version: 0
terminate called after throwing an instance of 'boost::archive::archive_exception'
what(): class version 13XmlAttributes