如何解析django模板?

How are django templates parsed?

我一直在尝试了解更多关于Django的模板引擎,因为它在我看来总是有点像一个黑匣子。文档对所涉及的一般步骤给出了一个很好的概述,并指出模板是被加载和解析的,从而创建了一个节点树(层叠?)并附加在一起以给出结果。

我不理解的是解析的方法,以及在什么条件下创建节点?解析后,什么构成了一个特定的节点,这对创建自定义模板标记有何影响(即,是否有更好、更有效的方法来编写模板标记,从而减少节点?).


从每个标记中创建一个节点。通过阅读如何编写自定义标记,您可以了解它是如何工作的。标签中的任何内容都将是其子项。以下是来自Django Docs的注释标记示例:

1
2
3
4
def do_comment(parser, token):
    nodelist = parser.parse(('endcomment',))
    parser.delete_first_token()
    return CommentNode()

正如您所看到的,comment标签将解析所有内容,直到"endcomment"结束,并将其丢弃。其他标签会将nodelist传递给SometagNode(),并将其用于渲染。

呈现是递归完成的。当在节点上调用render()时,它会在其子节点上运行render,依此类推。

解析也是递归进行的,这就是为什么你可以得到嵌套的标签,并且parser.parse()会设法找到合适的匹配结束标签,因为当它进行解析并偶然发现一个标签时,它会调用do_tag()东西,而这反过来又会调用parser.parse()来找到最近的结束标签,并将所有东西包装成一个节点,返回一个节点,较高的parser.parse()将把它放在一个节点列表中,并继续搜索结束标记。

节点中的上下文对象是一种dicts结构列表。额外的上下文被推到现有上下文的顶部,并传递给子节点,并在节点呈现后弹出,这样它就不会影响上部作用域。

对于没有子代的标记,不使用parser.parse(),因此返回的节点实例没有任何子代。


了解该过程更多信息的一种方法是使用werkzeug调试器运行django,并在模板中触发异常。这样,您就可以查看(和交互)到该点为止的整个堆栈。


我想你首先应该看看code.djangoproject.com使用django/template/base.py-第一个(如Yuji Tomita之前所述)。或者下载源代码,并使用您最喜欢的编辑器或IDE进行查看。


我猜他们使用标记化和解析

一个简单的描述方法是:

Tokenizing:将代码分解为以下类型:

1
integer foo ="bar" + 15;

这包括

1
T_VARIABLETYPE  + T_VARIABLENAME  + T_EQUALS + T_STRING + T_PLUS + T_DIGIT + T_SEMI

在这之后,您可以通过使用解析器查找模式来进行解析。

解析:

找到模式:

1
T_VARIABLETYPE  + T_VARIABLENAME  + T_EQUALS + {A recursive thing} + T_SEMI

这样就可以执行命令

如果你想试验一下,我建议你使用"antlr"http://www.antlr.org。/它可以在很多不同的语言中使用,如Java或C语言,甚至PHP和JS。