XML Serialization
In order to manage the XMLs DOM tree, we should make use of a nice library which does all the magic for us. I went for TinyXML because I made good experiences with it in DVW. You may want to have a short look into its documentation in order to understand what I did in the following implementation.
Let’s jump straight into the implementation of die XMLSerializer
class.
#ifndef VTE_CORE_XMLSERIALIZER_H #define VTE_CORE_XMLSERIALIZER_H #include "Serializer.h" #include <core/tinyxml/tinyxml.h> namespace vte { namespace core { class XMLSerializer : public Serializer { public: XMLSerializer(); virtual ~XMLSerializer(); void beginAttribute( const std::string& name ); void writeNumberOfElements( u32 numElements ) { // Not used for XML } void writeParameter( const std::string& name, const std::string& value ); void writeParameter( const std::string& name, s32 value, const std::string& readable ); void writeParameter( const std::string& name, const bool& value ); void writeParameter( const std::string& name, const u32& value ); void writeParameter( const std::string& name, const f32& value ); void writeParameter( const std::string& name, const vec3& value ); void writeParameter( const std::string& name, const irr::video::SColorf& value ); void endAttribute(); TiXmlDocument& getDocument() { return doc; } protected: TiXmlDocument doc; // The actual XML document created by the serializer TiXmlElement* currentElement; // The current node we're working on }; } // namespace core } // namespace vte #endif
As you see, there’s no magic going on here. XMLSerializer
inherits from Serializer
and implements the pure virtual methods. As I mentioned before, the XML serialization makes no use of the writeNumberOfElements
method, so it’s left empty here.
On top of that the XMLSerializer
has TinyXMLs TiXmlDocument
as an attribute which holds the XML document the serializer builds during the serialization process and a TiXmlElement
as the node the serializer currently works on. Moreover there’s an accessor method for the generated TiXmlDocument
.
Now for the implementation.
vte::core::XMLSerializer::XMLSerializer( const std::string& fileName ) : Serializer(), currentElement( 0 ) { TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" ); doc.LinkEndChild( decl ); } vte::core::XMLSerializer::~XMLSerializer() { }
The constructor initializes the currentElement
attribute with 0 and creates an XML version declaration which is attached to the document which acts as TinyXML’s root element.
void vte::core::XMLSerializer::beginAttribute( const std::string& name ) { TiXmlElement* child = new TiXmlElement( name ); if( currentElement == 0 ) { doc.LinkEndChild( child ); } else { currentElement->LinkEndChild( child ); } currentElement = child; }
This is the actual workhorse of the XMLSerializer
. Whenever beginAttribute
is called, a new child element is created in the XMLs DOM right under the current element. Unless we did not create one yet, the newly created child is appended directly under the document.
Writing a single parameter is pretty simple then.
void vte::core::XMLSerializer::writeParameter( const std::string& name, const std::string& value ) { VTE_ASSERT( currentElement != 0 ); // Make sure that beginAttribute has been called! currentElement->SetAttribute( name, value ); }
I leave the implementation of the rest of the writeParameter
methods to you. Just remember that we defined some lexical_cast
specializations e.g. for bool
which you should use.
void vte::core::XMLSerializer::endAttribute() { VTE_ASSERT( currentElement != 0 ); // Make sure that beginAttribute has been called! if( currentElement && currentElement->Parent() != 0 ) { // becomes 0 if the document is reached currentElement = currentElement->Parent()->ToElement(); } }
Whenever an attribute is finished, we’ll move the currentElement
pointer back to the parent element in the XML DOM. In order to recognize that we’re back at the top of the DOM, we use TinyXMLs ToElement
method which will return 0 if Parent()
returns the document (since document is of type TiXmlDocument
, not TiXmlElement
, just think of dynamic casting here).
4 Comments