Freemarker - 循环变量无法在嵌套宏调用中幸存

时间:2013-09-05 11:59:42

标签: freemarker

我有以下freemarker模板:

[#local snippet ][#noparse]
        [#assign out ]value: ${v}
        [/#assign]
    [/#noparse]
[/#local]
[#assign hook = snippet?interpret ]
...
[#macro trigger ]
    [@hook /]
[/#macro]
...
[#list values as v ]
    [@trigger ]
[/#list]
${out}

它本质上做的是定义一个钩子以便在稍后的某个时刻执行,一个宏来触发它的执行。

当我尝试渲染此模板时,出现以下错误:

The following has evaluated to null or missing:
==> v  [in template "xxx.ftl->anonymous_interpreted" at line 1, column 17]

注意以下内容可能会很有趣:

[#list values as v ]
    [@hook ]
[/#list]

只是工作,即按照我的预期渲染模板,为列表中的每个值打印value: xxx

  • 有人知道这里出了什么问题吗?
  • 有没有办法让这项工作符合预期?

编辑

我刚刚发现如果我通过常规宏代替解释片段,则不会发生错误:

[#assign hook = myMacro ]
...

但如果宏是在另一个名称空间中定义的话,则不行。

1 个答案:

答案 0 :(得分:3)

循环变量(v)基本上是#list块的局部变量。因此,使用Java-ish伪代码,您尝试执行的操作就像:

void main() {
   for (int v : values) {
      trigger();
   }
}

void trigger() {
   print(v);  // Error, v is not visible here!
}

在调用用?interpret定义的指令时,这是特别的,因为它试图表现得像在调用位置复制粘贴代码片段一样。也就是说,使用@hook调用的指令不会创建自己的本地上下文。因此,如果您从循环中直接将称为,它就会看到v的原因。但是如果你将它称为trigger形式,那么它将存在于trigger宏的本地上下文中,它具有自己的本地上下文。

从使其工作为止......一种可能性是通过v<#assign value = v>分配给命名空间范围变量,然后在解释的片段中引用value。如果可以的话,另一种解决方案当然是摆脱trigger间接。另一个解决方案是使用trigger而不是?interpret来定义#macro,因为trigger会看到v,因此hook也会{{1}}