visit, recurse, fallback  
    
    
    
    
            
  
  
  
  
Synopsis  
          <#visit node using namespace>
or
<#visit node>
          <#recurse node using namespace>
or
<#recurse node>
or
<#recurse using namespace>
or
<#recurse>
          <#fallback>
          Where:
              
            - 
              node:
              Expression evaluates to a node
              variable.
            
 
            - 
              namespace: A
              namespace, or a
              sequence of namespaces. A namespace can be given with the
              namespace hash (a.k.a. gate hash), or with a string literal that
              store the path of template that could be imported. Instead of
              namespace hashes, you can use plain hashes as well.
            
 
          
     
        
            
  
  
  
  
Description  
          The visit and recurse
          directives are used for the recursive processing of trees. In
          practice, this will mostly be used for processing XML.
          
              
  
  
  
  
Visit  
            When you call <#visit
            node>, it looks for a
            user-defined directive (like a macro) to invoke that has the name
            deducted from the node's name
            (node?node_name) and
            namespace
            (node?node_namesoace).
            The rules of name deduction:
                
              - 
                
If the node doesn't support node namespaces (as text
                nodes in XML), then the directive name is simply the name of
                the node
                (node?node_name).
                A node does not support node
                namespaces if the getNodeNamespace method
                returns null.
               
              - 
                
If the node does support node namespaces (as element
                nodes in XML), then a prefix deduced from the node namespace
                maybe appended before the node name with a colon used as
                separator (e.g. e:book). The prefix, and if
                there is a prefix used at all, depends on what prefixes has
                been registered with the ns_prefixes
                parameter of the ftl directive in the FTL namespace where
                visit looks for the handler directive
                (which is not necessary the same as the FTL namespace where
                visit was called from, as you will see
                later). Concretely, if there was no default namespace
                registered with ns_prefixes then for nodes
                that does not belong to any namespace (when getNodeNamespace
                returns "") no prefix is used. If
                there was a default namespace registered with
                ns_prefixes then for nodes that does not
                belong to any namespace prefix N is used,
                and for nodes that belong to the default node namespace no
                prefix is used. Otherwise, in both case, the prefix associated
                to the node namespace with the ns_prefixes
                is used. If there is not prefix associated to the node
                namespace of the node, then visit simply
                behave as if there was no directive found with the proper
                name.
               
            
     
            The node for which the user-defined directive was invoked is
            available for it as special variable .node.
            Example:
              |   |   | 
  | 
<#-- Assume that nodeWithNameX?node_name is "x" -->
<#visit nodeWithNameX>
Done.
<#macro x>
   Now I'm handling a node that has the name "x".
   Just to show how to access this node: this node has ${.node?children?size} children.
</#macro>   |  
  |   | 
  |   |   |       
   
            The output will be something like:
              |   |   | 
  | 
   Now I'm handling a node that has the name "x".
   Just to show how to access this node: this node has 3 children.
Done.    |  
  |   | 
  |   |   |       
   
            If one or more namespaces is specified using the optional
            using clause, then visit
            will look for the directives in those namespaces only, with the
            earlier specified namespaces in the list getting priority. If no
            using clause is specified, the namespace or
            sequence of namespaces specified with the using
            clause of the last uncompleted visit call is
            reused. If there is no such pending visit call,
            then the current namespace is used. For example, if you execute
            this template:
              |   |   | 
  | 
<#import "n1.ftl" as n1>
<#import "n2.ftl" as n2>
<#-- This will call n2.x (because there is no n1.x): -->
<#visit nodeWithNameX using [n1, n2]>
<#-- This will call the x of the current namespace: -->
<#visit nodeWithNameX>
<#macro x>
  Simply x
</#macro>    |  
  |   | 
  |   |   |       
   
            and this is n1.ftl:
              |   |   | 
  | 
<#macro y>
  n1.y
</#macro>    |  
  |   | 
  |   |   |       
   
            and this is n2.ftl:
              |   |   | 
  | 
<#macro x>
  n2.x
  <#-- This callc n1.y as it inherits the "using [n1, n2]" from the pending visit call: -->
  <#visit nodeWithNameY>
  <#-- This will call n2.y: -->
  <#visit nodeWithNameY using .namespace>
</#macro>
<#macro y>
  n2.y
</#macro>    |  
  |   | 
  |   |   |       
   
            then this will print:
            
            If visit doesn't find a user-defined
            directive in either FTL namespaces with the name identical to the
            name deduced with the rules described earlier, then it tries to
            find an user-defined directive with name
            @node_type, or if
            the node does not support node type property (i.e.
            node?node_type
            returns undefined variable), then with name
            @default. For the lookup, it uses the same
            mechanism as was explained earlier. If it still doesn't find an
            user-defined directive to handle the node, then
            visit stops template processing with error.
            Some XML specific node types have special handling in this regard;
            see: XML Processing Guide/Declarative XML processing/Details. Example:
              |   |   | 
  | 
<#-- Assume that nodeWithNameX?node_name is "x" -->
<#visit nodeWithNameX>
<#-- Assume that nodeWithNameY?node_type is "foo" -->
<#visit nodeWithNameY>
<#macro x>
Handling node x
</#macro>
<#macro @foo>
There was no specific handler for node ${node?node_name}
</#macro>   |  
  |   | 
  |   |   |       
   
            This would print:
              |   |   | 
  | 
Handling node x
  
There was no specific handler for node y
     |  
  |   | 
  |   |   |       
   
          
          
              
  
  
  
  
Recurse  
            
            The <#recurse> directive is really
            syntactic sugar. It visits all children nodes of the node (and not
            the node itself). So, to write:
              |   |   | 
  | 
<#recurse someNode using someLib>    |  
  |   | 
  |   |   |       
   
            is equivalent to writing:
              |   |   | 
  | 
<#list someNode?children as child><#visit child using someLib></#list>    |  
  |   | 
  |   |   |       
   
            However, target node is optional in the
            recurse directive. If the target node is
            unspecified, it simply uses the .node. Thus,
            the terse instruction <#recurse> is
            equivalent to:
              |   |   | 
  | 
<#list .node?children as child><#visit child></#list>    |  
  |   | 
  |   |   |       
   
            As a side comment for those who are familiar with XSLT,
            <#recurse> is pretty much exactly
            analogous to the <xsl:apply-templates/>
            instruction in XSLT.
          
          
              
  
  
  
  
Fallback  
            
            As you could learn earlier, in the documentation of the
            visit directive, the user-defined directive
            that handles the node is maybe searched in multiple FTL
            name-spaces. The fallback directive can be used
            in a user-defined directive that was invoked to handle a node. It
            directs FreeMarker to continue the searching for the user-defined
            directive in the further name-spaces (that is, in the name-spaces
            that are after the name-space of the currently invoked
            user-defined directive in the list of name-spaces). If a handler
            for the node is found then it is invoked, otherwise
            fallback does nothing.
            A typical usage of this to write customization layer over a
            handler library, that sometimes passes the handling to the
            customized library:
              |   |   | 
  | 
<#import "/lib/docbook.ftl" as docbook>
<#--
  We use the docbook library, but we override some handlers
  in this namespace.
-->
<#visit document using [.namespace, docbook]>
<#--
  Override the "programlisting" handler, but only in the case if
  its "role" attribute is "java"
-->
<#macro programlisting>
  <#if .node.@role[0]!"" == "java">
    <#-- Do something special here... -->
    ...
  <#else>
    <#-- Just use the original (overidden) handler -->
    <#fallback>
  </#if>
</#macro>   |  
  |   | 
  |   |   |