编译Jinja2 AST的子部分

2 投票
1 回答
1553 浏览
提问于 2025-04-16 07:47

能否对Jinja2的抽象语法树(AST)的一部分进行编译或还原?

举个例子,是否可以从jinja2.environmentjinja2.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扩展;以及
  2. 在Jinja 2中在包含文件顶部插入JavaScript

感谢你的阅读。

布莱恩

1 个回答

1

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。记得在使用完后把它丢掉,否则它会出现在你的模板中。

撰写回答