HTML helpers

Consider the following code in a view:

  1. {{=DIV('this', 'is', 'a', 'test', _id='123', _class='myclass')}}

it is rendered as:

  1. <div id="123" class="myclass">thisisatest</div>

DIV is a helper class, i.e., something that can be used to build HTML programmatically. It corresponds to the HTML <div> tag.

Positional arguments are interpreted as objects contained between the open and close tags. Named arguments that start with an underscore are interpreted as HTML tag attributes (without the underscore). Some helpers also have named arguments that do not start with underscore; these arguments are tag-specific.

Instead of a set of unnamed arguments, a helper can also take a single list or tuple as its set of components using the * notation and it can take a single dictionary as its set of attributes using the **, for example:

  1. {{
  2. contents = ['this', 'is', 'a', 'test']
  3. attributes = {'_id':'123', '_class':'myclass'}
  4. =DIV(*contents, **attributes)
  5. }}

(produces the same output as before).

The following set of helpers:

A, ASSIGNJS, B, BEAUTIFY, BODY, BR, CAT, CENTER, CODE, COL, COLGROUP, DIV, EM, EMBED, FIELDSET, FORM, H1, H2, H3, H4, H5, H6, HEAD, HR, HTML, I, IFRAME, IMG, INPUT, LABEL, LEGEND, LI, LINK, MARKMIN, MENU, META, OBJECT, ON, OL, OPTGROUP, OPTION, P, PRE, SCRIPT, SELECT, SPAN, STYLE, TABLE, TAG, TBODY, TD, TEXTAREA, TFOOT, TH, THEAD, TITLE, TR, TT, UL, URL, XHTML, XML, embed64, xmlescape

can be used to build complex expressions that can then be serialized to XML[xml-w] [xml-o]. For example:

  1. {{=DIV(B(I("hello ", "<world>")), _class="myclass")}}

is rendered:

  1. <div class="myclass"><b><i>hello &lt;world&gt;</i></b></div>

Helpers can also be serialized into strings, equivalently, with the __str__ and the xml methods:

  1. >>> print str(DIV("hello world"))
  2. <div>hello world</div>
  3. >>> print DIV("hello world").xml()
  4. <div>hello world</div>

The helpers mechanism in web2py is more than a system to generate HTML without concatenating strings. It provides a server-side representation of the Document Object Model (DOM).

Components of helpers can be referenced via their position, and helpers act as lists with respect to their components:

  1. >>> a = DIV(SPAN('a', 'b'), 'c')
  2. >>> print a
  3. <div><span>ab</span>c</div>
  4. >>> del a[1]
  5. >>> a.append(B('x'))
  6. >>> a[0][0] = 'y'
  7. >>> print a
  8. <div><span>yb</span><b>x</b></div>

Attributes of helpers can be referenced by name, and helpers act as dictionaries with respect to their attributes:

  1. >>> a = DIV(SPAN('a', 'b'), 'c')
  2. >>> a['_class'] = 's'
  3. >>> a[0]['_class'] = 't'
  4. >>> print a
  5. <div class="s"><span class="t">ab</span>c</div>

Note, the complete set of components can be accessed via a list called a.components, and the complete set of attributes can be accessed via a dictionary called a.attributes. So, a[i] is equivalent to a.components[i] when i is an integer, and a[s] is equivalent to a.attributes[s] when s is a string.

Notice that helper attributes are passed as keyword arguments to the helper. In some cases, however, attribute names include special characters that are not allowed in Python identifiers (e.g., hyphens) and therefore cannot be used as keyword argument names. For example:

  1. DIV('text', _data-role='collapsible')

will not work because “_data-role” includes a hyphen, which will produce a Python syntax error.

In such cases you have a couple of options. You can use the data argument (this time without a leading underscore) to pass a dictionary of related attributes without their leading hyphen, and the output will have the desired combinations e.g.

  1. >>> print DIV('text', data={'role': 'collapsible'})
  2. <div data-role="collapsible">text</div>

or you can instead pass the attributes as a dictionary and make use of Python’s ** function arguments notation, which maps a dictionary of (key:value) pairs into a set of keyword arguments:

  1. >>> print DIV('text', **{'_data-role': 'collapsible'})
  2. <div data-role="collapsible">text</div>

Note that more elaborate entries will introduce HTML character entities, but they will work nonetheless e.g.

  1. >>> print DIV('text', data={'options':'{"mode":"calbox", "useNewStyle":true}'})
  2. <div data-options="{&quot;mode&quot;:&quot;calbox&quot;, &quot;useNewStyle&quot;:true}">text</div>

You can also dynamically create special TAGs:

  1. >>> print TAG['soap:Body']('whatever', **{'_xmlns:m':'http://www.example.org'})
  2. <soap:Body xmlns:m="http://www.example.org">whatever</soap:Body>

XML

XML is an object used to encapsulate text that should not be escaped. The text may or may not contain valid XML. For example, it could contain JavaScript.

The text in this example is escaped:

  1. >>> print DIV("<b>hello</b>")
  2. <div>&lt;b&gt;hello&lt;/b&gt;</div>

by using XML you can prevent escaping:

  1. >>> print DIV(XML("<b>hello</b>"))
  2. <div><b>hello</b></div>

Sometimes you want to render HTML stored in a variable, but the HTML may contain unsafe tags such as scripts:

  1. >>> print XML('<script>alert("unsafe!")</script>')
  2. <script>alert("unsafe!")</script>

Un-escaped executable input such as this (for example, entered in the body of a comment in a blog) is unsafe, because it can be used to generate Cross Site Scripting (XSS) attacks against other visitors to the page.

The web2py XML helper can sanitize our text to prevent injections and escape all tags except those that you explicitly allow. Here is an example:

  1. >>> print XML('<script>alert("unsafe!")</script>', sanitize=True)
  2. &lt;script&gt;alert(&quot;unsafe!&quot;)&lt;/script&gt;

The XML constructors, by default, consider the content of some tags and some of their attributes safe. You can override the defaults using the optional permitted_tags and allowed_attributes arguments. Here are the default values of the optional arguments of the XML helper.

  1. XML(text, sanitize=False,
  2. permitted_tags=['a', 'b', 'blockquote', 'br/', 'i', 'li',
  3. 'ol', 'ul', 'p', 'cite', 'code', 'pre', 'img/'],
  4. allowed_attributes={'a':['href', 'title'],
  5. 'img':['src', 'alt'], 'blockquote':['type']})