How does it look like?
Now that we have a nice interface defined, how would serialization and deserialization actually look like? I’ll give a straight example from my project where the World
class acts as a wrapper for a tree of Entity
objects, i.e. a World
has one root Entity
and an Entity
can contain 0:n entities itself. I have added additional tabs to emphasize the structure.
void vte::world::World::writeTo( vte::core::Serializer* destination ) { destination->beginAttribute( "world" ); destination->writeNumberOfElements( 1 ); writeEntity( root, destination ); destination->endAttribute(); // world } void vte::world::World::writeEntity( vte::world::Entity* entity, vte::core::Serializer* destination ) { destination->beginAttribute( "entity" ); destination->writeParameter( "type", entity->getType(), vte::core::lexical_cast< std::string >( entity->getType() ) ); destination->writeParameter( "name", entity->getName() ); destination->writeParameter( "id", entity->getID() ); entity->writeTo( destination ); destination->beginAttribute( "children" ); destination->writeNumberOfElements( (u32) entity->getChildren().size() ); for( vecEntities::iterator it = entity->getChildren().begin(); it != entity->getChildren().end(); ++it ) { Entity* child = *it; writeEntity( child, destination ); } destination->endAttribute(); // children destination->endAttribute(); // entity }
Let’s dig into the code line by line. Line 1, method writeTo
, defines the entry point where the however-it-was-created (we’ll get to this later) Serializer
is handed over to do its work. In line 3, the enclosing tag I mentioned earlier is created. Since this tag simply wraps the entity hierarchy, it has exactly one child element, the root Entity
, so I set the number of child elements to 1 in line 4. Next, I jump into the actual entity serialization in line 5.
writeEntity
performs the recursive entity serialization. Starting with the root element handed over by writeTo
, it starts a new entity
attribute in line 11 and then writes some crucial parameters all entities have in common, i.e. a type, a name and a unique ID. The rest of attributes is written by the Entity
itself in line 17 – here, I make use of polymorphism which means that each object inherited from Entity
or its inheritors adds the attributes it requires to successfully serialize itself. Then, I create a new children
attribute which wraps all child entities of the current Entity
, save the number of children and dive into recursion for each child entity. After that, the children and entity attributes are closed in line 26 and 28 respectively and we’re done. Easy, huh?
Because an example often explains more than a thousand words, here’s a part of the output of the XML serializer of my project.
<world> <entity type="root" name="RootEntity_1" id="1"> <transformation position="0 0 0" rotation="0 0 0" scale="1 1 1" /> <scriptable fileName="" class="" /> <children> <entity type="camera" name="Camera_2" id="2"> <transformation position="0 0 0" rotation="0 0 0" scale="1 1 1" /> <scriptable fileName="" class="" /> <children /> </entity> <entity type="skybox" name="SkyBox_3" id="3"> <transformation position="0 0 0" rotation="0 0 0" scale="1 1 1" /> <scriptable fileName="" class="" /> <top texture="resource/defaults/skybox/irrlicht2_up.jpg" /> <bottom texture="resource/defaults/skybox/irrlicht2_dn.jpg" /> <left texture="resource/defaults/skybox/irrlicht2_lf.jpg" /> <right texture="resource/defaults/skybox/irrlicht2_rt.jpg" /> <front texture="resource/defaults/skybox/irrlicht2_ft.jpg" /> <back texture="resource/defaults/skybox/irrlicht2_bk.jpg" /> <children /> </entity> ... </children> </entity> </world>
Before we move on to the concrete implementation of the (de)serializers, one last word of explanation regarding the interface. You may have wondered why the writeParameter
method for type s32
has an additional attribute readable
. The reason is that I have several enumerations (which are internally represented as s32
) which would become numerical digits when written to XML. But since XML is so descriptive elsewhere, I wanted to have the opportunity to have descriptive values written to and read from XML.
4 Comments