Template Annotations

TDI strictly keeps the template and the rendering logic apart. That way you can write your, say, HTML template in HTML and your logic in a real language – python in this case. There is no template language in-between. You just need to label the locations in the template which should be modified later.

For TDI this looks like the following:

<html>
<body>
    <h1 tdi="doctitle">doc title goes here</h1>
    <p tdi="intro">Intro goes here.</p>
</body>
</html>

When you pass that to TDI, it will be parsed into a document tree essentially containing the two nodes (doctitle and intro). Everything in between is passed through literally (except when your template logic changes it, of course). The tree is stuffed into a template object which you can handle in python. For example:

from tdi import html
template = html.from_string("""
<html>
<body>
    <h1 tdi="doctitle">doc title goes here</h1>
    <p tdi="intro">Intro goes here.</p>
</body>
</html>
""")
template.render()

template.render() streams the result to sys.stdout by default. So the output of this snippet would be:

<html>
<body>
    <h1>doc title goes here</h1>
    <p>Intro goes here.</p>
</body>
</html>

We have no render logic specified, so the only difference to the original template is, that the annotations (tdi=...) are gone.

Annotation Syntax

All annotations recognized by TDI follow the same pattern. They are defined as markup attribute and consist of a name optionally prepended by flags. Names are limited to the usual US-ASCII word alphabet (a-z, A-Z, 0-9, _) and must start with a letter. Flags are represented by single “special” characters, which are not member of the name alphabet (like - or *).

The following annotation attributes are recognized (and removed automatically) by the parser:

Attribute / Description Flag Description
tdi="[flags]name"
Main attribute for labeling modifiable nodes - Hide the markup
+ Show the markup
: Separator node
* Silent node
tdi:overlay="[flags]name"
Mark overlay source or target - Hide the markup
+ Show the markup
< Source overlay
> Target overlay
tdi:scope="[flags]name"
Enter a logical scope. Empty names and dotted names allowed - Hide the markup
+ Show the markup
= Absolute scope

Note that the + and - flags are mutually exclusive per attribute. If they are mixed across attributes of the same node, - takes precedence. You only need to set them, if the desired flag differs from the template parser/builder default. For example, TDI‘s HTML template factory defaults to +.

Mock-Up Content

When editing or presenting the template it’s often useful to fake parts that are actually generated later. That’s called mock-up content. TDI provides a special annotation for this very purpose:

from tdi import html
template = html.from_string("""
<ul>
<li tdi="item">1st</li>
<li tdi="-">2nd</li>
<li tdi="-">3rd</li>
</ul>
""")
template.render()

All nodes annotated with tdi="-" are handled as mock-up content and simply stripped by the template builder. Here’s the output of the snippet above:

<ul>
<li>1st</li>


</ul>

Note that the builder strips the mock-up nodes (not the renderer). Consequently once the template object is ready, there is no performance penalty at all.

Character Encoding

The → encoding property of the template object contains information about what TDI knows about the template encoding. This information is used by TDI itself to encode supplied content properly (and for consistency checks when combining templates, but more about that elsewhere).

You can use that information for example, for setting the proper HTTP or MIME headers.

The html template factory is configured to look out for two encoding indicators within the template:

  • An XML prolog
  • An applicable <meta> element

If it contains more than one encoding hint, the last one wins. If it doesn’t contain any hint, US-ASCII is assumed as the most safe fallback. The following code shows examples:

from tdi import html

# xml prolog
template = html.from_string(
    """<?xml version="1.0" encoding="latin-1"?>..."""
)
print template.encoding

# meta
template = html.from_string(
    """<html>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    </html>"""
)
print template.encoding

# meta HTML5
template = html.from_string(
    """<html>
        <meta charset="windows-1252">
    </html>"""
)
print template.encoding

# xml prolog + meta
template = html.from_string(
    """<?xml version="1.0" encoding="latin-1"?>
       <meta charset=utf-8>
    """
)
print template.encoding

# none
template = html.from_string("<html>...</html>")
print template.encoding

The script produces the following output:

latin-1
utf-8
windows-1252
utf-8
ascii