模板递归结构与apache速度



我有一个递归数据结构,基本上是一个树,其中一个节点可能有子节点等等。我正在尝试生成一个类似JSON的结构文件。对于使用#parse指令的想法。在上下文中,我存储根节点,在templateName中存储模板的名称。

{
    "name" = "$node.name",
    "value" = "$node.value"
    #if ($node.childrens.size() > 0)
    ,
    "childrens" = {
        #foreach ($child in $node.childrens)
            ## The next statement does not work
            #parse ($child.type + ".vm", $child)
        #end
    }
    #end
}

apachevelocity文档指出#parse指令只接受一个参数。

在示例中,我看到在调用另一个模板之前使用了#set指令,但如果树的深度高于2,这就不起作用,因为#set指令中使用的变量存储在同一上下文中,因此当从深度1到深度2时,变量将被覆盖。

使用#parse而不是@Sergiu Dumitriu建议的宏的原因是,每个节点可能根据其属性$node.type以不同的方式呈现。我希望每个类型都有一个模板,这样一个人为特定类型添加模板就不必与任何其他模板混淆,我的意思是,也许这可以通过在类型属性上切换来实现;但这意味着所有渲染方式都将在同一文件中定义。

有没有任何方法可以使用Velocity将模板应用于递归数据结构?


解决方案根据Sergiu Dumitriu的两个答案,最终模板看起来像:

#macro ( displayNode $node)
{
    #set ( $parseNode = $node )
    #set ( $parseTemplate = $parseNode.type + ".vm" )
    #parse ( $parseTemplate )
    #set ( $parseNode = $node )
    #set ( $parseTemplate = "Common.vm" )
    #parse ( $parseTemplate )
}
#end

Common.vm具有问题中所示的结构。

您不应该使用#parse,因为这是一个成本较高的操作。定义一个宏并递归使用它。

#macro(displayNode $node)
{
    "name" = "$node.name",
    "value" = "$node.value"##
    #if ($node.childrens.size() > 0),
    "childrens" = {
        #foreach ($child in $node.children)
            #displayNode($child)
        #end
    }
    #end
}
#end

如果模板名称也是可变的,则可以使用#evaluate动态构建模板名称:

        #set ($d = '$')
        #foreach ($child in $node.children)
            #evaluate("#display${child.type}Node(${d}child)")
        #end

为了克服Velocity中默认变量是全局变量的事实,您可以在当前范围中使用局部变量。Velocity有几个选项用于启用不同的本地作用域,包括每当渲染模板时创建的模板作用域template.provide.scope.control。问题是,这在默认情况下是禁用的,所以您必须配置Velocity才能激活它。激活后,您将自动拥有一个$template变量,可用于存储本地变量。

## The first thing to do is to copy the $node value into a local scope
## that won't be overwritten by nested calls
#set ($template.node = $node)
{
    "name" = "$template.node.name",
    "value" = "$template.node.value"##
    #if ($template.node.childrens.size() > 0),
    "childrens" = {
        #foreach ($child in $template.node.children)
            ## $template.node doesn't change, so now $node can be freely reassigned
            #set ($node = $child)
            #parse("${child.type}.vm")
        #end
    }
    #end
}

最新更新