GnrStructures

Bags can be seen as unhomogeneus collections of hiearchical data linked by containment relations. Each bag's element can have some metadata called attributes that corresponds to an XML item's attributes. Starting from this considerations we saw that many complex and hierarchical problems could be represented as bags. So we defined a particular way to create special bags that represents structures of objects: GnrStructures.

This can be considered a sort of programming pattern based on the abstract classes

GnrStructData is a subclass of Bag that implements functional syntax for adding particular elements to the tree. GnrStructObj is a tree of GnrObjects? that is auto-builded starting from an instance of GnrStructData.

We use this paradigm in many contexts such as databases, web pages, wx applications.

GnrStructData

GnrStructData is a bag-derived class used for defining structures descriptors.

By structure we mean a complex entity that is composed by an unhomogeneous collection of other complex entities (e.g. HTML pages, XML, GUI elements, etc.).

By entity we mean an object that has the following charateristics:

  • It belongs to a type. Entity type is called tag.
  • It may have attributes
  • If may contain other entities.

In other words by entity we mean something that is representable as an XML node.

A descriptor is an object that contains all entities definitions and manages relationships between them.

The primary use of descriptor is a functional syntax for defining entities and convert them to their XML representation.

Example

We want a vehicle descriptor that could load car definitions from XML or define them in python with function calls. So that we define the class VehicleDescriptor that inherits from GnrDataStructure.

class VehicleDescriptor(GnrStructData):
    
    def vehicle(self, name='vehicle', weight=None, lenght=None, width=None, type=None ,**kwargs):
        return 
        self.child(tag='vehicle', name=name, weight=weight, lenght=lenght, width=width, type=type ,**kwargs)
    
    def body(self, color=None, **kwargs):
        return self.child(tag='body', color=color, **kwargs)
    
    def doors(self, automatic=None, number=None, **kwargs):
        return self.child(tag='doors', automatic=automatic, number=number ,**kwargs)
    
    def door(self, name, type=None, **kwargs):
        return self.child(tag='door', name=name, type=type, **kwargs)
    
    def mechanics(self, name=None, **kwargs):
        return self.child(tag='mechanics', name=name, **kwargs)
    
    def engine(self, name=None, cc=None, hp=None, alimentation=None, **kwargs):
        return self.child(tag='engine', name=name, cc=cc, hp=hp, alimentation=alimentation, **kwargs)
    
    def wheels(self, rim=None, **kwargs):
        return self.child(tag='wheels', rim=rim, **kwargs)
    
    def wheelfront(self, name=None, diameter=None, **kwargs):
        return self.child(tag='wheelfront', name=name, diameter=diameter, **kwargs)
    
    def wheelrear(self, name=None, diameter=None, **kwargs):
        return self.child(tag='wheelrear', name=name, diameter=diameter, **kwargs)
    
    def tyre(self, name=None, type=None,**kwargs):
        return self.child(tag='tyre', name=name, type=type,**kwargs)
    
    def seats(self, number=None, covering=None, **kwargs):
        return self.child(tag='seats', number=number, covering=covering, **kwargs)

The class VehicleDescriptor implements methods for defining entities and put them at their right place in the structure tree. Each method defines a particular subset of attributes passed to the GnrDataStructure method child.

Now, let's instantiate the descriptor using the class method makeRoot(). If we don't pass any argument to makeRoot() it creates an empty description, else it may take the path of the XML file and it loads the description from it. In the following code wecreate an empty description and fill it with VehicleDescriptor methods, then we export the obtained description into XML.

if __name__ =='__main__':
    
    descriptor=VehicleDescriptor.makeRoot()
    
    #---car description---
    
    car= descriptor.vehicle(name='500', weight=140, height=150, lenght=230, type='citycar')
    doors=car.body(color='red').doors(automatic='yes', number='3')
    doors.door(name='rear-lft', type='standard')
    doors.door(name='rear-rght', type='standard')
    doors.door(name='back', type='baggage')
    mech=car.mechanics(name='F500CX16V')
    mech.engine(name='fiat500', cc='1000', hp='100', alimentation='super')
    wheels=mech.wheels(rim='500Chrome')
    wheels.wheelfront(diameter='50').tyre(name='Pirelli', type='rain')
    wheels.wheelrear(diameter='50').tyre(name='Pirelli', type='rain')
    car.seats(number='2', covering='black leather')
    
    #---export car description as XML---

    descriptor.save('myCar.xml')

Here's the XML obtained from the code's execution.

<?xml version='1.0' encoding='UTF-8'?>
<GenRoBag>
	<500 _T="BAG" tag="vehicle" weight="140" lenght="230" type="citycar" height="150"> 
	<body_0 _T="BAG" color="red" tag="body">
		<doors_0 _T="BAG" tag="doors" automatic="yes" number="3">
			<rear-lft _T="BAG" tag="door" type="standard" />
			<rear-rght _T="BAG" tag="door" type="standard" />
			<back _T="BAG" tag="door" type="baggage" />
		</doors_0>
	</body_0>
	<F500CX16V _T="BAG" tag="mechanics">
		<fiat500 _T="BAG" cc="1000" hp="100" alimentation="super" tag="engine" />
		<wheels_1 _T="BAG" rim="500Chrome" tag="wheels">
			<wheelfront_0 _T="BAG" diameter="50" tag="wheelfront">
				<Pirelli _T="BAG" tag="tyre" type="rain" />
			</wheelfront_0>
			<wheelrear_1 _T="BAG" diameter="50" tag="wheelrear">
				<Pirelli _T="BAG" tag="tyre" type="rain" />
			</wheelrear_1>
		</wheels_1>
	</F500CX16V>
	<seats_2 _T="BAG" tag="seats" number="2" covering="black leather" />
</500>
</GenRoBag>

Descriptor can be also sed as recipe for building a structure of objects, caled GnrStructObj.

GnrStructObj

GnrStructObj is a bag derived class that is used for building tree-structured objects (like GUI). GnrStructObj reads entity definitions from a recipe defined with GnrStructData.

Let's see how to build a hierachy of vehicle parts (starting the car description of the previous example.

First of all let's define the classes representing vehile components in a module carsobject.py. All those classes must inherits from GnrStructObj and must implements the method init. Since each class corresponds to an entity defined by the descriptor, each class must have a special property whose value is equal to the entity tag. In our example this property is called carobj.

class Car(GnrStructObj):
    carobj='vehicle'

    def init(self, **kwargs):
        self.tag=self.attributes['tag']
        self.model=self.attributes['carname']
        self.type=self.attributes['type']
        self.length=self.attributes['length']
        self.height=self.attributes['height']
        self.weight=self.attributes['weight']
    
    def show(self):
        print 'This is a %s, it is a %s its length is %i' %(self.model,
                                                            self.type,
                                                            self.length)
    def start(self):
        print 'brooom'
        
class CarBody(GnrStructObj):
    carobj='body'
    def init(self):
        self.tag=self.attributes['tag']
        self.color=self.attributes['color']
    
    def show(self):
        print '%s: its color is %s' %(self.tag, self.color)

Error: Macro Image(structures.png) failed
Attachment 'wiki:GnrStuctures: structures.png' does not exist.

A GnrStructObj holds reference to parent and children elements.

  • GnrStructObj.children is a dictionary made of couples entyty name, objects.
  • GnrStruct.parent is the reference to the parent object.

Each of the GnrStructObj objects has a property called name which contains the element's name and a property attributes that's a dictionary the element's attributes, like color, height, length etc.

Now let's see how to build car parts objects starting from car's description.

objDict= moduleDict('carObjects', 'carobj')

mycarStructObj=GnrStructObj.makeRoot(None,
                                     mycarStructData.getNode('vehicle'),
                                     objDict)
    

First of all we define an objectDictionary calling the gnrlang function moduleDict. moduleDict receives the name of the python module where the classes have been defined and the name of the property that corresponds to elements' tag. The result of moduleDict is a dictionary that holds all relations between entities and corresponding classes. Then we create the structure of objects calling the classmethodGnrStructObj.makeRoot that starts the structure's building. It receives the following parameters:

  • cls: ???
  • root element: is an element of the StructData from which the method starts to build the structObj
  • objDict: it's a GnrModuleDict that keeps the corripondence between name and class

Now we have obtained the structure of object, let's observe it.

>>> mycarStructObj.show()
    This is a 500, it is a citycar its length is 230

>>> mycarStructObj.children
{'body_0': <carObjects.CarBody object at 0x749870>,
'F500CX16V': <carObjects.Mechanics object at 0x749830>,
'seats_2': <carObjects.Seats object at 0x7498f0>}

>>> mycarStructObj.children['body_0'].show()
body: its color is red