如何使用 C++ boost::serialization 处理可选 Xml 元素

问题描述 投票:0回答:1

我正在使用 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
库来解决这个问题。

c++ boost xml-parsing xml-serialization boost-optional
1个回答
0
投票

Boost Serialization 不处理 XML 属性。它处理 XML 档案。

您可以通过为您的类型定义序列化来控制序列化。

如果您需要向后兼容,您需要对该定义进行版本控制。幸运的是,Boost Serialization 可以让您做到这一点:https://www.boost.org/doc/libs/1_84_0/libs/serialization/doc/

演示

住在Coliru

#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
© www.soinside.com 2019 - 2024. All rights reserved.