2013-07-17 99 views
4

我有一個遞歸數據結構,基本上是一棵樹,其中一個節點可能有子節點等。我試圖生成一個類似JSON的文件。對於使用#parse指令的想法。在上下文中,我存儲根節點,並在templateName中存儲模板的名稱。模板遞歸結構與Apache速度

{ 
    "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 
} 

的阿帕奇速度文檔指出#parse指令only takes one argument

在示例中我已經看到在調用另一個模板之前使用#set指令,但是如果樹的深度高於2,則這不起作用,因爲#set指令中使用的變量存儲在相同的上下文中,所以當從深度1到2時,變量將被覆蓋。

使用#parse而不是@Sergiu Dumitriu建議的宏的原因是因爲每個節點可能以不同的方式呈現,具體取決於它的屬性$node.type。我想每個類型都有一個模板,因此爲特定類型添加模板的人員不必與任何其他模板混淆,也就是說,可以通過在類型屬性上進行切換來實現;但這意味着所有渲染方式都將在同一個文件中定義。

有沒有使用Velocity將模板應用於遞歸數據結構的方法?


解決方案 基於從的Sergiu杜米特留兩個答案最終模板的樣子:

#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有問題所示的結構。

回答

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 
+0

我沒想到如果是這樣,它可能會完成工作。我之所以去解析是因爲每個節點可能以不同的方式顯示,具體取決於節點的類型屬性。這就是我使用'#parse'的原因。這個問題在問題中沒有明確說明,所以我已經更新以反映這個事實。 –

+0

遞歸宏有效,宏參數似乎是該宏調用的本地對象。我還在另一個答案中提供的'#parse'之前使用了'#set',所以最終解決方案是兩者的混合。 –

3

爲了克服這樣的事實,默認情況下在速度變量是全球性的,你可以使用本地當前範圍內的變量。 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 
}