c++serializationboost

Boost serializing wrapper class to XML without nesting


I have made a class that wraps boost::uuids::uuid. Now I want to insert the the wrapped value into an XML using boost::archive::xml_oarchive. The following minimal example does that:

#include <iostream>
#include <sstream>

#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/wrapper.hpp>
#include <boost/uuid/string_generator.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid_serialize.hpp>

class Wrapper {
public:
    explicit Wrapper(boost::uuids::uuid value)
        : m_value{value} {}

    boost::uuids::uuid &operator*() { return m_value; }

private:
    boost::uuids::uuid m_value;
};

BOOST_CLASS_IS_WRAPPER(Wrapper)

template <class Archive>
void serialize(Archive &archive, Wrapper &wrapper, [[maybe_unused]] const uint version) {
    archive << boost::serialization::make_nvp("key", *wrapper);
}

int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) {
    std::ostringstream oss;
    boost::uuids::uuid value{};
    Wrapper wrapper{value};
    std::string string = to_string(*wrapper);
    {
        boost::archive::xml_oarchive archive(oss);
        archive << boost::serialization::make_nvp("expected", string);
        archive << boost::serialization::make_nvp("result", wrapper);
    }
    std::cout << oss.str() << std::endl;
    return 0;
}

However, this outputs the following XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="18">
<expected>00000000-0000-0000-0000-000000000000</expected>
<result class_id="0" tracking_level="0" version="0">
        <key>00000000-0000-0000-0000-000000000000</key>
</result>
</boost_serialization>

As you can see, the wrapped uuid is nested inside <result><key> ... </key></result>, but want I want is it to be similar to the <expected> ... </expected> part (the class_id, etc metadata is fine, just not nesting).

I've tried various permutations of removing the BOOST_CLASS_IS_WRAPPER, using it on boost::uuids::uuid, using to_string in serialize and then serializing the std::string, etc, but none of them achieves the desired result.


Solution

  • The nvp wrapper adds a layer. Simplify:

    Live On Coliru

    #include <boost/archive/xml_oarchive.hpp>
    #include <boost/serialization/wrapper.hpp>
    #include <boost/uuid.hpp>
    #include <iostream>
    
    class Wrapper {
      public:
        explicit Wrapper(boost::uuids::uuid value) : m_value{value} {}
    
        boost::uuids::uuid& operator*() { return m_value; }
    
      private:
        boost::uuids::uuid m_value;
    };
    
    BOOST_CLASS_IS_WRAPPER(Wrapper)
    BOOST_CLASS_IMPLEMENTATION(Wrapper, boost::serialization::object_serializable)
    BOOST_CLASS_TRACKING(Wrapper, boost::serialization::track_never)
    
    void serialize(auto& archive, Wrapper& wrapper, unsigned) {
        archive << boost::serialization::make_nvp("key", *wrapper);
    }
    
    int main() {
        Wrapper w{{}};
        boost::archive::xml_oarchive(std::cout) << w;
    }
    

    Prints

    <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
    <!DOCTYPE boost_serialization>
    <boost_serialization signature="serialization::archive" version="20">
    <key>00000000-0000-0000-0000-000000000000</key>
    </boost_serialization>