Skip to main content
 首页 » 编程设计

python之编译 Jinja2 AST 的小节

2025年05月04日7zhwl

可以编译或还原 Jinja2 AST 的一部分吗?

例如,是否可以从jinja2.environment调用函数或方法?或 jinja2.compiler.generate或者从模板中提取的节点列表中的一些等价物?

例如,给定一个模板y.html:

avant-tag 
{% xyz %} 
tag content {{ 3 + 5 }} 
{% endxyz %} 
apres-tag 

和一个扩展y.py:

# -*- coding: utf-8 -*- 
from jinja2 import nodes, Environment, FileSystemLoader 
from jinja2.ext import Extension 
 
class YExtension(Extension): 
    tags = set(['y']) 
 
    def __init__(self, environment): 
        super(YExtension, self).__init__(environment) 
 
    def parse(self, parser): 
        tag = parser.stream.next() 
        body = parser.parse_statements(['name:endy'], drop_needle=True) 
        return nodes.Const("<!-- slurping: %s -->" % str(body)) 
 
env = Environment( 
    loader      = FileSystemLoader('.'), 
    extensions  = [YExtension], 
    ) 
 
print env.get_template('x.html').render() 

运行 python y.py 会产生预期的输出:

avant-tag 
 <!-- slurping: [Output(nodes=[TemplateData(data=u'\n    tag-content '), 
   Add(left=Const(value=3), right=Const(value=5)), 
   TemplateData(data=u'\n ')])] --> 
sous-tag 

在parse 方法中,如何可以:

  1. 将body编译为unicode(即tag-content 8);或者,或者,
  2. 将 body 恢复为其原始来源(即 tag-content {{ 3 + 5 }})。

作为背景,这个问题与之前的两个问题有关:

  1. Jinja2 compile extension after includes ;和
  2. Insert javascript at top of including file in Jinja 2

感谢阅读。

布莱恩

请您参考如下方法:

在 parse() 方法中还不能编译成 unicode,因为此时您没有可用的上下文。您当然可以绕过它,但这可能不是最好的方法。

请注意,parse() 步骤通常只在 html 文件上执行一次,之后它将使用解析的字节码来呈现模板。解析步骤的结果可以在给定的环境中呈现。

你根本没有那里可用的上下文,并且在那里获取上下文......非常困难;)

然而,要获得原始来源...没有黑客攻击也不会容易得多,但黑客攻击也不算太糟糕;)

class YExtension(Extension): 
    tags = set(['y']) 
 
    def preprocess(self, source, name, filename=None): 
        # insert some code here that replaces '{% xyz %}foo bar{% endxyz %}' 
        # with something like: '{% xyz %}foo bar{% raw %}foo bar{% endraw %}{% endxyz %}' 
        return source 

之后,您可以从 {% raw %} 节点读取作为 value 的文本。之后一定要将其删除,否则它将显示在您的模板中。