我有一个递归数据结构,基本上是一个树,其中一个节点可能有子节点,依此类推。我正在尝试生成该结构的类似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
}
apache velocity文档指出#parse
指令only takes one argument。
在示例中,我看到在调用另一个模板之前使用#set
指令,但是如果树的深度高于2,则这不起作用,因为#set
指令中使用的变量存储在相同的上下文中,因此当从深度1到2时,变量将被覆盖。
使用#parse
而不是@Sergiu Dumitriu建议的宏的原因是因为每个节点可能会以不同的方式呈现,具体取决于它的属性$node.type
。我想为每种类型都有一个模板,所以一个人为特定类型添加模板不必混淆任何其他模板,我的意思是,也许这可以通过在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
具有问题中显示的结构。
答案 0 :(得分:7)
你不应该使用#parse
,因为这是一个有点昂贵的操作。而是Define a macro and use it recursively。
#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
答案 1 :(得分:3)
为了克服默认情况下Velocity变量是全局变量的事实,您可以在当前范围中使用局部变量。 Velocity具有several options用于启用不同的本地范围,包括在呈现模板时创建的模板范围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
}