Hi there…
This small tutorial will deal with the ConfigLoader class. We will see what is this class for and how to use it in a project.
Of course you’ll need the pixlib framework to do so. You can download it HERE or you can use the repository HERE.
You will need as well some basic understanding of the framework. If you haven’t done it yet check the first tutorial giving you an introduction to the framework, PixLib – Understanding the basis of the framework
Ok, let’s start…
I. What is the ConfigLoader class
First, you will find the ConfigLoader class in the com.bourre.data.libs package.
The ConfigLoader class is the class that will help you loading datas from a xml file.
Better than that, you will be able to :
- strong typing your nodes
- create objects from the xml
- create custom objects using a custom deserializer
Of course this class is not doing all of this but is the entry point for those tasks. The classes used through this one are :
- Config which will return the object created from the xml
- XMLToObject which is the entry point for the creation of your object
- XMLToObjectDeserializer
II. How to use it?
a. The basis
The ConfigLoader work this way.
BY DEFAULT, the instance created from the ConfigLoader class will load the XML “config.xml”, will use the XMLToObject and XMLToObjectDeserializer to parse your XML file and will send back the result in the Config class singleton – which is only an empty object -
But you can specify the path of the XML, the deserializer you want to use ( if you have complex custom object – we will see that later – ) and the object that should hold all the data loaded from the XML file.
To specify the object holding the result and the deserializer you just need to give them as arguments when creating a new ConfigLoader instance ( new ConfigLoader( holder, deserializer ) )
A couple of things you need to know about your xml structure:
- in your XML, you must have a node parent of all the others. This node will be the container and will not be visible in the result sent back by the parser ( usually we are calling it config )
- by default if a XML node has children, the parser will create an object out of it and each child will be a property of this object
Anyway, here is the code using all default settings
[as]
private function _onLoadConfig( e : ConfigLoaderEvent ) : Void {
// Broadcast the onLoadComplete event
XEventBroadcaster.getInstance().broadcastEvent( new BasicEvent( EventList.CONFIG_LOADED ) );
}
// create a new ConfigLoader and set it up to load the desire xml file
_cl = new ConfigLoader();
_cl.addEventListener( ConfigLoader.onLoadInitEVENT, this, _onLoadConfig );
_cl.load();
[/as]
Keep in mind that in most of the case you will use the ConfigLoader class in the same way. The difference will come from your XML.
So here, you are creating the instance, then adding listener to events dispatch by the ConfigLoader and when loaded broadcasting an event to let the application know that you are ready to go…
Oh, and the events dispatched by the ConfigLoader are:
- onLoadInitEVENT
- onLoadProgressEVENT
- onTimeOutEVENT
and are static property of the ConfigLoader class so can be accessed like ConfigLoader.onInitEVENT.
So saying that if we have this
[xml]
[/xml]
you’ll get a Config.getInstance() object like this
[xml]
–
|- property01 : “Property 1″
|- property02 : “Property 2″
[/xml]
Even if you’re using the default way to parse your XML you will need to know some things about the XMLToObjectDeserializer class.
There is some interesting features.
You can specify if you want the attributes of your nodes to be deserialized ( by default they are not ). To do so you need to define two static variables of the XMLToObjectDeserializer. Those properties are XMLToObjectDeserializer.ATTRIBUTE_TARGETED_PROPERTY_NAME which will get a string defining the property’s name of your object ( eg “attributes” so you’ll get yourCustomObject.attributes ( object ) created ) which will hold the object made from the attributes ( yourCustomObject.attributes will get all the object made from the attributes of your node ) and XMLToObjectDeserializer.DESERIALIZE_ATTRIBUTES which is a boolean saying if this feature is on ( true ) or off ( false, by default )
You can set up that if the XML has same nodes name ( with the same parent ) those nodes will be pushed in an array. To activate this feature you are doing XMLToObjectDeserializer.PUSHINARRAY_IDENTICAL_NODE_NAMES = true. The array name will be the nodes name.
Finally for debugging you can set up the XMLToObjectDeserializer.DEBUG_IDENTICAL_NODE_NAMES to true to have a warning in your logger everytime you ahve 2 nodes with identical names
Ok now you know how the “basis” works let’s see the interesting part of it
b. Typing your object
This is really easy to do. In your XML file in each node you can add an attribute named “type”. This attribute can have those values:
- array: the object created will be an Array, eg of value in the node: 1,’toto’,true
- boolean: the object created will be a Boolean, eg of value in the node: true
- class: the object created will be an instance of a custom object. In the node value you are giving the path of the class and arguments like
[xml]
‘net.webbymx.tutorial02.testObject’, argument01, argument02
[/xml] - number: the object created will be a Number, eg of value in the node: 15
- point: the object will be a Point, eg of value in the node: 5,2 – in the format x,y
- string: the object created will be a String, eg of value: a string, or < ![CDATA[A string]] ( remove the white space after the < ) when you have specific characters
- if you have no type, an Object will be created
That’s great isn’t it? You can already do lot’s of things.
But as you have probably notice the support of custom object here is not so good. In the example above you can see that when you are creating a custom object you cannot add node child ( properties ). The way it is set up is for simple objects that needs simple arguments ( that can be parse as string ). What if you need a more complex object?
III. I want full control when creating my Custom Objects
a. A custom deserializer
Since the rev35, PixLib offers developers to set up custom deserializer. The idea is simple. Extends the XMLToObjectDeserializer or create your own implementing the IXMLToObjectDeserializer. If extending the one from the framework you can simply add new types with the method yourDeserializer.addType( “yourTypeString”, yourDeserializer, functionToHandleThatType )… During my project I tried this way. But I’m a bit lazy see, and I don’t want everytime to do my own deserializer, so I tweak the XMLToObjectDeserializer. Let’s see what it is doing more.
b. The tweaked XMLToObjectDeserializer
I’ve tweak the file to be able to:
- define a custom object class and the arguments of this constructor but still be able to add properties to the new created object by adding two keywords in the node attributes, clazz and arguments
- define a setter attribute. The method ( given by the string of the setter attribute ) will be called passing the node value in it. This method will be called of course if the owner of your current object has a type=”class” – and if it has this method
So then you can have CustomObject with privates properties and setter to set them. So you sure you’ll not have undesired properties… Moreover you could create Custom Objects which will have Custom Objects as properties and have strong typing when setting them. This class of course keep as well all the features of the original one.
How does it work?
An example is better than any words… This example is taken from a new project I’m working on. As you can guess it’s a tile based engine.
[xml]
[/xml]
I could have done something smaller but this example shows how helpful this tweak is ( I think ).
I have done my structure like this:
- A map is a custom object having an array of level ( different area of the map ), a short name, a description and a link to a tileset ( bitmap data to take the tiles image from )
- A level is a custom object that has a level number and an array of layer( ground, not movable object, movable object, … )
- A layer is a custom object that has a depth and an array holding the info
So in my XML file starting from the smallest object, the layer.
I’m saying that this node will create a LevelLayer object, and I’m giving the arguments for the constructor
[xml]type=”class” clazz=”net.webbymx.bipcube.engines.tilebased.vos.LevelLayer” arguments=”6,8″[/xml]
then I’m setting the depth and the map info using setter ( as my properties are private )
[xml]
[/xml]
the lvl node:
I’m saying that this node will create a LevelLayer object. This one needs no arguments for the constructor
[xml]type=”class” clazz=”net.webbymx.bipcube.engines.tilebased.vos.Level”[/xml]
I’m setting up the level number, and my layers. You can see on the layer nodes that they have a setter attribute as well. So once created they will feed the setter of their owner.
And then the same for the map node which will pass the new created lvl in its setLevel setter.
IV. Conclusion
I hope you will like this. As usual if you have any feedbacks / comments feel free to post.
You can download the sources files here ( working example and the tweaked class )
[Download id not defined]
And if you’re reading this Francis, you reckon we could put it in the official release?
Pingback: Dev by MX» Blog Archive » Pixlib - Tut 03 - How to load assets at runtime