pml 1.21
simple, elegant HTML, XHTML and XML generation

Simple, elegant HTML, XHTML and XML generation.

Constructing your HTML
----------------------

To construct HTML start with an instance of ``html.HTML()``. Add
tags by accessing the tag's attribute on that object. For example:

>>> from html import HTML
>>> h = HTML()
>>> h.p('Hello, world!')
>>> print(h)
<p>Hello, world!</p>

You may supply a tag name and some text contents when creating a HTML
instance:

>>> h = HTML('html', 'text')
>>> print(h)
<html>text</html>

You may also append text content later using the tag's ``.text()`` method
or using augmented addition ``+=``. Any HTML-specific characters (``<>&"``)
in the text will be escaped for HTML safety as appropriate unless
``escape=False`` is passed. Each of the following examples uses a new
``HTML`` instance:

>>> p = h.p('hello world!\n')
>>> p.br
>>> p.text('more &rarr; text', escape=False)
>>> p += ' ... augmented'
>>> h.p
>>> print(h)
<p>hello, world!<br>more &rarr; text ... augmented</p>
<p>

Note also that the top-level ``HTML`` object adds newlines between tags by
default. Finally in the above you'll see an empty paragraph tag - tags with
no contents get no closing tag.

If the tag should have sub-tags you have two options. You may either add
the sub-tags directly on the tag:

>>> l = h.ol
>>> l.li('item 1')
>>> l.li.b('item 2 > 1')
>>> print(h)
<ol>
<li>item 1</li>
<li><b>item 2 &gt; 1</b></li>
</ol>

Note that the default behavior with lists (and tables) is to add newlines
between sub-tags to generate a nicer output. You can also see in that
example the chaining of tags in ``l.li.b``.

Tag attributes may be passed in as well:

>>> t = h.table(border='1')
>>> for i in range(2):
>>>   r = t.tr
>>>   r.td('column 1')
>>>   r.td('column 2')
>>> print(t)
<table border="1">
<tr><td>column 1</td><td>column 2</td></tr>
<tr><td>column 1</td><td>column 2</td></tr>
</table>

A variation on the above is to use a tag as a context variable. The
following is functionally identical to the first list construction but
with a slightly different sytax emphasising the HTML structure:

>>> with h.ol as l:
...   l.li('item 1')
...   l.li.b('item 2 > 1')

You may turn off/on adding newlines by passing ``newlines=False`` or
``True`` to the tag (or ``HTML`` instance) at creation time:

>>> l = h.ol(newlines=False)
>>> l.li('item 1')
>>> l.li('item 2')
>>> print(h)
<ol><li>item 1</li><li>item 2</li></ol>

Since we can't use ``class`` as a keyword, the library recognises ``klass``
as a substitute:

>>> print(h.p(content, klass="styled"))
<p class="styled">content</p>


Unicode
-------

``HTML`` will work with either regular strings **or** unicode strings, but
not **both at the same time**.

Obtain the final unicode string by calling ``unicode()`` on the ``HTML``
instance:

>>> h = HTML()
>>> h.p(u'Some Euro: €1.14')
>>> unicode(h)
u'<p>Some Euro: €1.14</p>'

If (under Python 2.x) you add non-unicode strings or attempt to get the
resultant HTML source through any means other than ``unicode()`` then you
will most likely get one of the following errors raised:

UnicodeDecodeError
   Probably means you've added non-unicode strings to your HTML.
UnicodeEncodeError
   Probably means you're trying to get the resultant HTML using ``print``
   or ``str()`` (or ``%s``).


How generation works
--------------------

The HTML document is generated when the ``HTML`` instance is "stringified".
This could be done either by invoking ``str()`` on it, or just printing it.
It may also be returned directly as the "iterable content" from a WSGI app
function.

You may also render any tag or sub-tag at any time by stringifying it.

Tags with no contents (either text or sub-tags) will have no closing tag.
There is no "special list" of tags that must always have closing tags, so
if you need to force a closing tag you'll need to provide some content,
even if it's just a single space character.

Rendering doesn't affect the HTML document's state, so you can add to or
otherwise manipulate the HTML after you've stringified it.


Creating XHTML
--------------

To construct XHTML start with an instance of ``html.XHTML()`` and use it
as you would an ``HTML`` instance. Empty elements will now be rendered
with the appropriate XHTML minimized tag syntax. For example:

>>> from html import XHTML
>>> h = XHTML()
>>> h.p
>>> h.br
>>> print(h)
<p></p>
<br />


Creating XML
------------

A slight tweak to the ``html.XHTML()`` implementation allows us to generate
arbitrary XML using ``html.XML()``:

>>> from html import XML
>>> h = XML('xml')
>>> h.p
>>> h.br('hi there')
>>> print(h)
<xml>
<p />
<br>hi there</br>
</xml>


Tags with difficult names
-------------------------

If your tag name isn't a valid Python identifier name, or if it's called
"text" or "raw_text" you can add your tag slightly more manually:

>>> from html import XML
>>> h = XML('xml')
>>> h += XML('some-tag', 'some text')
>>> h += XML('text', 'some text')
>>> print(h)
<xml>
<some-tag>some text</some-tag>
<text>some text</text>
</xml>


Version History (in Brief)
--------------------------

- 1.19 produce a universal wheel
- 1.17 repackage it as "pml" since "html" clashes with the
  homonymous py3 stdlib module
- 1.16 detect and raise a more useful error when some WSGI frameworks
  attempt to call HTML.read(). Also added ability to add new content using
  the += operator.
- 1.15 fix Python 3 compatibility (unit tests)
- 1.14 added plain XML support
- 1.13 allow adding (X)HTML instances (tags) as new document content
- 1.12 fix handling of XHTML empty tags when generating unicode
  output (thanks Carsten Eggers)
- 1.11 remove setuptools dependency
- 1.10 support plain ol' distutils again
- 1.9 added unicode support for Python 2.x
- 1.8 added Python 3 compatibility
- 1.7 added Python 2.5 compatibility and escape argument to tag
  construction
- 1.6 added .raw_text() and and WSGI compatibility
- 1.5 added XHTML support
- 1.3 added more documentation, more tests
- 1.2 added special-case klass / class attribute
- 1.1 added escaping control
- 1.0 was the initial release

----

This code is copyright 2009-2011 eKit.com Inc (http://www.ekit.com/)
See the end of the source file for the license of use.
XHTML support was contributed by Michael Haubenwallner.