1

I have made the below changes to have customised names for tags. And the below code changes worked successfully and i could create a xml doc with customised names.

namespace boost { namespace serialization {
    template <typename Ar>
        void serialize(Ar& ar,std::pair<int const , Myclass::Pgroups>& p, unsigned) {
            ar & make_nvp("assetid", p.first) & make_nvp("assetdata", p.second);
        }
} }

namespace boost { namespace serialization {
    template <typename Ar>
        void serialize(Ar& ar,std::pair<int const , values>& p, unsigned) {
            ar & make_nvp("hacc_groupid", p.first) & make_nvp("hacc_groupdata", p.second);
        }
} }

But this seems to be a problem deserialising the xml to the object, i get boost error

 template<class Archive, class Object>
   std::string serialise_to_string(const char* tag,Object & obj)
   {
     std::ostringstream os (std::ios::binary);
     Archive arch ( os );
     arch << boost::serialization::make_nvp(tag,obj);
     return os.str();
   }
   template<class Archive , class Object>
   void deserialise_to_obj( std::string const  &s1,Object &outObj)
   {
      std::stringstream is( s1, std::ios_base::binary| std::ios_base::out| std::ios_base::in);
      Archive arch (is);
      arch >> boost::serialization::make_nvp("tag",outObj);
   };

Without boost namespace customisation the serialisation and deserialisation are perfectly working , but with change in boost namespace for having customised tag names , the deserialisation has issue .

Error with the above code , i.e with const in namespace argvoid serialize(Ar& ar,std::pair<int const , values>& p, unsigned)

In file included from main.cpp:1:
In file included from /usr/local/include/boost/archive/binary_oarchive.hpp:21:
In file included from /usr/local/include/boost/archive/binary_oarchive_impl.hpp:22:
In file included from /usr/local/include/boost/archive/basic_binary_oarchive.hpp:33:
In file included from /usr/local/include/boost/archive/detail/common_oarchive.hpp:22:
In file included from /usr/local/include/boost/archive/detail/interface_oarchive.hpp:23:
In file included from /usr/local/include/boost/archive/detail/oserializer.hpp:68:
/usr/local/include/boost/archive/detail/check.hpp:162:5: error: static_assert failed "typex::value"
    BOOST_STATIC_ASSERT(typex::value);
    ^                   ~~~~~~~~~~~~
/usr/local/include/boost/static_assert.hpp:70:41: note: expanded from macro 'BOOST_STATIC_ASSERT'
#     define BOOST_STATIC_ASSERT( ... ) static_assert(__VA_ARGS__, #__VA_ARGS__)
                                        ^             ~~~~~~~~~~~
/usr/local/include/boost/archive/detail/iserializer.hpp:603:13: note: in instantiation of function template specialization 'boost::archive::detail::check_const_loading<const int>' requested here
    detail::check_const_loading< T >();
            ^
/usr/local/include/boost/archive/detail/common_iarchive.hpp:66:18: note: in instantiation of function template specialization 'boost::archive::load<boost::archive::xml_iarchive, const int>' requested here
        archive::load(* this->This(), t);
                 ^
/usr/local/include/boost/archive/basic_xml_iarchive.hpp:78:39: note: in instantiation of function template specialization 'boost::archive::detail::common_iarchive<boost::archive::xml_iarchive>::load_override<const int>' requested here
        this->detail_common_iarchive::load_override(t.value());
                                      ^
/usr/local/include/boost/archive/xml_iarchive.hpp:95:38: note: in instantiation of function template specialization 'boost::archive::basic_xml_iarchive<boost::archive::xml_iarchive>::load_override<const int>' requested here
        basic_xml_iarchive<Archive>::load_override(t);
                                     ^
/usr/local/include/boost/archive/detail/interface_iarchive.hpp:68:23: note: in instantiation of function template specialization 'boost::archive::xml_iarchive_impl<boost::archive::xml_iarchive>::load_override<const boost::serialization::nvp<const int> >' requested here
        this->This()->load_override(t);
                      ^
/usr/local/include/boost/archive/detail/interface_iarchive.hpp:75:32: note: (skipping 45 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
        return *(this->This()) >> t;
                               ^
/usr/local/include/boost/archive/basic_xml_iarchive.hpp:78:39: note: in instantiation of function template specialization 'boost::archive::detail::common_iarchive<boost::archive::xml_iarchive>::load_override<Myclass>' requested here
        this->detail_common_iarchive::load_override(t.value());
                                      ^
/usr/local/include/boost/archive/xml_iarchive.hpp:95:38: note: in instantiation of function template specialization 'boost::archive::basic_xml_iarchive<boost::archive::xml_iarchive>::load_override<Myclass>' requested here
        basic_xml_iarchive<Archive>::load_override(t);
                                     ^
/usr/local/include/boost/archive/detail/interface_iarchive.hpp:68:23: note: in instantiation of function template specialization 'boost::archive::xml_iarchive_impl<boost::archive::xml_iarchive>::load_override<const boost::serialization::nvp<Myclass> >' requested here
        this->This()->load_override(t);

If const-ness is removed from the boost namespace , deserialise_to_obj and serialise_to_string functions ,the code compiles and runs without any issue but doesn't customise the tag name

Hope my information is clear, Iam stuck at an issue where iam really not sure whether the deserialisation to object can smoothly happen with customised tag names. Please advice me what has to be done

Sample code foe serialisation and deserialisation with custom tag names live at coliru

sample working code without deserialzation and custom tag names live at coliru

Thanks Tejas

LearningCpp
  • 972
  • 12
  • 29

1 Answers1

2

The cinch is in the const-ness of std::pair<>::first for std::map::value_type.

This is one of the very few cases where using const_cast makes sense:

namespace boost { namespace serialization {
    template<class Ar>
        inline void serialize(Ar & ar, std::pair<int const, values> & p, unsigned) {
            ar & make_nvp("assetid", const_cast<int&>(p.first)) & make_nvp("assetdata", p.second);
        }

    template <typename Ar>
        void serialize(Ar& ar,std::pair<int const, Myclass::Pgroups>& p, unsigned) {
            ar & make_nvp("hacc_groupid", const_cast<int&>(p.first)) & make_nvp("hacc_groupdata", p.second);
        }
} }

Incidentally, this is also what Boost Serialization does: http://www.boost.org/doc/libs/1_63_0/boost/serialization/utility.hpp

Full Working Demo

Updated: Also overrides the the item node name now

Live On Coliru

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>

#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
#include <fstream>

#include <map>
#include <boost/serialization/map.hpp>
#include <boost/serialization/split_member.hpp>

using boost::serialization::make_nvp;

namespace MyDomain { // demonstrate ADL for serialize
    struct values
    {
        std::string name;
        std::string sex;
        values() : name("dummy"), sex("dummy") {};

        template<class Archive>   
            void serialize(Archive & ar, const unsigned int /*version*/) {
                ar & make_nvp("name", name);
                ar & make_nvp("sex", sex);
            }
    };

    struct Myclass {
        Myclass() { }

        template<class Archive>
            void serialize(Archive & ar, const unsigned int /*version*/)  {
                ar & make_nvp("etoto", e_group);
                ar & make_nvp("ptoto", p_group);
            }

        typedef std::map<int,values> groups;
        typedef std::map<int,groups> Pgroups;    

        groups  e_group;
        Pgroups p_group;
    };

    #define CUSTOM_MAP_SERIALIZE(Map, keyname, valuename) \
    template<class Ar> inline void serialize(Ar & ar, Map::value_type& p, unsigned) { \
            ar & make_nvp(keyname, const_cast<int&>(p.first)) & make_nvp(valuename, p.second); \
        }

    CUSTOM_MAP_SERIALIZE(Myclass::groups, "assetid", "assetdata")
    CUSTOM_MAP_SERIALIZE(Myclass::Pgroups, "hacc_groupid", "hacc_groupdata")
}

namespace boost { namespace serialization {

    #define OVERRIDE_NVP(T, name) \
       template <> inline const nvp<T> make_nvp(const char *, T &t) { return nvp<T>(name, t); } \
       template <> inline const nvp<T const> make_nvp(const char *, T const &t) { return nvp<T const>(name, t); }

    OVERRIDE_NVP(MyDomain::Myclass::groups::value_type,  "group_item")
    OVERRIDE_NVP(MyDomain::Myclass::Pgroups::value_type, "Pgroup_item")

    #undef OVERRIDE_NVP
} }

template<class Archive, class Object>
std::string serialise_to_string(Object const& assetlist)
{
    auto os = std::ostringstream(std::ios::binary);
    Archive arch { os, boost::archive::no_header };
    arch << make_nvp("Main", assetlist);
    return os.str();
}


template<class Archive , class Object>
void deserialise_to_obj(std::string const &s1,Object &outObj)
{
    std::stringstream is( s1, std::ios_base::binary| std::ios_base::out| std::ios_base::in);
    Archive arch { is, boost::archive::no_header };
    arch >> make_nvp("Main", outObj);
}

MyDomain::Myclass create_data()
{
    MyDomain::Myclass object;
    MyDomain::values val1;
    object.e_group.insert( std::make_pair(1,val1) ) ;
    object.e_group.insert( std::make_pair(2,val1) ) ;
    object.p_group.insert( std::make_pair(1,object.e_group) ) ;
    object.p_group.insert( std::make_pair(2,object.e_group) ) ;   
    return object;
}

int main() {
    {
        MyDomain::Myclass obj = create_data() ;

        std::string s2 = serialise_to_string<boost::archive::xml_oarchive>(obj);

        //Save xml to a file
        {
            std::ofstream ofs("output1.xml");
            ofs << s2 << std::endl << std::endl;
            ofs.close();
        }

    }

    std::string content;
    {
        std::ifstream ifs("output1.xml");
        content.assign(std::istreambuf_iterator<char>(ifs), {});
        ifs.close();
    }
    {
        MyDomain::Myclass outObj;
        deserialise_to_obj<boost::archive::xml_iarchive>(content,outObj);
        //Print the object 
        for(auto &i:outObj.p_group){
            std::cout<<"\n"<<i.first<<"\n";
            for(auto &j:i.second){
                std::cout<<"\t"<<j.first<<"\t"<<j.second.name<<"\t"<<j.second.sex<<"\n";
            }
        }  
    }
}

Prints

1
    1   dummy   dummy
    2   dummy   dummy

2
    1   dummy   dummy
    2   dummy   dummy

With output1.xml

<Main class_id="0" tracking_level="0" version="0">
    <etoto class_id="1" tracking_level="0" version="0">
        <count>2</count>
        <item_version>0</item_version>
        <group_item class_id="2" tracking_level="0" version="0">
            <assetid>1</assetid>
            <assetdata class_id="3" tracking_level="0" version="0">
                <name>dummy</name>
                <sex>dummy</sex>
            </assetdata>
        </group_item>
        <group_item>
            <assetid>2</assetid>
            <assetdata>
                <name>dummy</name>
                <sex>dummy</sex>
            </assetdata>
        </group_item>
    </etoto>
    <ptoto class_id="4" tracking_level="0" version="0">
        <count>2</count>
        <item_version>0</item_version>
        <Pgroup_item class_id="5" tracking_level="0" version="0">
            <hacc_groupid>1</hacc_groupid>
            <hacc_groupdata>
                <count>2</count>
                <item_version>0</item_version>
                <group_item>
                    <assetid>1</assetid>
                    <assetdata>
                        <name>dummy</name>
                        <sex>dummy</sex>
                    </assetdata>
                </group_item>
                <group_item>
                    <assetid>2</assetid>
                    <assetdata>
                        <name>dummy</name>
                        <sex>dummy</sex>
                    </assetdata>
                </group_item>
            </hacc_groupdata>
        </Pgroup_item>
        <Pgroup_item>
            <hacc_groupid>2</hacc_groupid>
            <hacc_groupdata>
                <count>2</count>
                <item_version>0</item_version>
                <group_item>
                    <assetid>1</assetid>
                    <assetdata>
                        <name>dummy</name>
                        <sex>dummy</sex>
                    </assetdata>
                </group_item>
                <group_item>
                    <assetid>2</assetid>
                    <assetdata>
                        <name>dummy</name>
                        <sex>dummy</sex>
                    </assetdata>
                </group_item>
            </hacc_groupdata>
        </Pgroup_item>
    </ptoto>
</Main>
sehe
  • 374,641
  • 47
  • 450
  • 633
  • it works now,thanks , is there a way I can change the tag or is it unchangable – LearningCpp Apr 02 '17 at 03:22
  • Sure. See [that previoius answer](https://stackoverflow.com/questions/43050361/how-to-customise-default-boost-xml-serialisation-default-node-naming-to-make-it/43055862#43055862). I'm going to point at the **Disclaimer** again. You'll just be doing code duplication while you - fundamentally - don't control the archive format. Since you're LearningCpp I'd suggest renaming `item` is a good exercise for the reader? – sehe Apr 02 '17 at 11:36
  • still trying to achieve it , I tried traversing p.second in the boost namespace – LearningCpp Apr 03 '17 at 18:08
  • It's really not that hard. I think. I just think its useless. Let me try – sehe Apr 03 '17 at 18:30
  • Added a proof of concept (most time spent cleaning it up) **[Live On Coliru](http://coliru.stacked-crooked.com/a/a0657185be987a38)** – sehe Apr 03 '17 at 19:20
  • I would nt have had a minimum idea of doing it :) , this is excellent – LearningCpp Apr 03 '17 at 19:27
  • The trick is to read what functions are used and what the minimum set of functions to overload. Should I repeat my [**Disclaimer**](https://stackoverflow.com/questions/43050361/how-to-customise-default-boost-xml-serialisation-default-node-naming-to-make-it/43055862#43055862) :) – sehe Apr 03 '17 at 19:28
  • Is there a need to catch the exception in serialise_to_string function or boost already has exception handling to catch the exception and print the serialization error, if there is a serialization error thrown due to the missing XML field. – LearningCpp May 19 '17 at 10:43
  • Is it possible to have all items of under in a single line under assetdata tag per group_item ex : – LearningCpp May 23 '17 at 11:10
  • Just stop it. You're swimming against the stream. If you try to do it at length, you'll tire and the stream wins. If your life depends on it, you have already drowned. – sehe May 23 '17 at 11:17
  • :) :) , So its not possible ? – LearningCpp May 23 '17 at 12:38
  • is there any other way using BOOST ? – LearningCpp May 23 '17 at 12:39
  • No good ways. Boost does not have an XML library. Use PugiXML or Libxml2, e.g. PugiXML is/can be header only. It has MIT license, which is similar to Boost License – sehe May 23 '17 at 12:47
  • Thanks sehe , you are best :) – LearningCpp May 23 '17 at 12:49
  • can I not do it ? Doesn't boost support it ? – LearningCpp May 23 '17 at 13:50