Entrian Solutions
By the same author: 

Are you a professional Visual Studio developer?

Then you should check out Entrian Source Search:

Screenshot

Entrian Source Search is a powerful search addin for Visual Studio.

It displays syntax colored search results within a fraction of a second, whether you're working with hundreds of lines of code or millions.

It's the fastest and easiest way to navigate your source code.

Learn more...

Also available in Polish (thanks, Andrey)
and in Portuguese (thanks, Artur)
and in Spanish (thanks, Lera)
and in Russian (thanks, Ruslan)

PyMeld

A simple, lightweight system for manipulating HTML (and XML, informally) using a Pythonic object model. PyMeld is a single Python module, PyMeld.py.

Features:

  • Allows program logic and HTML to be completely separated - a graphical designer can design the HTML in a visual HTML editor, without needing to deal with any non-standard syntax or non-standard attribute names. The program code knows nothing about XML or HTML - it just deals with objects and attributes like any other piece of Python code.
  • Designed with common HTML-application programming tasks in mind. Populating an HTML form with a record from a database is a one-liner (using the % operator - see below). Building an HTML table from a set of records is just as easy, as shown in the example below.
  • No special requirements for the HTML/XML (or just one: attribute values must be quoted) - so you can use any editor, and your HTML/XML doesn't need to be strictly valid.
  • Works by string substitution, rather than by decomposing and rebuilding the markup, hence has no impact on the parts of the page you don't manipulate.
  • Does nothing but manipulating HTML/XML, hence fits in with any other Web toolkits you're using.
  • Tracebacks always point to the right place - many Python/HTML mixing systems use exec or eval, making bugs hard to track down.

Quick overview

A PyMeld.Meld object represents an XML document, or a piece of one. All the elements in a document with id=name attributes are made available by a Meld object as object.name. The attributes of elements are available in the same way. A brief example is worth a thousand words:

>>> from PyMeld import Meld
>>> xhtml = '''<html><body>
... <textarea id="message" rows="2" wrap="off">Type your message.</textarea>
... </body></html>'''
>>> page = Meld(xhtml)                # Create a Meld object from XHTML.
>>> print page.message                # Access an element within the document.
<textarea id="message" rows="2" wrap="off">Type your message.</textarea>
>>> print page.message.rows           # Access an attribute of an element.
2
>>> page.message = "New message."     # Change the content of an element.
>>> page.message.rows = 4             # Change an attribute value.
>>> del page.message.wrap             # Delete an attribute.
>>> print page                        # Print the resulting page.
<html><body>
<textarea id="message" rows="4">New message.</textarea>
</body></html>

So the program logic and the HTML are completely separated - a graphical designer can design the HTML in a visual XHTML editor, without needing to deal with any non-standard syntax or non-standard attribute names. The program code knows nothing about XML or HTML - it just deals with objects and attributes like any other piece of Python code. Populating an HTML form with a record from a database is a one-liner (using the % operator - see below). Building an HTML table from a set of records is just as easy, as shown in the example below:

Real-world example:

Here's a data-driven example populating a table from a data source, basing the table on sample data put in by the page designer. Note that in the real world the HTML would normally be a larger page read from an external file, keeping the data and presentation separate, and the data would come from an external source like an RDBMS. The HTML could be full of styles, images, anything you like and it would all work just the same.

>>> xhtml = '''<html><table id="people">
... <tr id="header"><th>Name</th><th>Age</th></tr>
... <tr id="row"><td id="name">Example name</td><td id="age">21</td></tr>
... </table></html>'''
>>> doc = Meld(xhtml)
>>> templateRow = doc.row.clone()  # Take a copy of the template row, then
>>> del doc.row                    # delete it to make way for the real rows.
>>> for name, age in [("Richie", 30), ("Dave", 39), ("John", 78)]:
...      newRow = templateRow.clone()
...      newRow.name = name
...      newRow.age = age
...      doc.people += newRow
>>> print re.sub(r'</tr>\s*', '</tr>\n', str(doc))  # Prettify the output
<html><table id="people">
<tr id="header"><th>Name</th><th>Age</th></tr>
<tr id="row"><td id="name">Richie</td><td id="age">30</td></tr>
<tr id="row"><td id="name">Dave</td><td id="age">39</td></tr>
<tr id="row"><td id="name">John</td><td id="age">78</td></tr>
</table></html>

Note that if you were going to subsequently manipulate the table, using PyMeld or JavaScript for instance, you'd need to rename each row, name and age element to have a unique name - you can do that by assigning to the id attribute but I've skipped that to make the example simpler.

As the example shows, the += operator appends content to an element - appending <tr> elements to a <table> in this case.

Shortcut: the % operator

Using the object.id = value syntax for every operation can get tedious, so there are shortcuts you can take using the % operator. This works just like the built-in % operator for strings. The example above could have been written like this:

>>> for name, age in [("Richie", 30), ("Dave", 39), ("John", 78)]:
...      doc.people += templateRow % (name, age)

The % operator, given a single value or a sequence, assigns values to elements with `id`s in the order that they appear, just like the % operator for strings. Note that there's no need to call clone() when you're using %, as it automatically returns a modified clone (again, just like % does for strings). You can also use a dictionary:

>>> print templateRow % {'name': 'Frances', 'age': 39}
<tr id="row"><td id="name">Frances</td><td id="age">39</td></tr>

The % operator is really useful when you have a large number of data items - for example, populating an HTML form with a record from an RDBMS becomes a one-liner.

Note that these examples are written for clarity rather than performance, and don't necessarily scale very well - using += to build up a result in a loop is inefficient, and PyMeld's % operator is slower than Python's built-in one. See toFormatString() in the reference manual for ways to speed up this kind of code.

Element content

When you refer to a named element in a document, you get a Meld object representing that whole element:

>>> page = Meld('<html><span id="x">Hello world</span></html>')
>>> print page.x
<span id="x">Hello world</span>

If you just want to get the content of the element as string, use the _content attribute:

>>> print page.x._content
Hello world

You can also assign to _content, though that's directly equivalent to assigning to the tag itself:

>>> page.x._content = "Hello again"
>>> print page
<html><span id="x">Hello again</span></html>
>>> page.x = "Goodbye"
>>> print page
<html><span id="x">Goodbye</span></html>

The only time that you need to assign to _content is when you've taken a reference to an element within a document:

>>> x = page.x
>>> x._content = "I'm back"
>>> print page
<html><span id="x">I'm back</span></html>

Saying x = "I'm back" would simply re-bind x to the string "I'm back" without affecting the document.

Version and license

This is version 2.1.4 of PyMeld.py, Copyright (c) 2002-2009 Entrian Solutions. It is Open Source software released under the terms of the MIT License.