| <!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>Basics - 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="Basics"> |
| <meta property="og:locale" content="en_US"> |
| <meta property="og:url" content="https://freemarker.apache.org/docs/xgui_declarative_basics.html"> |
| <link rel="canonical" href="https://freemarker.apache.org/docs/xgui_declarative_basics.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="xgui.html"><span itemprop="name">XML Processing Guide</span></a></li><li class="step-2" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="xgui_declarative.html"><span itemprop="name">Declarative XML processing</span></a></li><li class="step-3" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="xgui_declarative_basics.html"><span itemprop="name">Basics</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","XML Processing Guide","Declarative XML processing","Basics"];</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="xgui_declarative.html"><span>Previous</span></a><a class="paging-arrow next" href="xgui_declarative_details.html"><span>Next</span></a></div><div class="title-wrapper"> |
| <h1 class="content-header header-section1" id="xgui_declarative_basics" itemprop="headline">Basics</h1> |
| </div></div> <div class="callout note"> |
| <strong class="callout-label">Note:</strong> |
| |
| <p>This section uses the DOM tree and the variable made in <a href="xgui_expose.html">a previous chapter</a>.</p> |
| </div> |
| <p>With the imperative approach of XML processing -- this was shown |
| in the previous chapter -- you write an FTL program that walks the |
| tree to find the different kind of nodes. With the declarative |
| approach, you rather define how to handle the different kind of nodes, |
| and then let FreeMarker walk the tree and call the handlers you have |
| defined. This approach is useful for complex XML schemas, where the |
| same element can occur as the child of many other elements. Examples |
| of such schemas are XHTML and XDocBook.</p><p>The directive you most often use with the declarative approach |
| is the <a href="ref_directive_visit.html#ref.directive.recurse"><code>recurse</code> |
| directive</a>. This directive gets a node variable as parameter, |
| and "visits" all its children nodes, one after the other, |
| starting with the first child. "Visiting" a node means |
| that it calls a user-defined directive (like a macro) that has the |
| same name as the name of the child node |
| (<code class="inline-code">?node_name</code>). We say on this, that the user-defined |
| directive <em>handles</em> the node. The node that the |
| user-defined directive just handles is available as special variable |
| <code class="inline-code">.node</code>. For example, this FTL:</p> |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#recurse doc> |
| |
| <#macro book> |
| I'm the book element handler, and the title is: ${.node.title} |
| </#macro></pre> </div> |
| <p>will print (I have removed some disturbing white-space form the |
| output):</p> |
| |
| <div class="code-block role-output"> |
| <div class="code-block-label">Output</div><pre class="code-block-body">I'm the book element handler, and the title is: Test Book</pre> </div> |
| <p>If you call <code class="inline-code">recurse</code> without parameter, then |
| it uses <code class="inline-code">.node</code>, that is, it visits all children |
| nodes of the node currently handled. So this FTL:</p> |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#recurse doc> |
| |
| <#macro book> |
| Book element with title ${.node.title} |
| <#recurse> |
| End book |
| </#macro> |
| |
| <#macro title> |
| Title element |
| </#macro> |
| |
| <#macro chapter> |
| Chapter element with title: ${.node.title} |
| </#macro></pre> </div> |
| <p>will print (I have removed disturbing white-space form the |
| output):</p> |
| |
| <div class="code-block role-output"> |
| <div class="code-block-label">Output</div><pre class="code-block-body">Book element with title Test Book |
| Title element |
| Chapter element with title: Ch1 |
| Chapter element with title: Ch2 |
| End book</pre> </div> |
| <p>You have seen how to define handlers for element nodes, but not |
| how to define handler for the text nodes. Since the name of the |
| handler is the same as the node-name of nodes it handles, and as the |
| node-name of all text nodes is <code class="inline-code">@text</code> (see <a href="xgui_imperative_formal.html#misc.xguiTable">the table</a>), you define handler for the |
| text nodes like this:</p> |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"> |
| <#macro @text>${.node?html}</#macro></pre> </div> |
| <p>Note the <code class="inline-code">?html</code>. You have to HTML-escape the |
| text, since you generate output of HTML format.</p><p>Here it is the template that transforms the XML to complete |
| HTML:</p><a name="misc.example.declarativeBookProcessor"></a> |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#recurse doc> |
| |
| <#macro book> |
| <html> |
| <head> |
| <title><#recurse .node.title></title> |
| </head> |
| <body> |
| <h1><#recurse .node.title></h1> |
| <#recurse> |
| </body> |
| </html> |
| </#macro> |
| |
| <#macro chapter> |
| <h2><#recurse .node.title></h2> |
| <#recurse> |
| </#macro> |
| |
| <#macro para> |
| <p><#recurse> |
| </#macro> |
| |
| <#macro title> |
| <#-- |
| We have handled this element imperatively, |
| so we do nothing here. |
| --> |
| </#macro> |
| |
| <#macro @text>${.node?html}</#macro></pre> </div> |
| <p>and the output will be (now I will honestly include the annoying |
| white-space...):</p> |
| |
| <div class="code-block role-output"> |
| <div class="code-block-label">Output</div><pre class="code-block-body"> <html> |
| <head> |
| <title>Test Book</title> |
| </head> |
| <body> |
| <h1>Test Book</h1> |
| |
| |
| <h2>Ch1</h2> |
| |
| |
| <p>p1.1 |
| |
| <p>p1.2 |
| |
| <p>p1.3 |
| |
| |
| <h2>Ch2</h2> |
| |
| |
| <p>p2.1 |
| |
| <p>p2.2 |
| |
| |
| </body> |
| </html> |
| |
| </pre> </div> |
| <p>Note that you can reduce substantially the amount of superfluous |
| whitespace in the output by using the <a href="ref_directive_t.html">trim directives</a>, as |
| <code class="inline-code"><#t></code>. See also: <a href="dgui_misc_whitespace.html">Template Author's Guide/Miscellaneous/White-space handling</a></p><p>You may say that the FTL that did it with imperative approach |
| was much shorter. That's true, but the example XML uses a very simple |
| schema, and as I said, the declarative approach brings its form with |
| XML schemas that are not that firm about what element can occur where. |
| Say, introduce element <code class="inline-code">mark</code>, that should color text |
| to red, does not mater where do you use it; in a |
| <code class="inline-code">title</code>, or in a <code class="inline-code">para</code>. For this, |
| with the declarative approach, you just add a macro:</p> |
| |
| <div class="code-block role-template"> |
| <div class="code-block-label">Template</div><pre class="code-block-body"><#macro mark><font color=red><#recurse></font></#macro></pre> </div> |
| <p>And then <code class="inline-code"><mark>...</mark></code> will |
| automatically work everywhere. So for certain XML schemas, declarative |
| XML processing will actually result in shorter, and what is even more |
| important, much clearer FTL-s, than imperative XML processing. It's up |
| to you to decide which approach to use when; don't forget that you can |
| mix the two approaches freely. Say, in an element handler, you can use |
| imperative approach to process the contents of that element.</p><div class="bottom-pagers-wrapper"><div class="pagers bottom"><a class="paging-arrow previous" href="xgui_declarative.html"><span>Previous</span></a><a class="paging-arrow next" href="xgui_declarative_details.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> |