| <!doctype html> |
| <!-- Generated by FreeMarker/Docgen from DocBook --> |
| <html lang="en" class="page-type-section"> |
| <head prefix="og: http://ogp.me/ns#"> |
| <meta charset="utf-8"> |
| <title>visit, recurse, fallback - Apache FreeMarker Manual</title> |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| <meta name="viewport" content="width=device-width,initial-scale=1"> |
| <meta name="format-detection" content="telephone=no"> |
| <meta property="og:site_name" content="Apache FreeMarker Manual"> |
| <meta property="og:title" content="visit, recurse, fallback"> |
| <meta property="og:locale" content="en_US"> |
| <meta property="og:url" content="https://freemarker.apache.org/docs/ref_directive_visit.html"> |
| <link rel="canonical" href="https://freemarker.apache.org/docs/ref_directive_visit.html"> |
| <link rel="icon" href="favicon.png" type="image/png"> |
| <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Roboto:500,700,400,300|Droid+Sans+Mono"> |
| <link rel="stylesheet" type="text/css" href="docgen-resources/docgen.min.css?1707770044859"> |
| <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/cookie-bar/cookiebar-latest.min.js"></script> |
| </head> |
| <body itemscope itemtype="https://schema.org/Code"> |
| <meta itemprop="url" content="https://freemarker.apache.org/docs/"> |
| <meta itemprop="name" content="Apache FreeMarker Manual"> |
| |
| <!--[if lte IE 9]> |
| <div class="oldBrowserWarning" style="display: block"> |
| Unsupported web browser - Use a modern browser to view this website! |
| </div> |
| <![endif]--> <div class="oldBrowserWarning"> |
| Unsupported web browser - Use a modern browser to view this website! |
| </div> |
| <div class="header-top-bg"><div class="site-width header-top"><div id="hamburger-menu" role="button"></div> <div class="logo"> |
| <a href="https://freemarker.apache.org" role="banner"><img itemprop="image" src="logo.png" alt="FreeMarker"></a> </div> |
| <ul class="tabs"><li><a href="https://freemarker.apache.org/">Home</a></li><li class="current"><a href="index.html">Manual</a></li><li><a class="external" href="api/index.html">Java API</a></li></ul><ul class="secondary-tabs"><li><a class="tab icon-heart" href="https://freemarker.apache.org/contribute.html" title="Contribute"><span>Contribute</span></a></li><li><a class="tab icon-bug" href="https://issues.apache.org/jira/projects/FREEMARKER" title="Report a Bug"><span>Report a Bug</span></a></li><li><a class="tab icon-download" href="https://freemarker.apache.org/freemarkerdownload.html" title="Download"><span>Download</span></a></li></ul></div></div><div class="header-bottom-bg"><div class="site-width search-row"><a href="index.html" class="navigation-header">Manual</a><div class="navigation-header"></div><form method="get" class="search-form" action="search-results.html"><fieldset><legend class="sr-only">Search form</legend><label for="search-field" class="sr-only">Search query</label><input id="search-field" name="q" type="search" class="search-input" placeholder="Search" spellcheck="false" autocorrect="off" autocomplete="off"><button type="submit" class="search-btn"><span class="sr-only">Search</span></button></fieldset></form></div><div class="site-width breadcrumb-row"> <div class="breadcrumbs"> |
| <ul class="breadcrumb" itemscope itemtype="http://schema.org/BreadcrumbList"><li class="step-0" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="index.html"><span itemprop="name">Apache FreeMarker Manual</span></a></li><li class="step-1" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="ref.html"><span itemprop="name">Template Language Reference</span></a></li><li class="step-2" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="ref_directives.html"><span itemprop="name">Directive Reference</span></a></li><li class="step-3" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="ref_directive_visit.html"><span itemprop="name">visit, recurse, fallback</span></a></li></ul> </div> |
| <div class="bookmarks" title="Bookmarks"><span class="sr-only">Bookmarks:</span><ul><li><a href="alphaidx.html">Alpha. index</a></li><li><a href="gloss.html">Glossary</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions</a></li><li><a href="ref_builtins_alphaidx.html">?builtins</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_specvar.html">.spec_vars</a></li><li><a href="app_faq.html">FAQ</a></li></ul></div></div></div> <div class="main-content site-width"> |
| <div class="content-wrapper"> |
| <div id="table-of-contents-wrapper" class="col-left"> |
| <script>var breadcrumb = ["Apache FreeMarker Manual","Template Language Reference","Directive Reference","visit, recurse, fallback"];</script> |
| <script src="toc.js?1707770044859"></script> |
| <script src="docgen-resources/main.min.js?1707770044859"></script> |
| </div> |
| <div class="col-right"><div class="page-content"><div class="page-title"><div class="pagers top"><a class="paging-arrow previous" href="ref_directive_userDefined.html"><span>Previous</span></a><a class="paging-arrow next" href="ref_specvar.html"><span>Next</span></a></div><div class="title-wrapper"> |
| <h1 class="content-header header-section1" id="ref_directive_visit" itemprop="headline">visit, recurse, fallback</h1> |
| </div></div><div class="page-menu"> |
| <div class="page-menu-title">Page Contents</div> |
| <ul><li><a class="page-menu-link" href="#autoid_130" data-menu-target="autoid_130">Synopsis</a></li><li><a class="page-menu-link" href="#autoid_131" data-menu-target="autoid_131">Description</a><ul><li><a class="page-menu-link" href="#autoid_132" data-menu-target="autoid_132">Visit</a></li><li><a class="page-menu-link" href="#autoid_133" data-menu-target="autoid_133">Recurse</a></li><li><a class="page-menu-link" href="#autoid_134" data-menu-target="autoid_134">Fallback</a></li></ul></li></ul> </div><a name="ref.directive.visit"></a> |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_130">Synopsis</h2> |
| |
| |
| |
| <pre class="metaTemplate"><code class="inline-code"><#visit <em class="code-color">node</em> using <em class="code-color">namespace</em>></code> |
| or |
| <code class="inline-code"><#visit <em class="code-color">node</em>></code></pre> |
| |
| |
| |
| <pre class="metaTemplate"><code class="inline-code"><#recurse <em class="code-color">node</em> using <em class="code-color">namespace</em>></code> |
| or |
| <code class="inline-code"><#recurse <em class="code-color">node</em>></code> |
| or |
| <code class="inline-code"><#recurse using <em class="code-color">namespace</em>></code> |
| or |
| <code class="inline-code"><#recurse></code></pre> |
| |
| |
| |
| <pre class="metaTemplate"><code class="inline-code"><#fallback></code></pre> |
| |
| |
| <p>Where:</p> |
| |
| <ul> |
| <li> |
| <code class="inline-code"><em class="code-color">node</em></code>: |
| Expression evaluates to a <a href="xgui_expose_dom.html">node |
| variable</a>. |
| </li> |
| |
| <li> |
| <code class="inline-code"><em class="code-color">namespace</em></code>: A |
| <a href="dgui_misc_namespace.html">namespace</a>, 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. |
| </li> |
| </ul> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_131">Description</h2> |
| |
| |
| <p>The <code class="inline-code">visit</code> and <code class="inline-code">recurse</code> |
| directives are used for the recursive processing of trees. In |
| practice, this will mostly be used for <a href="xgui.html">processing XML.</a></p> |
| |
| |
| |
| |
| |
| |
| <h3 class="content-header header-section3" id="autoid_132">Visit</h3> |
| |
| |
| <p>When you call <code class="inline-code"><#visit |
| <em class="code-color">node</em>></code>, it looks for a |
| user-defined directive (like a macro) to invoke that has the name |
| deducted from the node's name |
| (<code class="inline-code"><em class="code-color">node</em>?node_name</code>) and |
| namespace |
| (<code class="inline-code"><em class="code-color">node</em>?node_namespace</code>). |
| The rules of name deduction:</p> |
| |
| <ul> |
| <li> |
| <p>If the node doesn't support node namespaces (as text |
| nodes in XML), then the directive name is simply the name of |
| the node |
| (<code class="inline-code"><em class="code-color">node</em>?node_name</code>). |
| <span class="marked-for-programmers">A node does not support node |
| namespaces if the <code class="inline-code">getNodeNamespace</code> method |
| returns <code class="inline-code">null</code>.</span></p> |
| </li> |
| |
| <li> |
| <p>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. <code class="inline-code">e:book</code>). The prefix, and if |
| there is a prefix used at all, depends on what prefixes has |
| been registered with the <code class="inline-code">ns_prefixes</code> |
| parameter of the <code class="inline-code">ftl</code> directive in the <a href="dgui_misc_namespace.html">FTL namespace</a> where |
| <code class="inline-code">visit</code> looks for the handler directive |
| (which is not necessary the same as the FTL namespace where |
| <code class="inline-code">visit</code> was called from, as you will see |
| later). Concretely, if there was no default namespace |
| registered with <code class="inline-code">ns_prefixes</code> then for nodes |
| that does not belong to any namespace (<span class="marked-for-programmers">when <code class="inline-code">getNodeNamespace</code> |
| returns <code class="inline-code">""</code></span>) no prefix is used. If |
| there was a default namespace registered with |
| <code class="inline-code">ns_prefixes</code> then for nodes that does not |
| belong to any namespace prefix <code class="inline-code">N</code> 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 <code class="inline-code">ns_prefixes</code> |
| is used. If there is not prefix associated to the node |
| namespace of the node, then <code class="inline-code">visit</code> simply |
| behave as if there was no directive found with the proper |
| name.</p> |
| </li> |
| </ul> |
| |
| <p>The node for which the user-defined directive was invoked is |
| available for it as special variable <code class="inline-code">.node</code>. |
| Example:</p> |
| |
| |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#-- 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></pre> </div> |
| |
| |
| <p>The output will be something like:</p> |
| |
| |
| |
| <div class="code-block role-output"> |
| <div class="code-block-label">Output</div><pre class="code-block-body"> 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.</pre> </div> |
| |
| |
| <p>If one or more namespaces is specified using the optional |
| <code class="inline-code">using</code> clause, then <code class="inline-code">visit</code> |
| will look for the directives in those namespaces only, with the |
| earlier specified namespaces in the list getting priority. If no |
| <code class="inline-code">using</code> clause is specified, the namespace or |
| sequence of namespaces specified with the <code class="inline-code">using</code> |
| clause of the last uncompleted <code class="inline-code">visit</code> call is |
| reused. If there is no such pending <code class="inline-code">visit</code> call, |
| then the current namespace is used. For example, if you execute |
| this template:</p> |
| |
| |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#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></pre> </div> |
| |
| |
| <p>and this is <code class="inline-code">n1.ftl</code>:</p> |
| |
| |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#macro y> |
| n1.y |
| </#macro></pre> </div> |
| |
| |
| <p>and this is <code class="inline-code">n2.ftl</code>:</p> |
| |
| |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#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></pre> </div> |
| |
| |
| <p>then this will print:</p> |
| |
| |
| |
| <div class="code-block role-output"> |
| <div class="code-block-label">Output</div><pre class="code-block-body"> |
| n2.x |
| n1.y |
| n2.y |
| |
| Simply x |
| </pre> </div> |
| |
| |
| <p>If <code class="inline-code">visit</code> 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 |
| <code class="inline-code">@<em class="code-color">node_type</em></code>, or if |
| the node does not support node type property (i.e. |
| <code class="inline-code"><em class="code-color">node</em>?node_type</code> |
| returns undefined variable), then with name |
| <code class="inline-code">@default</code>. 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 |
| <code class="inline-code">visit</code> stops template processing with error. |
| Some XML specific node types have special handling in this regard; |
| see: <a href="xgui_declarative_details.html">XML Processing Guide/Declarative XML processing/Details</a>. Example:</p> |
| |
| |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#-- 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></pre> </div> |
| |
| |
| <p>This would print:</p> |
| |
| |
| |
| <div class="code-block role-output"> |
| <div class="code-block-label">Output</div><pre class="code-block-body">Handling node x |
| |
| There was no specific handler for node y |
| |
| </pre> </div> |
| |
| |
| |
| |
| |
| |
| |
| |
| <h3 class="content-header header-section3" id="autoid_133">Recurse</h3> |
| |
| |
| <a name="ref.directive.recurse"></a> |
| |
| <p>The <code class="inline-code"><#recurse></code> directive is really |
| syntactic sugar. It visits all children nodes of the node (and not |
| the node itself). So, to write:</p> |
| |
| |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#recurse <em>someNode</em> using <em>someLib</em>></pre> </div> |
| |
| |
| <p>is equivalent to writing:</p> |
| |
| |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#list <em>someNode</em>?children as <em>child</em>><#visit <em>child</em> using <em>someLib</em>></#list></pre> </div> |
| |
| |
| <p>However, target node is optional in the |
| <code class="inline-code">recurse</code> directive. If the target node is |
| unspecified, it simply uses the <code class="inline-code">.node</code>. Thus, |
| the terse instruction <code class="inline-code"><#recurse></code> is |
| equivalent to:</p> |
| |
| |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#list .node?children as child><#visit child></#list></pre> </div> |
| |
| |
| <p>As a side comment for those who are familiar with XSLT, |
| <code class="inline-code"><#recurse></code> is pretty much exactly |
| analogous to the <code class="inline-code"><xsl:apply-templates/></code> |
| instruction in XSLT.</p> |
| |
| |
| |
| |
| |
| |
| |
| <h3 class="content-header header-section3" id="autoid_134">Fallback</h3> |
| |
| |
| <a name="ref.directive.fallback"></a> |
| |
| <p>As you could learn earlier, in the documentation of the |
| <code class="inline-code">visit</code> directive, the user-defined directive |
| that handles the node is maybe searched in multiple FTL |
| name-spaces. The <code class="inline-code">fallback</code> 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 |
| <code class="inline-code">fallback</code> does nothing.</p> |
| |
| <p>A typical usage of this to write customization layer over a |
| handler library, that sometimes passes the handling to the |
| customized library:</p> |
| |
| |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#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></pre> </div> |
| |
| |
| <div class="bottom-pagers-wrapper"><div class="pagers bottom"><a class="paging-arrow previous" href="ref_directive_userDefined.html"><span>Previous</span></a><a class="paging-arrow next" href="ref_specvar.html"><span>Next</span></a></div></div></div></div> </div> |
| </div> |
| <div class="site-footer"><div class="site-width"><div class="footer-top"><div class="col-left sitemap"><div class="column"><h3 class="column-header">Overview</h3><ul><li><a href="https://freemarker.apache.org/">What is FreeMarker?</a></li><li><a href="https://freemarker.apache.org/freemarkerdownload.html">Download</a></li><li><a href="app_versions.html">Version history</a></li><li><a href="app_faq.html">FAQ</a></li><li><a itemprop="license" href="app_license.html">License</a></li><li><a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy policy</a></li></ul></div><div class="column"><h3 class="column-header">Often used / Reference</h3><ul><li><a href="https://try.freemarker.apache.org/">Try template online</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions cheatsheet</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_builtins_alphaidx.html">?built_ins</a></li><li><a href="ref_specvar.html">.special_vars</a></li><li><a href="api/freemarker/core/Configurable.html#setSetting-java.lang.String-java.lang.String-">Configuration settings</a></li></ul></div><div class="column"><h3 class="column-header">Community</h3><ul><li><a href="https://github.com/apache/freemarker">Github project page</a></li><li><a href="https://issues.apache.org/jira/projects/FREEMARKER">Report a bug</a></li><li><a href="https://freemarker.apache.org/report-security-vulnerabilities.html">Report security vulnerability</a></li><li><a href="https://stackoverflow.com/questions/ask?tags=freemarker">Get help on StackOverflow</a></li><li><a href="https://twitter.com/freemarker">Announcements on Twitter</a></li><li><a href="https://freemarker.apache.org/mailing-lists.html">Discuss on mailing lists</a></li></ul></div></div><div class="col-right"><ul class="social-icons"><li><a class="github" href="https://github.com/apache/freemarker">Github</a></li><li><a class="twitter" href="https://twitter.com/freemarker">Twitter</a></li><li><a class="stack-overflow" href="https://stackoverflow.com/questions/ask?tags=freemarker">Stack Overflow</a></li></ul><a class="xxe" href="http://www.xmlmind.com/xmleditor/" rel="nofollow" title="Edited with XMLMind XML Editor"><span>Edited with XMLMind XML Editor</span></a></div></div><div class="footer-bottom"> <p class="last-generated"> |
| Last generated: |
| <time itemprop="dateModified" datetime="2024-02-12T20:34:04Z" title="Monday, February 12, 2024 at 8:34:04 PM Greenwich Mean Time">2024-02-12 20:34:04 GMT</time>, for Freemarker 2.3.32 </p> |
| <p class="copyright"> |
| © <span itemprop="copyrightYear">1999</span>–2024 |
| <a itemtype="http://schema.org/Organization" itemprop="copyrightHolder" href="https://apache.org/">The Apache Software Foundation</a>. Apache FreeMarker, FreeMarker, Apache Incubator, Apache, the Apache FreeMarker logo are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners. </p> |
| </div></div></div></body> |
| </html> |