c++xmlserializationxml-serializationcereal

C++: How to remove "Cereal" XML node?


I want to (de)serialize C++ object into XML files. To do so, I use Cereal library which is lighter than Boost.

So using the Cereal documentation, I created a very simple MWE. Thus, using Cereal serialize function inside the object definition, it is possible to export the object into an XML archive.

The MWE:

#include <string.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <vector>

#include <cereal/archives/xml.hpp>
#include <cereal/types/vector.hpp>

using namespace std;
    
class ClassRectangle 
{
    private:
        /* data */
    public:
        std::string nameClass="Rectangle";
        double length=0.;
        double width=0.;
        vector<double> center={0., 2.};
        
        template <class Archive>
        void serialize( Archive & ar ) const
        {
            ar(  CEREAL_NVP( length )  );
            ar(  CEREAL_NVP( width )  );
            ar(  CEREAL_NVP( center )  );
        }
};

int main(void) 
{ 
    // Beginning of main.
    cout << "(Start)" << endl;
    
    // Save Part.
    ClassRectangle Shape;
    cereal::XMLOutputArchive archive( std::cout );
    archive( cereal::make_nvp(Shape.nameClass, Shape) );

    // End of the main.
    cout << "(End) " << endl;   
    return 0; 
} 
// EoF

This example yields:

(Start)
(End) 
<?xml version="1.0" encoding="utf-8"?>
<cereal>
    <Rectangle>
        <length>0</length>
        <width>0</width>
        <center size="dynamic">
            <value0>0</value0>
            <value1>1</value1>
        </center>
    </Rectangle>
</cereal>

Up to this point, everything is fine. However, in this example the Rectangle object/XML node is whitin an cereal node.

My question is: How can I remove the <cereal> XML node ? This would give the following output:

<?xml version="1.0" encoding="utf-8"?>
<Rectangle>
    <length>0</length>
    <width>0</width>
    <center size="dynamic">
        <value0>0</value0>
        <value1>1</value1>
    </center>
</Rectangle>

Solution

  • Looking at the source code of cereal, it doesn't look like you can remove the root tag. I guess it exists because cereal can only deal with a single root node, and since you could serialize multiple values directly into the archive, for example:

    ClassRectangle Shape;
    cereal::XMLOutputArchive archive( std::cout );
    archive( cereal::make_nvp("first node", Shape) );    
    archive( cereal::make_nvp("second node", Shape) );
    

    this would break that limitation. I'm not sure whether (or if) this is a restriction of rapidxml (the underlying xml library), the xml spec or something else.

    Cereal uses this root node with that exact name to serialize your data, but also to deserialize it (it checks if the root node has the expected name).

    However, you can change the name of that root node by specifying the

    CEREAL_XML_STRING_VALUE "MyRootNodeName"
    

    macro before you include the xml archive header. But note that this name must also be used in the application that deserializes your xml strings.


    Of course you could also manually remove (and add) that root tag as a post (or pre-) processing step to the actual serialization. Basically serialize everything to a string stream and only take a substring off of it (starting from your <Rectangle> node and stopping at its closing tag (which is always a fixed offset from the end if you have only a single node).