Recursive template structure with apache speed

I have a recursive data structure, basically a tree, where a node can have child nodes, etc. I am trying to create a JSON-like file of this structure. Use the #parse directive for this thought. In the context, I store the root of the node and the template name in 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 } 

The Apache speed documentation states that the #parse directive accepts only one argument .

In the examples, I saw the use of the #set directive before calling another template, but if the tree depth is higher than 2, this does not work, because the variable used in the #set directive is stored in the same context, so when moving from depth 1 to 2 the variable will be overwritten.

The reason for using #parse instead of a macro suggested by @Sergiu Dumitriu is that each node may be displayed differently, depending on its $node.type . I would like to have a template for each type, so that one person adding a template for a certain type should not bother with any other template, I mean, maybe this can be achieved by including the type property; but this means that all rendering methods will be defined in one file.

Is there a way to use Velocity to apply patterns to recursive data structures?


Solution Based on both answers by Sergiu Dumitriou, the final template is as follows:

 #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 has the structure shown in the question.

+4
source share
2 answers

You should not use #parse , as this is a somewhat expensive operation. 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 

If the template name is also a variable, you can use #evaluate to dynamically create the template name:

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

To overcome the fact that Velocity variables are global by default, you can use local variables in the current scope. Velocity has several options for including various local areas, including the template area created when the template is rendered, template.provide.scope.control . The problem is that this is disabled by default, so you need to configure Velocity to activate it. After activation, you will automatically have a variable $template , which you can use to store local variables.

 ## 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 } 
+3
source

Source: https://habr.com/ru/post/1491908/


All Articles