Mapping XML to Models¶
XML is mapped to xml_models.Model
via Fields
. Each field requires an xpath expression that determines which
node or attribute to get the data from. Each field also has an optional default
value for when no value can be
retrieved from the XML.
Basic Fields¶
The available field mappings are
CharField
– returns string dataIntField
– returns integersDateField
– returns a date from using the supplieddate_format
mask or the default ISO8601 formatFloatField
– returns a floating point numberBoolField
– returns a booleanOneToOneField
– returns axml_model.Model
subclassCollectionField
– returns a collection of either one of the above types, or anxml_model.Model
subclass
Most of these fields are fairly self explanatory. The CollectionField
and OneToOneField
is where it gets
interesting. This is what allows you to map instances or collections of nested entities, such as:-
<Person id="112">
<firstName>Chris</firstName>
<lastName>Tarttelin</lastName>
<occupation>Code Geek</occupation>
<website>http://www.pyruby.com</website>
<contact-info>
<contact type="telephone">
<info>(555) 555-5555</info>
<description>Cell phone, but no calls during work hours</description>
</contact>
<contact type="email">
<info>me@here.net</info>
<description>Where possible, contact me by email</description>
</contact>
<contact type="telephone">
<info>1-800-555-5555</info>
<description>Toll free work number for during office hours.</description>
</contact>
</contact-info>
</Person>
This can be mapped using a Person
and a ContactInfo
model:-
class Person(Model):
id = IntField(xpath="/Person/@id")
firstName = CharField(xpath="/Person/firstName")
lastName = CharField(xpath="/Person/lastName")
contacts = CollectionField(ContactInfo, order_by="contact_type", xpath="/Person/contact-info/contact")
class ContactInfo(Model):
contact_type = CharField(xpath="/contact/@type")
info = CharField(xpath="/contact/info")
description = CharField(xpath="/contact/description", default="No description supplied")
This leads to the usage of a person as :-
>>> person.contacts[0].info
me@here.com
Collections¶
When querying collections or lists, it is assumed that a collection of zero or more results are returned wrapped in an enclosing collection tag.
As some REST APIs may return lists wrapped in one or more layers of metadata, Models may also define
a collection_node
attribute. this allows the XML processor to find the relevant node.
Note
collection_node
is the tag name only and not an xpath expression.
For example, given the following XML
<reponse status="200">
<metadata count="2">
<collection>
<model ... />
<model ... />
</collection>
</metadata>
</response>
We would need to define a Model with a collection_node
like so
class SomeModel(Model):
fieldA = CharField(xpath="/some/node")
collection_node = 'collection'
Nested Collections¶
Similarly with Collections there may be a need where you have collections nested in metadata objects that are not relevant.
For example, given the following XML, you may only be interested in the Models. Rather than having to create a
Collection model as well you can create a collection from the nested XML using the collection_xpath
attribute.
<reponse status="200">
<metadata count="2">
<collection name="Collection1">
<model ... />
<model ... />
</collection>
<collection name="Collection2">
<model ... />
<model ... />
</collection>
</metadata>
</response>
class SomeModel(Model):
fieldA = CharField(xpath="/model/some/node")
collection_xpath = '//collection/model'
Note
collection_xpath
will pass the enclosing tag XML to the Model. Therefore your models field definitions
should start with the last tag name in the collection_xpath
as the example does with the model
tag.
Note
collection_node
and collection_xpath
are mutually exclusive