2010-10-01 99 views
1

您好我一直在試圖爲jinja2創建一個擴展,它將會使用分隔符連接多個項目,同時跳過評估爲空白的項目(模板片段)。如何爲Jinja2寫一個「joiner」擴展?

有幾個這些片段,你永遠不知道哪些將是非空的,哪些將會。

聽起來像一個微不足道的任務,但我真的很難讓這個工作在jinja2。也許部分原因是jinja不允許定義自定義模板節點。

你有什麼建議嗎?下面是一個將執行解析工作的代碼段,但它缺少評估部分。

class JoinerExtension(Extension): 
    """Template tag that joins non-whitespace (string) items 
    with a specified separator 

    Usage syntax: 

    {% joinitems separator='|' %} 
    .... 
    {% separator %} 
    .... 
    {% separator %} 
    .... 
    {% endjoinitems %} 

    where value of "separator" within the joinitems tag 
    can be an expression, not necessarily a sting 
    """ 

    tags = set(['joinitems']) 

    def parse(self, parser): 
     """parse function for the 
     joinitems template tag 
     """ 
     lineno = next(parser.stream).lineno 

     #1) read separator 
     separator = None 
     while parser.stream.current.type != 'block_end': 
      name = parser.stream.expect('name') 
      if name.value != 'separator': 
       parser.fail('found %r, "separator" expected' % 
          name.value, name.lineno, 
          exc=TemplateAssertionError) 

      # expressions 
      if parser.stream.current.type == 'assign': 
       next(parser.stream) 
       separator = parser.parse_expression() 
      else: 
       var = parser.stream.current 
       parser.fail('assignment expected after the separator' % 
          var.value, var.lineno, 
          exc=TemplateAssertionError) 

     #2) read the items 
     items = list() 
     end_tags = ['name:separator', 'name:endjoinitems'] 
     while True: 
      item = parser.parse_statements(end_tags) 
      items.append(item) 
      if parser.stream.current.test('name:separator'): 
       next(parser.stream) 
      else: 
       next(parser.stream) 
       break 

回答

4

內置的joiner類可能工作嗎?以下是文檔中的一個簡單示例。

{% set pipe = joiner("|") %} 
{% if categories %} {{ pipe() }} 
    Categories: {{ categories|join(", ") }} 
{% endif %} 
{% if author %} {{ pipe() }} 
    Author: {{ author() }} 
{% endif %} 
{% if can_edit %} {{ pipe() }} 
    <a href="?action=edit">Edit</a> 
{% endif %} 

你提到,它並不知道哪些碎片將是空的,在「顯示」它之前,可能會將每個片段的值存儲在變量中,以便確定哪些片段確實是空的。例如:

{% set pipe = joiner("|") %} 
{% set fragment = gen_fragment1() %} 
{% if fragment|trim is not "" %} 
    {{ pipe() }} {{ fragment }} 
{% endif %} 
... 

你甚至可以封裝上面的圖案在宏以減少重複:

{% set pipe = joiner("|") %} 
{{ print_if_notblank(pipe, gen_fragment1()) }} 
{{ print_if_notblank(pipe, gen_fragment2()) }} 
... 

其中print_if_notblank是一個宏定義爲:

{% macro print_if_notblank(separator, content) %} 
    {% if content|trim is not "" %} 
     {{ separator() }} {{ content }} 
    {% endif %} 
{% endmacro %} 
+0

,將工作,使用現在內置了策略性的{{pipe()}}調用。 – Evgeny 2010-10-01 22:22:11