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.