<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>[xml] </title> <meta content="text/html;charset=ISO-8859-1" name="Content-Type"/> <link href="style.css" media="screen" rel="stylesheet" type="text/css"/></head> <body> <div><a href="http://codespeak.net"><img alt="py lib" height="114" id="pyimg" src="http://codespeak.net/img/pylib.png" width="154"/></a></div> <div id="metaspace"> <div class="project_title">[xml] </div> <div id="menubar"><a class="menu" href="index.html">index</a> <a class="menu" href="../../apigen/api/index.html">api</a> <a class="menu" href="../../apigen/source/index.html">source</a> <a class="menu" href="contact.html">contact</a> <a class="menu" href="download.html">download</a></div></div> <div id="contentspace"> <div id="docinfoline"> <div style="float: right; font-style: italic;"> </div></div> <div class="document" id="py-xml-lightweight-and-flexible-xml-html-generation"> <h1 class="title">py.xml: Lightweight and flexible xml/html generation</h1> <div class="contents topic" id="contents"> <p class="topic-title first">Contents</p> <ul class="auto-toc simple"> <li><a class="reference internal" href="#motivation" id="id1">1 Motivation</a></li> <li><a class="reference internal" href="#a-pythonic-object-model-please" id="id2">2 a pythonic object model , please</a><ul class="auto-toc"> <li><a class="reference internal" href="#generating-arbitrary-xml-structures" id="id3">2.1 generating arbitrary xml structures</a></li> <li><a class="reference internal" href="#basic-example-for-generating-html" id="id4">2.2 basic example for generating html</a></li> <li><a class="reference internal" href="#css-styling-your-html-tags" id="id5">2.3 CSS-styling your html Tags</a></li> <li><a class="reference internal" href="#more-to-come" id="id6">2.4 More to come ...</a></li> </ul> </li> </ul> </div> <div class="section" id="motivation"> <h1><a class="toc-backref" href="#id1">1 Motivation</a></h1> <p>There are a plethora of frameworks and libraries to generate xml and html trees. However, many of them are large, have a steep learning curve and are often hard to debug. Not to speak of the fact that they are frameworks to begin with.</p> <p>The py lib strives to offer enough functionality to represent itself and especially its API in html or xml.</p> </div> <div class="section" id="a-pythonic-object-model-please"> <h1><a class="toc-backref" href="#id2">2 a pythonic object model , please</a></h1> <p>The py lib offers a pythonic way to generate xml/html, based on ideas from <a class="reference external" href="http://www.livinglogic.de/Python/xist/index.html">xist</a> which <a class="reference external" href="http://www.livinglogic.de/Python/xist/Howto.html">uses python class objects</a> to build xml trees. However, <a class="reference external" href="http://www.livinglogic.de/Python/xist/index.html">xist</a>'s implementation is somewhat heavy because it has additional goals like transformations and supporting many namespaces. But its basic idea is very easy.</p> <div class="section" id="generating-arbitrary-xml-structures"> <h2><a class="toc-backref" href="#id3">2.1 generating arbitrary xml structures</a></h2> <p>With <tt class="docutils literal"><span class="pre">py.xml.Namespace</span></tt> you have the basis to generate custom xml-fragments on the fly:</p> <pre class="literal-block"> class ns(py.xml.Namespace): "my custom xml namespace" doc = ns.books( ns.book( ns.author("May Day"), ns.title("python for java programmers"),), ns.book( ns.author("why"), ns.title("Java for Python programmers"),), publisher="N.N", ) print doc.unicode(indent=2).encode('utf8') </pre> <p>will give you this representation:</p> <pre class="literal-block"> <books publisher="N.N"> <book> <author>May Day</author> <title>python for java programmers</title></book> <book> <author>why</author> <title>Java for Python programmers</title></book></books> </pre> <p>In a sentence: positional arguments are child-tags and keyword-arguments are attributes.</p> <p>On a side note, you'll see that the unicode-serializer supports a nice indentation style which keeps your generated html readable, basically through emulating python's white space significance by putting closing-tags rightmost and almost invisible at first glance :-)</p> </div> <div class="section" id="basic-example-for-generating-html"> <h2><a class="toc-backref" href="#id4">2.2 basic example for generating html</a></h2> <p>Consider this example:</p> <pre class="literal-block"> from py.xml import html # html namespace paras = "First Para", "Second para" doc = html.html( html.head( html.meta(name="Content-Type", value="text/html; charset=latin1")), html.body( [html.p(p) for p in paras])) print unicode(doc).encode('latin1') </pre> <p>Again, tags are objects which contain tags and have attributes. More exactly, Tags inherit from the list type and thus can be manipulated as list objects. They additionally support a default way to represent themselves as a serialized unicode object.</p> <p>If you happen to look at the py.xml implementation you'll note that the tag/namespace implementation consumes some 50 lines with another 50 lines for the unicode serialization code.</p> </div> <div class="section" id="css-styling-your-html-tags"> <h2><a class="toc-backref" href="#id5">2.3 CSS-styling your html Tags</a></h2> <p>One aspect where many of the huge python xml/html generation frameworks utterly fail is a clean and convenient integration of CSS styling. Often, developers are left alone with keeping CSS style definitions in sync with some style files represented as strings (often in a separate .css file). Not only is this hard to debug but the missing abstractions make it hard to modify the styling of your tags or to choose custom style representations (inline, html.head or external). Add the Browers usual tolerance of messyness and errors in Style references and welcome to hell, known as the domain of developing web applications :-)</p> <p>By contrast, consider this CSS styling example:</p> <pre class="literal-block"> class my(html): "my initial custom style" class body(html.body): style = html.Style(font_size = "120%") class h2(html.h2): style = html.Style(background = "grey") class p(html.p): style = html.Style(font_weight="bold") doc = my.html( my.head(), my.body( my.h2("hello world"), my.p("bold as bold can") ) ) print doc.unicode(indent=2) </pre> <p>This will give you a small'n mean self contained represenation by default:</p> <pre class="literal-block"> <html> <head/> <body style="font-size: 120%"> <h2 style="background: grey">hello world</h2> <p style="font-weight: bold">bold as bold can</p></body></html> </pre> <p>Most importantly, note that the inline-styling is just an implementation detail of the unicode serialization code. You can easily modify the serialization to put your styling into the <tt class="docutils literal"><span class="pre">html.head</span></tt> or in a separate file and autogenerate CSS-class names or ids.</p> <p>Hey, you could even write tests that you are using correct styles suitable for specific browser requirements. Did i mention that the ability to easily write tests for your generated html and its serialization could help to develop _stable_ user interfaces?</p> </div> <div class="section" id="more-to-come"> <h2><a class="toc-backref" href="#id6">2.4 More to come ...</a></h2> <p>For now, i don't think we should strive to offer much more than the above. However, it is probably not hard to offer <em>partial serialization</em> to allow generating maybe hundreds of complex html documents per second. Basically we would allow putting callables both as Tag content and as values of attributes. A slightly more advanced Serialization would then produce a list of unicode objects intermingled with callables. At HTTP-Request time the callables would get called to complete the probably request-specific serialization of your Tags. Hum, it's probably harder to explain this than to actually code it :-)</p> </div> </div> </div> </div></body></html>