Customized XML configuration files

For a more complex XML configuration file, you can refer to http://wiki.metawerx.net/wiki/Web.xml. These files contain a mixture of special-purpose tags and general-purpose tags. These documents can be challenging to parse. There are two general approaches:

  • Write a document processing class that uses XPath queries to locate the tags in the XML document structure. In this case, we'll create a class with properties (or methods) to locate the requested information in the XML document.
  • Unwind the XML document into a Python data structure. This is the approach followed by the plist module, mentioned previously. This will convert the XML text values into native Python objects.

Based on examples of the web.xml files, we'll design our own customized XML document to configure our simulation application:

<?xml version="1.0" encoding="UTF-8"?> 
<simulation> 
    <table> 
        <dealer>Hit17</dealer> 
        <split>NoResplitAces</split> 
        <decks>6</decks> 
        <limit>50</limit> 
        <payout>(3,2)</payout> 
    </table> 
    <player> 
        <betting>Flat</betting> 
        <play>SomeStrategy</play> 
        <rounds>100</rounds> 
        <stake>50</stake> 
    </player> 
    <simulator> 
        <outputfile>data/ch14_simulation6b.dat</outputfile> 
        <samples>100</samples> 
    </simulator> 
</simulation> 

This is a specialized XML file. We didn't provide a DTD or an XSD, so there's no formal way to validate the XML against a schema. However, this file is small, easily debugged, and parallels other example initialization files. Here's a Configuration class that can use XPath queries to retrieve information from this file:

import xml.etree.ElementTree as XML

class Configuration:

def read_file(self, file):
self.config = XML.parse(file)

def read(self, filename):
self.config = XML.parse(filename)

def read_string(self, text):
self.config = XML.fromstring(text)

def get(self, qual_name, default):
section, _, item = qual_name.partition(".")
query = "./{0}/{1}".format(section, item)
node = self.config.find(query)
if node is None:
return default
return node.text

def __getitem__(self, section):
query = "./{0}".format(section)
parent = self.config.find(query)
return dict((item.tag, item.text) for item in parent)

We've implemented three methods to load the XML document: read(), read_file(), and read_string(). Each of these simply delegates itself to an existing method function of the xml.etree.ElementTree class. This parallels the configparser API. We could use load() and loads() method names too, as they would delegate themselves to parse() and fromstring(), respectively.

For access to the configuration data, we implemented two methods: get() and __getitem__(). These methods build XPath queries to locate the section and item within the XML structure. The get() method allows us to use code like this: stake = int(config.get('player.stake', 50)). The __getitem__() method allows us to use code like this: stake = config['player']['stake'].

The parsing is a trifle more complex than a PLIST file. However, the XML document is much simpler than an equivalent PLIST document.

We can use the main_cm_prop() function, mentioned in the previous section on the properties files, to process this configuration.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset