TurboGears - Genshi 模板语言


Genshi 是一种基于 XML 的模板语言。它类似于Kid,它曾经是 TurboGears 早期版本的模板引擎。Genshi 和 Kid 的灵感来自其他著名的模板语言,如HSLT、TALPHP

Genshi 模板由处理指令组成。这些指令是模板中的元素和属性。Genshi 指令在命名空间http://genshi.edgewall.org/中定义。因此,这个命名空间需要在模板的根元素中声明。

<html xmlns = "http://www.w3.org/1999/xhtml"
   xmlns:py = "http://genshi.edgewall.org/"
   lang = "en">
...
</html>

上面的声明意味着默认命名空间设置为 XHTML,并且 Genshi 指令具有“py”前缀。

原氏指令

Genshi 中定义了许多指令。以下列表列举了 Genshi 指令 -

  • py:如果
  • py:选择
  • py:对于
  • py:定义
  • py:匹配
  • py:与
  • py:替换
  • py:内容
  • py:属性
  • py:条带

条件部分

Genshi 提供了两个用于条件渲染内容的指令 - py:if 和 py:choose。

py:如果

仅当if 子句中的表达式计算结果为 true 时,才会呈现该指令元素的内容。假设模板上下文中的数据是{'foo':True, 'bar':'Hello'},以下指令 -

<div>
   <b py:if = "foo">${bar}</b>
</div>

将导致

Hello

但是,如果'foo' 设置为 False ,则不会呈现此输出。

该指令也可以用作元素。在这种情况下<py:if>必须由相应的</py:if>关闭

<div>
   <py:if test = "foo">
      <b>${bar}</b>
   </py:if>
</div>

py:选择

通过将py:choosepy:whenpy:otherwise指令结合使用,可以实现高级条件处理。这个特性类似于C/C++中的switch-case构造。

使用py:choose指令中的不同值来检查表达式:何时将呈现替代项和相应的内容。可以以py:otherwise指令的形式提供默认替代方案。

<div py:choose = "foo”>
   <span py:when = "0">0</span>
   <span py:when = "1">1</span>
   <span py:otherwise = "">2</span>
</div>

以下示例说明了py:choosepy:when指令的使用。HTML 表单将数据发布到 /marks URL。marks ()函数将标记和结果以字典对象的形式重定向到total.html模板。结果通过/失败的条件显示是通过使用py:choosepy:when指令实现的。

输入标记的 HTML 脚本 ( marks.html ) 如下 -

<html>
   <body>
      <form action = "http://localhost:8080/marks" method = "post">
         <p>Marks in Physics:</p>
         <p><input type = "text" name = "phy" /></p>
         <p>Marks in Maths:</p>
         <p><input type = "text" name = "maths" /></p>
         <p><input type = "submit" value = "submit" /></p>
      </form>
   </body>
</html>

root.py的完整代码如下。marks ()控制器将标记和结果发送到total.html模板 -

from hello.lib.base import BaseController
from tg import expose, request

class RootController(BaseController):
   @expose("hello.templates.marks")
      def marksform(self):
      return {}
		
   @expose("hello.templates.total")
      def marks(self, **kw):
      phy = kw['phy']
      maths = kw['maths']
      ttl = int(phy)+int(maths)
      avg = ttl/2
		
      if avg ≥ 50:
         mydata = {'phy':phy, 'maths':maths, 'total':ttl, 'result':2}
      else:
         mydata = {'phy':phy, 'maths':maths, 'total':ttl,'result':1}
	
      return mydata

templates 文件夹中的total.html接收字典数据并有条件地在html 输出中解析它如下所示 -

<html xmlns = "http://www.w3.org/1999/xhtml"
   xmlns:py = "http://genshi.edgewall.org/"
   lang = "en">
	
   <head>
      <title>TurboGears Templating Example</title>
   </head>
	
   <body>
      <h2>Hello, Welcome to TurboGears!.</h2>
      <h3>Marks in Physics: ${phy}.</h3>
      <h3>Marks in Maths: ${maths}.</h3>
      <h3>Total Marks: ${total}</h3>
		
      <div py:choose = "result">
         <span py:when = "1"><h2>Result: Fail</h2></span>
         <span py:when = "2"><h2>Result: Pass</h2></span>
      </div>
		
   </body>
</html>

启动服务器(如果尚未运行)

Gearbox server –reload –debug

在浏览器中输入http://localhost::8080/marksform -

结果窗口

Total.html将呈现以下输出-

总HTML

py:对于

py:for 指令中的元素对于可迭代对象(通常是 Python List 对象)中的每个项目重复。如果items = [1,2,3]存在于模板上下文中,则可以通过以下 py:for 指令对其进行迭代 -

<ul>
   <li py:for = "item in items">${item}</li>
</ul>

将呈现以下输出 -

1
2
3

以下示例显示使用 py:for 指令在 Total.html 模板中呈现的 HTML 表单数据,也可以按如下方式使用 -

<py:for each = "item in items">
   <li>${item}</li>
</py:for>

HTML 表单脚本

<html>
   <body>
	
      <form action = "http://localhost:8080/loop" method="post">
         <p>Marks in Physics:</p>
         <p><input type = "text" name = "phy" /></p>
         <p>Marks in Chemistry:</p>
         <p><input type = "text" name = "che" /></p>
         <p>Marks in Maths:</p>
         <p><input type = "text" name = "maths" /></p>
         <p><input type = "submit" value = "submit" /></p>
      </form>
		
   </body>
</html>

Loop ()控制器读取表单数据并将其以列表对象的形式发送到total.template。

from hello.lib.base import BaseController
from tg import expose, request

class RootController(BaseController):
   @expose("hello.templates.marks")
   def marksform(self):
   return {}
	
   @expose("hello.templates.temp")
   def loop(self, **kw):
      phy = kw['phy']
      maths = kw['maths']
      che = kw['che']
      l1 = []
      l1.append(phy)
      l1.append(che)
      l1.append(maths)
		
   return ({'subjects':['physics', 'Chemistry', 'Mathematics'], 'marks':l1})

temp.html 模板使用 py:for 循环以表格的形式呈现 dict 对象的内容。

<html xmlns = "http://www.w3.org/1999/xhtml" 
   xmlns:py = "http://genshi.edgewall.org/" lang = "en">
	
   <body>
      <b>Marks Statement</b>
      <table border = '1'>
         <thead>
            <py:for each = "key in subjects"><th>${key}</th></py:for>
         </thead>
         <tr>
            <py:for each = "key in marks"><td>${key}</td></py:for>
         </tr>
      </table>
   </body>
</html>

启动服务器(如果尚未运行)

gearbox server –reload –debug

在浏览器中输入http://localhost::8080/marksform 。

窗口结果

提交上述表单后,浏览器中将显示以下输出。

表格输出

py:定义

该指令用于创建宏。宏是模板代码的可重用片段。与 Python 函数非常相似,它有一个名称,并且可以选择包含参数。该宏的输出可以插入到模板中的任何位置。

py:def 指令遵循以下语法 -

<p py:def = "greeting(name)">
   Hello, ${name}!
</p>

该宏可以使用“name”参数的变量值来呈现。

${greeting('world')}
${greeting('everybody)}

该指令还可以与另一个版本的语法一起使用,如下所示 -

<py:def function = "greeting(name)">
   <p>Hello, ${name}! </p>
</py:def>

在下面的示例中,root.py中的Macro()控制器将具有两个键 name1 和 name2 的dict对象发送到 Macro.html 模板。

from hello.lib.base import BaseController
from tg import expose, request

class RootController(BaseController):
   @expose('hello.templates.macro')
   def macro(self):
      return {'name1':'TutorialPoint', 'name2':'TurboGears'}

此 Macro.html 模板包含名为greeting 的宏的定义。它用于为从控制器接收的数据生成问候消息。

<html xmlns = "http://www.w3.org/1999/xhtml"
   xmlns:py = "http://genshi.edgewall.org/"
   lang = "en">
	
   <body>
      <h2>py:def example</h2>
		
      <div>
         <div py:def = "greeting(name)">
            Hello, Welcome to ${name}!
         </div>
				
         <b>
            ${greeting(name1)}
            ${greeting(name2)}
         </b>
			
      </div>
   </body>
</html>

使用变速箱启动服务器

gearbox serve –reload –debug

通过在浏览器中输入以下 URL 来调用 Macro() 控制器 -

http://localhost:8080/宏

以下输出将在浏览器中呈现 -

默认示例

py:与

该指令允许您将表达式分配给局部变量。这些局部变量使内部的表达式更简洁、更高效。

假设在模板的上下文数据中给出 x = 50,以下将是 py:with 指令 -

<div>
   <span py:with = "y = 50; z = x+y">$x $y $z</span>
</div>

它将产生以下输出 -

50 50 100

py:with 指令的替代版本也可用 -

<div>
   <py:with = "y = 50; z = x+y">$x $y $z</py:with>
</div>

在下面的示例中,macro() 控制器返回一个带有 name、phy 和 maths 键的 dict 对象。

from hello.lib.base import BaseController
from tg import expose, request

class RootController(BaseController):
   @expose('hello.templates.macro')
   def macro(self):
      return {'name':'XYZ', 'phy':60, 'maths':70}

模板 Macro.html 使用 py:with 指令添加 phy 和 maths 键的值。

<html xmlns = "http://www.w3.org/1999/xhtml"
   xmlns:py = "http://genshi.edgewall.org/"
   lang = "en">
	
   <body>
      <h2>py:with example</h2>
      <h3>Marks Statement for : ${name}!</h3>
		
      <b>Phy: $phy Maths: $maths
         <span py:with = "ttl = phy+maths">Total: $ttl</span>
      </b>
		
   </body>
	
</html>

浏览器将呈现以下输出以响应 URL http://localhost:8080/macro

py:例如

结构操作指令

py :attrs指令添加、修改或删除元素的属性。

<ul>
   <li py:attrs = "foo">Bar</li>
</ul>

如果foo = {'class':'collapse'}存在于模板上下文中,上面的代码片段将呈现该上下文。

<ul>
   <li class = "collapse">Bar</li>
</ul>

py :content指令用计算表达式的结果替换任何嵌套内容 -

<ul>
   <li py:content = "bar">Hello</li>
</ul>

给定上下文数据中的 bar = 'Bye',这将产生

<ul>
   <li>Bye</li>
</ul>

py :replace指令用表达式求值的结果替换元素本身 -

<div>
   <span py:replace = "bar">Hello</span>
</div>

给定上下文数据中的 bar = 'Bye',它将产生

<div>
   Bye
</div>