Migrating from Genshi

Warning

This document is mostly obsolete. Use at your own risk!

Kajiki uses syntax derived from the syntax of Genshi. In particular, the following directives are supported, with semantics intended to be nearly identical to those of Genshi.

  • py:def
  • py:when
  • py:otherwise
  • py:for
  • py:if
  • py:choose
  • py:with
  • py:replace
  • py:content
  • py:attrs
  • py:strip
  • xi:include

Note that, in particular, py:match is not supported. In addition, Kajiki supports the following additional directives:

  • py:include - same semantics as xi:include, use if you don’t like lots of namespaces in your xml
  • py:extends - indicates that this is an extension template. The parent template will be read in and used for layout, with any py:slot directives in the child template overriding the py:slot directives defined in the parent.
  • py:slot - used to name a replaceable ‘slot’ in a parent template, or to specify a slot override in a child template. The py:slot semantics are modeled after the {% block %} semantics of Jinja2.
  • py:super - used to insert the contents of a parent py:slot, modeled after {% super %} in Jinja2.

Generally, migration consists of a few steps that can be simple or quite difficult based on your fondness of the py:match directive in Genshi. In simple cases where you have one master.html template with a few py:match directives that is xi:included into all your page templates, the following steps should suffice:

  • You may need to rewrite some of our xi:include directives to use Kajiki’s module naming system and relative imports.
  • In a simple case where you have only a few py:match directives, all of which are in a master.html template that is being included from child templates, I recommend that you rewrite the master.html as layout.html, defining named py:slot regions that will be overridden in child templates.
  • In your child templates, remove the <xi:include href=”master.html”> that probably lurks near the top. Then add a py:extends directive to the top-level tag (usually <html>). The tag the parts of the child template that are intended to override parts of the parent template with the py:slot directive.

Example Migration

Suppose you have a couple of Genshi templates, one of which called master.html and one of which is index.html. (TurboGears developers may recognize these files as slightly modified versions of the default templates deposited in a TG quickstarted project.) The contents of master.html are:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!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:py="http://genshi.edgewall.org/"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      py:strip="">
    <xi:include href="header.html" />
    <xi:include href="sidebars.html" />
    <xi:include href="footer.html" />
<head py:match="head" py:attrs="select('@*')">
    <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
    <title py:replace="''">Your title goes here</title>
    <meta py:replace="select('*')"/>
    <link rel="stylesheet" type="text/css" media="screen" href="${tg.url('/css/style.css')}" />
    <link rel="stylesheet" type="text/css" media="screen" href="${tg.url('/css/admin.css')}" />
</head>

<body py:match="body" py:attrs="select('@*')">
  ${header()}
  <ul id="mainmenu">
    <li class="first"><a href="${tg.url('/')}" class="${('', 'active')[defined('page') and page=='index']}">Welcome</a></li>
        <li><a href="${tg.url('/about')}" class="${('', 'active')[defined('page') and page=='about']}">About</a></li>
        <li py:if="tg.auth_stack_enabled"><a href="${tg.url('/auth')}" class="${('', 'active')[defined('page') and page=='auth']}">Authentication</a></li>
        <li><a href="${tg.url('/environ')}" class="${('', 'active')[defined('page') and page=='environ']}">WSGI Environment</a></li>
        <li><a href="http://groups.google.com/group/turbogears">Contact</a></li>
    <span py:if="tg.auth_stack_enabled" py:strip="True">
        <li py:if="not request.identity" id="login" class="loginlogout"><a href="${tg.url('/login')}">Login</a></li>
        <li py:if="request.identity" id="login" class="loginlogout"><a href="${tg.url('/logout_handler')}">Logout</a></li>
        <li py:if="request.identity" id="admin" class="loginlogout"><a href="${tg.url('/admin')}">Admin</a></li>
    </span>
  </ul>
  <div id="content">
    <py:if test="defined('page')">
    <div class="currentpage">
     Now Viewing: <span py:replace="page"/>
     </div>
    </py:if>
    <py:with vars="flash=tg.flash_obj.render('flash', use_js=False)">
        <div py:if="flash" py:content="XML(flash)" />
    </py:with>
    <div py:replace="select('*|text()')"/>
    <!-- End of main_content -->
    ${footer()}
  </div>
</body>
</html>

Likewise, the contents of index.html are as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!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:py="http://genshi.edgewall.org/"
      xmlns:xi="http://www.w3.org/2001/XInclude">

  <xi:include href="master.html" />

<head>
  <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
  <title>Welcome to TurboGears 2.0, standing on the 
  shoulders of giants, since 2007</title>
</head>

<body>
    ${sidebar_top()}
  <div id="getting_started">
    <h2>Presentation</h2>
    <p>TurboGears 2 is rapid web application development toolkit designed to make your life easier.</p>
    <ol id="getting_started_steps">
      <li class="getting_started">
        <h3>Code your data model</h3>
        <p> Design your data model, Create the database, and Add some bootstrap data.</p>
      </li>
      <li class="getting_started">
        <h3>Design your URL architecture</h3>
        <p> Decide your URLs, Program your controller methods, Design your 
            templates, and place some static files (CSS and/or JavaScript). </p>
      </li>
      <li class="getting_started">
        <h3>Distribute your app</h3>
        <p> Test your source, Generate project documents, Build a distribution.</p>
      </li>
    </ol>
  </div>
  <div class="clearingdiv" />
  <div class="notice"> Thank you for choosing TurboGears. 
  </div>
</body>
</html>

In order to perform our kajiki migration, we begin by creating two empty templates. The first one will replace our master.html, and we will call it layout.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!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:py="http://genshi.edgewall.org/"
      xmlns:xi="http://www.w3.org/2001/XInclude">
    <xi:include href="header" />
    <xi:include href="footer" />

    <head>
      <title py:slot="title">Your title goes here</title>
      <py:slot name="head_content">
        <link rel="stylesheet" type="text/css" media="screen" href="${tg.url('/css/style.css')}" />
        <link rel="stylesheet" type="text/css" media="screen" href="${tg.url('/css/admin.css')}" />
      </py:slot>
    </head>

    <body>
      <py:slot name="body_header"><h1>My Header</h1></py:slot>
      <ul py:slot="mainmenu" id="mainmenu">
        <li class="first"><a href="${tg.url('/')}" class="${('', 'active')[defined('page') and page=='index']}">Welcome</a></li>
        <li><a href="${tg.url('/about')}" class="${('', 'active')[defined('page') and page=='about']}">About</a></li>
        <li py:if="tg.auth_stack_enabled"><a href="${tg.url('/auth')}" class="${('', 'active')[defined('page') and page=='auth']}">Authentication</a></li>
        <li><a href="${tg.url('/environ')}" class="${('', 'active')[defined('page') and page=='environ']}">WSGI Environment</a></li>
        <li><a href="http://groups.google.com/group/turbogears">Contact</a></li>
      </ul>
      <div id="content">
        <py:if test="defined('page')">
          <div class="currentpage">
            Now Viewing: <span py:replace="page"/>
          </div>
        </py:if>
        <py:with vars="flash=tg.flash_obj.render('flash', use_js=False)">
          <div py:if="flash" py:content="XML(flash)" />
        </py:with>
        <py:slot name="body_text">Your body text goes here</py:slot>
        <py:slot name="bodyfooter">${footer()}</py:slot>
      </div>
    </body>
</html>

Note the introduction of the py:slot directive, and the disappearance of the py:match directives from master.html. py:slot mimics the behavior of Jinja2 “blocks”, providing a name to a construct in a parent template which can be replaced by the contents of py:slot -named constructs in child templates. For instance, the “title” slot in layout.html:

1
      <title py:slot="title">Your title goes here</title>

can be replaced by a similarly-named slot in the child document index_kajiki.html:

1
2
3
4
5
6
7
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:py="http://genshi.edgewall.org/"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      py:extends="layout">
    <title py:slot="title">Welcome to TurboGears 2.0, standing on the 
      shoulders of giants, since 2007</title>

We also provide a way of including the contents of the parent template’s slot in a child template’s slot using <py:super/>. The following slot in layout.html:

1
      <py:slot name="body_header"><h1>My Header</h1></py:slot>

can be replaced in include/index_kajiki.html with:

1
2
3
4
    <py:slot name="body_header">
      <py:super/>
      <h1>Some extra header data</h1>
    </py:slot>

Yielding the following html once rendered:

1
2
 <h1>My Header</h1>
 <h1>Some extra header data</h1>

Table Of Contents

Previous topic

Kajiki Text Templates

Next topic

Internationalization

This Page