TurboGears - linguagem de modelo Genshi

Genshi é uma linguagem de template baseada em XML. É similar àKid, que costumava ser o mecanismo de modelo para versões anteriores do TurboGears. Tanto o Genshi quanto o Kid são inspirados por outras linguagens de template conhecidas, comoHSLT, TAL e PHP.

Um modelo Genshi consiste em diretivas de processamento. Essas diretivas são elementos e atributos em um modelo. As diretivas Genshi são definidas em um namespacehttp://genshi.edgewall.org/. Portanto, este namespace precisa ser declarado no elemento raiz do template.

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

A declaração acima significa que o namespace padrão é definido como XHTML e as diretivas Genshi têm o prefixo 'py'.

Diretivas Genshi

Várias diretrizes são definidas em Genshi. A lista a seguir enumera as diretivas Genshi -

  • py:if
  • py:choose
  • py:for
  • py:def
  • py:match
  • py:with
  • py:replace
  • py:content
  • py:attrs
  • py:strip

Seções condicionais

Genshi fornece duas diretivas para renderização condicional de content− py: if e py: choose.

py: se

O conteúdo do elemento desta diretiva será processado apenas se a expressão em if clauseavalia como verdadeiro. Assumindo que os dados no contexto do modelo são{‘foo’:True, ‘bar’:’Hello’}, a seguinte diretiva -

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

vai resultar em

Hello

Esta saída, no entanto, não seria renderizada se ‘foo’ is set to False.

Esta diretiva também pode ser usada como elemento. Nesse caso<py:if> deve ser fechado pelo correspondente </py:if>

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

py: escolha

O processamento condicional avançado é possível com o uso de py:choose em combinação com py:when e py:otherwisediretivas. Este recurso é semelhante aswitch – case construir em C/C++.

Expressão em py:choose diretiva é verificada com diferentes valores identificados com py:whenalternativas e conteúdos correspondentes serão processados. Uma alternativa padrão pode ser fornecida na forma depy:otherwise diretiva.

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

O exemplo a seguir ilustra o uso de py:choose e py:whendiretivas. O formulário HTML envia dados para /marks URL. omarks() função redireciona marcas e resultados na forma de um objeto de dicionário para total.htmlmodelo. A exibição condicional deresult Pass/Fail é conseguido usando py:choose e py:when diretivas.

Script HTML de marcas de entrada (marks.html) é o seguinte -

<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>

O código completo de root.pyé o seguinte. omarks() controlador está enviando marcas e resultados para total.html modelo -

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

o total.html na pasta de modelos recebe dados do dicionário e os analisa na saída html condicionalmente da seguinte forma -

<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>

Inicie o servidor (se ainda não estiver em execução)

Gearbox server –reload –debug

Entrar http://localhost::8080/marksform no navegador -

o total.html irá renderizar a seguinte saída -

py: para

O elemento na diretiva py: for é repetido para cada item em um iterável, normalmente um objeto List Python. E seitems = [1,2,3] está presente em um contexto de modelo, ele pode ser iterado seguindo py: para diretiva -

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

A seguinte saída será renderizada -

1
2
3

O exemplo a seguir mostra dados de formulário HTML renderizados no modelo total.html usando a diretiva py: for também pode ser usada da seguinte maneira -

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

Script de formulário 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>

o loop() o controlador lê os dados do formulário e os envia para total.template na forma de um objeto de lista.

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})

O modelo temp.html usa o loop py: for para renderizar o conteúdo do objeto dict na forma de uma tabela.

<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>

Inicie o servidor (se ainda não estiver em execução)

gearbox server –reload –debug

Entrar http://localhost::8080/marksform no navegador.

A seguinte saída será exibida no navegador quando o formulário acima for enviado.

py: def

Esta diretiva é usada para criar uma macro. Uma macro é um fragmento reutilizável de código de modelo. Muito parecido com uma função Python, tem um nome e pode opcionalmente ter parâmetros. A saída desta macro pode ser inserida em qualquer lugar de um modelo.

A diretiva py: def segue a seguinte sintaxe -

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

Esta macro pode ser renderizada com um valor variável para o parâmetro 'nome'.

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

Esta diretiva também pode ser usada com outra versão da sintaxe da seguinte forma -

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

No exemplo a seguir, macro() controlador em root.py envia um dict objeto com duas chaves name1 e name2 para macro.html template.

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'}

Este modelo macro.html contém a definição de uma macro chamada saudação. É usado para gerar mensagem de saudação para dados recebidos do controlador.

<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>

Inicie o servidor usando a caixa de engrenagens

gearbox serve –reload –debug

Invoque o controlador de macro () inserindo a seguinte URL no navegador -

http://localhost:8080/macro

A saída a seguir será renderizada no navegador -

py: com

Esta diretiva permite atribuir expressões a variáveis ​​locais. Essas variáveis ​​locais tornam a expressão interna menos detalhada e mais eficiente.

Supondo que x = 50 seja fornecido nos dados de contexto de um modelo, o seguinte será o py: com diretiva -

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

Isso resultará na seguinte saída -

50 50 100

Uma versão alternativa para py: com diretiva também está disponível -

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

No exemplo a seguir, o controlador macro () retorna um objeto dict com as chaves name, phy e maths.

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}

O modelo macro.html adiciona valores de chaves phy e matemáticas usando a diretiva py: with.

<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>

O navegador irá renderizar a seguinte saída em resposta ao URL http://localhost:8080/macro

Diretivas de manipulação de estrutura

o py:attrs diretiva adiciona, modifica ou remove atributos do elemento.

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

E se foo = {‘class’:’collapse’} está presente em um contexto de modelo, que o snippet acima renderizará.

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

o py:content diretiva substitui qualquer conteúdo aninhado com o resultado da avaliação da expressão -

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

Dado bar = 'Tchau' nos dados de contexto, isso produziria

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

o py:replace diretiva substitui o próprio elemento com o resultado da avaliação da expressão -

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

Dado bar = 'Tchau' nos dados de contexto, produziria

<div>
   Bye
</div>