Next / Previous / Contents / Shipman's homepage

3.2. Design refinements: convenience features

Before we discuss the features of the sox module, let us look at another useful XML generation technology and see what features we can borrow from it.

The author has used the etbuilder module, described in Python XML processing with lxml, quite extensively in a wide variety of XML generation applications. This module includes a multi-purpose element factory “E” that greatly streamlines XML generation. The etbuilder module was in turn based on the An ElementTree Builder by Fredrik Lundh.

In particular, calls to the E() factory allow an arbitrary number of positional and keyword arguments that are processed by type.

Here is a small, complete script that demonstrates how terse XHTML generation can be.

#!/usr/bin/env python
import sys
from etbuilder import E, et

root = E.html(
    E.head(
        E.title("Page title here")),
    E.body(
        E.h1("Main title here"),
        E.hr(),
        E.p({'class': 'note'}, "Some text",
            " and some more text", id='p001')))
doc = et.ElementTree(root)
doc.write(sys.stdout, pretty_print=True)

And here is the output of that script:

<html>
  <head>
    <title>Page title here</title>
  </head>
  <body>
    <h1>Main title here</h1>
    <hr/>
    <p id="p001" class="note">Some text and some more text</p>
  </body>
</html>

These are all good ideas, but we cannot implement all of them in the sox module.

We can't implement nested element calls as in E(). Because all Python arguments are evaluated before the call, we would have to save up all the child content until after the start tag gets written. That defeats our low-memory goal.

We can borrow the other two techniques, though.

  1. String-type positional arguments will be added as child content after the start tag. All arguments must be Unicode, or strings convertible to Unicode with UTF-8 encoding. (Support for other encodings would be easy to add, if requested.)

    Some other types (int, bool) will be run through unicode() and then treated as string content.

  2. Dictionary arguments and keyword arguments will become attributes within the start tag, assuming that their names are valid XML names.

So here is our sox conversion of the above etbuilder example.

import sys
import sox
s = sox.Sox(sys.stdout)
html = s.start("html")
head = s.start("head")
title = s.start("title", "Page title here")
title.end()
body = s.start("body")
s.start("h1", "Main title here").end()
s.leaf("hr")
s.start("p", {'class': 'note'}, "Some text",
        " and some more text", id='p001').end()
body.end()
html.end()