Presentation tier
=================

This document describes how to generate HTML and XML dialects with the service
offered by the framework.

The document :wiki:`ComponentModel` explains how to associate HTML or XML views
to the components.

Principles
----------

With Nagare, to generate a HTML text, you always build a tree of objects in
memory, a Document Objects Model (not the DOM version of the W3C), that you
can serialize in a (X)HTML text.

One of the benefic effect of this serialization is that the generated HTML or
XHTML is always valid.

The framework offers to you three ways to generate the DOM:

  1. functional
  2. imperative
  3. templating

It's important to note that these three methods all generate a DOM and so can
be freely mixed to build an aggregating DOM.

DOM objects creation
--------------------

A ``Renderer`` is a DOM objects factory. For example, the XHTML renderer
:apidoc:`nagare.namespaces.xhtml#xhtml.Renderer` has an attribute, for
each XHTML tag, that create a DOM object:

.. code-block:: pycon

    >>> from nagare.namespaces import xhtml
    >>> h = xhtml.Renderer()
    >>> h.div
    <Element div at 8410b6c>

DOM objects API
---------------

ElementTree API
~~~~~~~~~~~~~~~

A DOM object is an instance of the class ``_Tag`` from
:apidoc:`nagare.namespaces.xml#xml._Tag`. As this class inherits from
``lxml.etree.ElementBase``, the DOM objects offer an
`ElementTree API. <http://effbot.org/zone/pythondoc-elementtree-ElementTree.htm#elementtree.ElementTree._ElementInterface-class>`_:

.. code-block:: pycon

    >>> from nagare.namespaces import xhtml
    >>> h = xhtml.Renderer()
    
    >>> root = h.div  
    >>> root.set('id', 'content')
    
    >>> title = h.h1    
    >>> title.text = 'Hello world'
    
    >>> root.append(title)
    >>> root.write_htmlstring()
    '<div id="content"><h1>Hello world</h1></div>'

Lxml API
~~~~~~~~

You can also `validate <http://codespeak.net/lxml/validation.html>`_ a DOM tree
against a DTD, XML Schema, RelaxNG or Schematron document.

And you can use `XPath and Xsl transformations <http://codespeak.net/lxml/xpathxslt.html>`_.

Functional DOM building API
~~~~~~~~~~~~~~~~~~~~~~~~~~~

The ``_Tag`` class implements a ``__call__``  method to add children, text or
attributes to a DOM object: 

  .. code-block:: python
  
     def __call__(self, *children, **attributes)

Each element in ``children`` can be a:

  - DOM object that is added as a child of the DOM object
  - string, unicode string, integer or float that is converted to unicode
    string and added as data to the DOM object
  - list, tuple or generator which each elements are added to the DOM object
  - dictionary which each items are added as attributes of the DOM object
  
Each items in ``attributes`` are added as attributes of the DOM object.

.. note::

   As a keyword parameter cannot have the name of a Python reserved keyword,
   add a ``_`` character to the name (i.e: ``h.div(class_='content')``)

Using the DOM object creation API of the renderers, with the nesting of
calls to the created DOM objects, a DOM tree can be built in a functional way:

  .. code-block:: python
  
     >>> from nagare.namespaces import xhtml
     >>> h = xhtml.Renderer()

     >>> root = h.div(h.h1('Hello world'), id='content')
     >>> root.write_htmlstring()
     <div id="content"><h1>Hello world</h1></div>'

Imperative DOM building API
~~~~~~~~~~~~~~~~~~~~~~~~~~~

A DOM object is also a `context manager <http://docs.python.org/lib/typecontextmanager.html>`_

Once a context is opened using the ``with`` statement, children can be added
to the context manager using the ``<<`` operator on the renderer.

So a DOM tree can be imperatively built from the nesting of contexts. With is root
finally retrieved from the attribute ``root`` of the Renderer:

.. code-block:: python

   >>> from __future__ import with_statement
  
   >>> from nagare.namespaces import xhtml
   >>> h = xhtml.Renderer()

   >>> with h.div:
   ...     h << { 'id' : 'content' }
   ...     with h.h1:
   ...         h << 'Hello world'
  
   >>> root = h.root
   >>> root.write_htmlstring()
   '<div id="content"><h1>Hello world</h1></div>'

.. note::

  Dont't forget the line ``from __future__ import with_statement`` at the
  beginning of the file to activate the ``with`` statement in Python 2.5.
  
  In a component view, don't forget to return the tree with ``h.root``

Remember that the different ways to build a DOM tree can be freely mixed,
so the example above can be rewrote as:

.. code-block:: python

   >>> from __future__ import with_statement
   
   >>> from nagare.namespaces import xhtml
   >>> h = xhtml.Renderer()

   >>> with h.div(id='content'):
   ...     h << h.h1('Hello world')
   
   >>> root = h.root
   >>> root.write_htmlstring()
   '<div id="content"><h1>Hello world</h1></div>'


Or, creating a HTML list from the Python list ``l``:

.. code-block:: python

   # Functional
   >>> root = h.ul([u.li(element) for element in l])
   
   # Imperative
   >>> with h.ul:
   ...     for element in l:
   ...         h << h.ul(element)
   >>> root = h.root

Template
~~~~~~~~

The templating system in Nagare follows the idea of the
`meld family <http://plope.com/software/meld3/>`_: the
designer who creates the XHTML template only gives identifiers to nodes.
Then the developer can parse the template into a DOM tree, search for the DOM
objects given their identifiers and manipulates them in Python.

1. Creating the template
++++++++++++++++++++++++

The template must be a valid XML document, for example a XHTML template and
the namespace ``http://www.plope.com/software/meld3`` must be declared.

To mark the nodes, use the attribute ``id`` of this namespace:

.. code-block:: html

   <?xml version="1.0" encoding="UTF-8"?>
   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   <html xmlns="http://www.w3.org/1999/xhtml"
         xmlns:meld="http://www.plope.com/software/meld3">
       <body>
           <h1 meld:id="title">Hello</h1>
       </body>
   </html>

The helper method ``meld_id()`` is available to add, in Python, a ``meld:id``
attribute to a DOM object:

.. code-block:: pycon

   >>> from nagare.namespaces import xhtml
   >>> h = xhtml.Renderer()
   
   >>> tree = h.html(
   ...            h.body(
   ...                h.h1("Hello").meld_id("title")
   ...            )
   ...        )
   >>> print tree.write_xmlstring(pretty_print=True)
   <html>
     <body>
       <h1 xmlns:ns0="http://www.plope.com/software/meld3" ns0:id="title">Hello</h1>
     </body>
   </html>

2. Parsing the template
+++++++++++++++++++++++

You can use the ``parse_htmlstring()`` method of a xhtml renderer to parse a
template:

.. code-block:: pycon

   >>> from nagare.namespaces import xhtml
   >>> h = xhtml.Renderer()
   
   >>> root = h.parse_html('/tmp/template.xml', xhtml=True)
   
   >>> print root.write_xmlstring()
   <html xmlns="http://www.w3.org/1999/xhtml" xmlns:meld="http://www.plope.com/software/meld3">
       <body>
           <h1 meld:id="title">Hello</h1>
       </body>
   </html>

3. Finding the DOM objects
++++++++++++++++++++++++++

Use the ``findmeld()`` method of the DOM objects to retreive the marked nodes:

.. code-block:: pycon

   >>> from nagare.namespaces import xhtml
   >>> h = xhtml.Renderer()
   
   >>> root = h.parse_html('/tmp/template.xml', xhtml=True)
   
   >>> root.findmeld('title')
   <Element {http://www.w3.org/1999/xhtml}h1 at 8410c5c>

4. Manipulating the DOM objects
+++++++++++++++++++++++++++++++

Once a DOM object is found, you can manipulate it with the normal ElementTree,
Lxml, functional or imperative API:
 
.. code-block:: pycon

   >>> from nagare.namespaces import xhtml
   >>> h = xhtml.Renderer()
   
   >>> root = h.parse_html('/tmp/template.xml', xhtml=True)
   
   >>> t = root.findmeld('title')
   >>> t.text = 'World'

   >>> print root.write_xmlstring()
   <html xmlns="http://www.w3.org/1999/xhtml" xmlns:meld="http://www.plope.com/software/meld3">
       <body>
           <h1 meld:id="title">World</h1>
       </body>
   </html>


These three methods of the DOM objects are helpers to work with templates:

  - ``fill(self, *children, **attributes)`` -- replaces the children of the
    DOM object by the given children and appends the ``attributes`` to the DOM
    object current attributes.

    .. code-block:: python
      
       >>> from nagare.namespaces import xhtml
       >>> h = xhtml.Renderer()
    
       >>> root = h.div(h.h1('Hello world'), id='content')
       >>> root.write_htmlstring()
       <div id="content"><h1>Hello world</h1></div>'      
       
       >>> root.fill("Go to ", h.a("Nagare home", href="http://www.nagare.org"), class_="description")
       
       >>> root.write_htmlstring()
        '<div id="content" class="description">Go to <a href="http://www.nagare.org">Nagare home</a></div>'
    
  - ``replace(self, *children)`` -- replace the DOM object by the given children:

    .. code-block:: python
      
       >>> from nagare.namespaces import xhtml
       >>> h = xhtml.Renderer()
    
       >>> root = h.div(h.h1('Hello world'), id='content')
       >>> root.write_htmlstring()
       <div id="content"><h1>Hello world</h1></div>'
       >>> root[0].write_htmlstring()
       <h1>Hello world</h1>    
       
       >>> root[0].replace(h.h2('Nagare'))
       
       >>> root.write_htmlstring()
       '<div id="content"><h2>Nagare</h2></div>'
  
  - ``repeat(self, iterable, childname=None)`` -- (description taken from
    the `meld3 <http://plope.com/software/meld3/>`_ site)
    
      Repeats an element with values from an iterable.
    
      If ``childname`` is not ``None``, repeat the element on which repeat was called,
      otherwise find the child element with a ``meld:id`` matching ``childname``
      and repeat that.  The element is repeated within its parent element.
    
      This method returns an iterable; the value of each iteration is a
      two-sequence in the form (newelement, data).  ``newelement`` is a clone of
      the template element (including clones of its children) which has already
      been seated in its parent element in the template. ``data`` is a value from
      the passed in iterable.  Changing ``newelement`` (typically based on values
      from ``data``) mutates the element "in place". 

    .. code-block:: pycon
    
        >>> from nagare.namespaces import xhtml
        >>> h = xhtml.Renderer()
        
        >>> root = h.parse_xmlstring('''<ul xmlns:meld="http://www.plope.com/software/meld3">
        ...   <li meld:id="alist" align="center">A line example</li>
        ... </ul>''')
    
        >>> items = ['Item %d' % i for i in range(3)]
    
        >>> for (element, item) in root.findmeld('alist').repeat(items):
        ...     element.text = item
        ...
    
        >>> print root.write_xmlstring()
        <ul xmlns:meld="http://www.plope.com/software/meld3">
        <li align="center">Item 0</li>
        <li align="center">Item 1</li>
        <li align="center">Item 2</li>
        </ul>

DOM tree serialization
~~~~~~~~~~~~~~~~~~~~~~

Once a tree of DOM object is build, it can be serialized in (X)HTML:

  - ``write_xmlstring(self, encoding='utf-8', pipeline=True)`` -- serializes
    the DOM tree into a XML string, encoded according to the ``encoding``
    parameter. If ``pipeline`` is True, the eventual ``meld:id`` attributes are
    removed, else they are kept so that the xml string can be re-parse as a
    template.
    
  - ``write_htmlstring(self, encoding='utf-8', pipeline=True)`` -- serializes
    the DOM tree into a HTML string, encoded according to the ``encoding``
    parameter. If ``pipeline`` is True, the eventual ``meld:id`` attributes are
    removed.

.. wikiname: PresentationTier
