2.3.20. vacumm.misc.xml – XML serialization/deserialization

2.3.20.2. Content

This module provides XML serialization/deserialization features.

It is intented to provide a way to define python classes able to load/save data from/to XML elements, strings or files. The idea is to make a close but non restrictive link between XML and Python objects models with the least possible effort.

Below is an example to briefly introduce how to use this module. This could be simplified because there are shortcuts for default type, values and other stuff but we will be as explicit as possible to demonstrate how this module work.

Suppose you have or want the following XML syntax:

<Report>
    <MapFigure showgrid="True" output="meteo.png">
        <Title>Temperature and Wind</Title>
        <BoundingBox lonmin="-10" lonmax="10" latmin="40" latmax="60">
        <ColorBar levels="0,5,10,15,20,25,30"/>
        <Data file="/path/to/data/file" variable="temperature"/>
        <Data file="/path/to/data/file" variable="wind" plot="windbarbs"/>
    </Map>
</Report>

This can be serialized with the following python definitions:

class BoundingBox(XmlConfig):
    xml_attributes = {
        'lonmin':{type:float, default:-180},
        'lonmax':{type:float, default:180},
        'latmin':{type:float, default:-90},
        'latmax':{type:float, default:90},
    }

def parseFloatList(floatListString):
    return map(float, floatListString.split(','))

class ColorBar(XmlConfig):
    xml_attributes = {
        'levels':{type:parseFloatList, default:[0, 10, 20, 30]},
    }

class Data(XmlConfig):
    xml_attributes = {
        'file':{type:unicode, default:None},
        'variable':{type:unicode, default:None},
        'plot':{type=unicode, default:'fillcolor'},
    }

class MapFigure(XmlConfig):
    xml_attributes = {
        'showgrid':{type:bool, default:False},
        'temperature':{type:unicode, default:'output.png'},
    }
    xml_childnodes = {
        'boundingBox':{'type':BoundingBox, single:True},
        'colorBar':{'type':BoundingBox, single:True},
        'data':{'type':Data},
    }
    xml_textnodes = {
        'title':{'type':unicode, 'tagName':'Title', single:True},
    }

class Report(XmlConfig):
    xml_childnodes = {
        'mapFigures':{type:MapFigure},
    }

To load a file ‘report.xml’ containing the XML code above, you can either do:

r = Report()
r.load_xml_file('report.xml')

or

r = Report.from_xml_file('report.xml')

To save a xml file from the loaded object above you can do:

r.save_xml_file('report.xml')

Warning

  • This module make use of xml.etree.ElementTree and works with python >= 2.6.
  • Some XML functionnalities are not handled, there is no namespace support although namespaces can be ignored when loading XML data. When specifying an attribute name as ‘namespace:name’ the namespace is ignored when loading but is kept when saving.
  • When loading a list of elements into a dictionnary (e.g. using an attribute value as key), the order will be kept if the module collections.OrderedDict is available (python > 2.7)
class XmlConfig(*args, **kwargs)[source]

Bases: object

Base class for XML serializations/deserializations.

Subclasses can define the following class attributes which define the serialization specifications:

These attributes can also be passed as named arguments to the constructor to extend or overwrite those declared in the class definition.

XML attributes, childnodes and textnodes are stored in this instance (object) attributes.

classmethod dict(*a, **k)[source]

Wrapper to collections.OrderedDict if available, dict otherwise

classmethod from_url(url, *a, **k)[source]

Factory method instanciating from xml string returned by url.

classmethod from_xml_doc(d, *a, **k)[source]

Factory method instanciating from xml dom document.

classmethod from_xml_elt(e, *a, **k)[source]

Factory method instanciating from xml element.

classmethod from_xml_file(f, *a, **k)[source]

Factory method instanciating from xml file.

classmethod from_xml_str(s, *a, **k)[source]

Factory method instanciating from xml string.

get_current_file()[source]

Get the currently used xml file (from last load/save or manual set)

load_xml_doc(d, *a, **k)[source]

Load from an ElementTree object

load_xml_elt(e, *a, **k)[source]

Load configurations from an xml element.

load_xml_file(f, *a, **k)[source]

Load from a file

load_xml_str(s, *a, **k)[source]

Load from a string

post_load_xml(*a, **k)[source]

Called after load_xml_elt is executed

pre_load_xml(*a, **k)[source]

Called before load_xml_elt is executed

set_current_file(f)[source]

Set the currently used xml file. This method automatically called when loading/saving xml file

set_obj(obj)[source]
classmethod tag_name()[source]

Return the xml element name for this class or instance. If cls.xml_tag_name is not set, return class name formatted by xml_element_name()

to_obj()[source]
to_xml_doc(**kwargs)[source]

Dump object to an ElementTree

to_xml_elt(**kwargs)[source]

Dump object to an xml element.

to_xml_file(f, **kwargs)[source]

Dump object to a xml file.

to_xml_str(**kwargs)[source]

Dump object to a xml string.

to_xml_stream(stream, pretty=True, indent=' ', encoding='UTF-8', **kwargs)[source]

Dump object to a file object like stream.

xml_attributes = {}
classmethod xml_attributes_specs(attrs, copy=True)[source]

Fix attrs as used internally

xml_childnodes = {}
classmethod xml_childnodes_specs(childnodes, copy=True)[source]

Fix childnodes as used internally

classmethod xml_element_name(*a, **k)[source]
xml_tag_name = ''
xml_textnodes = {}
classmethod xml_textnodes_specs(textnodes, copy=True)[source]

Fix textnodes as used internally

class XmlConfigDict(*args, **kwargs)[source]

Bases: collections.OrderedDict, vacumm.misc.xml.XmlConfig

Convenient class inheriting Dict and XmlConfig to avoid metaclasses conflict when Dict is collections.OrderedDict

class XmlConfigList(*args, **kwargs)[source]

Bases: list, vacumm.misc.xml.XmlConfig

Convenient class inheriting list and XmlConfig

class XmlConfigMetaClass[source]

Bases: type

Metaclass used to pass the xml element from XmlConfig.from_xml_elt to XmlConfig.__init__. This allow XmlConfig descendants to use the loaded data in their __init__ straight after XmlConfig.__init__ have been called

If your implementation already inherit from a metaclass based class, you may use the code at: http://code.activestate.com/recipes/204197-solving-the-metaclass-conflict/

create_xml_element(name, attributes=None, childnodes=None, skipNone=True, **kwargs)[source]

Create an xml element with given attributes and children

Params:
  • name: the element tag name
  • attributes, optional: dict of attributes name:value
  • childnodes, optional: list/tuple/dict of ElementTree.Element object
  • skipNone, optional: skip attributes which value is None
Return:

a ElementTree.Element object

findchildren(elt, name)[source]

Find children of an element ignoring namespaces

Params:
  • elt: element to search in
  • name: searched element tag name
Return:

a generator on ElementTree.Element objects

getattribute(elt, name, default=None)[source]

Get the attribute value of an element ignoring namespaces

Params:
  • elt: element to search in
  • name: searched attribute name
  • default, optional: default value when elt has no such attribute
Return:

attribute value or default

hasattribute(elt, name)[source]

Check the presence of an element attribute ignoring namespaces

Params:
  • elt: element to search in
  • name: searched attribute name
Return:

boolean

load_xml_attributes(elt=None, attributes=None, dst=None, create=False)[source]

Deserialize attributes from an element

Params:
  • elt: element to search in
  • attributes: specification for attributes deserialization
    This may be either:
    • a list of attribute names
    • a dict of attributes {name:spec, …} with name as a string and spec as:
      • a type function
      • a list or tuple (type function, default value)
      • a dict {‘type’:function, ‘default’:value}
  • dst: an object that will be populated with the attributes
  • create: whether to create attributes in dst with the default value when they are not in elt

The type must be a callable taking the attribute value as single string argument and returning the converted value With no type function, attributes are loaded without modification (as string)

Return:dict of deserialized attributes
load_xml_childnodes(elt=None, childnodes=None, dst=None, create=False)[source]

Deserialize children from an element

Params:
  • elt: element to search in
  • childnodes: specification for children deserialization
    This must be a dict of object attribute {name:spec, …} with name as a string and spec as:
    • a type function
    • a list or tuple (type function, default value)
    • a dict with the entries:
      • type: a XmlConfig subclass
      • default: default value, expected as instance or list or dict of XMlConfig object(s), depending on the single/key parameters
      • create: whether to create the instance or list when there are no such children in elt
      • args: positionnal arguments for XmlConfig children creation
      • kwargs: named arguments for XmlConfig children creation
      • single: whether we expect a single instance or a list of instance as result in dst (default is False). This may also be an integer specifying the child 0-based index.
      • self: whether we want to register loaded children in dst as dict entries (default is False)
      • key: which children attribute to use as key when loading with self=True
  • dst: an object that will be populated with the children
  • create: whether to create attributes in dst with the default value when they are not in elt

The type must be a subclass of XmlConfig which will be used to deserialize the children elements

Return:a tuple (attributes, elements, entries) of the loaded data
load_xml_textnodes(elt=None, textnodes=None, dst=None, create=False, xml_element_name=<function xml_element_name>)[source]

Deserialize text node children from an element

Params:
  • elt: element to search in
  • textnodes: specification for text node children deserialization
    This must be a dict of object attribute {name:spec, …} with name as a string and spec as:
    • the text nodes tag name
    • a list or tuple (tag name, default value)
    • a dict with the entries:
      • tagName: the text nodes tag name (default is the textnode name formatted by xml_element_name)
      • type: a factory function taking the text node content as argument
      • default: default value, expected as instance or list depending on the single parameter
      • args: positionnal arguments for children creation
      • kwargs: named arguments for children creation
      • single: whether we expect a single instance or a list of instance as result in dst (default is False). This may also be an integer specifying the child 0-based index.
  • dst: an object that will be populated with the text node children
  • create: whether to create attributes in dst with the default value when they are not in elt

The type must be a callable taking the text node value as single string argument and returning the converted value.

With no type function, text nodes are loaded without modification (as string)

Return:None
log(*a, **k)[source]

Debugging log function

parse_bool(s)[source]
pretty_indent(elem, level=0, indent=' ')[source]

Indent an ElementTree element avoiding extraneous spaces around node text.

register(obj, attributes=None, elements=None, entries=None)[source]

Populate an object with data

Params:
  • obj: the object to be manipulated
  • attributes, optional: dict, used with setattr on obj
  • elements, optional: list, used with obj.extend
  • entries, optional: dict, used with obj.update
Return:

obj

splitns(name)[source]

Split a ‘namespace:name’ string into (‘namespace’, ‘name’) or (None, ‘name’) if the name doesnt contains a namespace.

usafe(o)[source]

Return a unicode textual representation of the given object

xml_element_name(name)[source]

Build an xml element name from the given name, this function returns a CamelCase name with any non alphanumeric characters omitted (eg. ‘Class_A’ => ‘ClassA’, ‘class_b’ => ‘Classb’ and class_C => ‘ClassC’)