Details

Default handlers

For some XML node types, there is a default handler, which will handle the node if you haven't defined a handler for the node (i.e. if there is no user-defined directive available with name identical to the node name). Here are these node types, and what the default handler does:

  • Text node: prints the text as it. Note, that in most applications, this will not be good for you, because you should escape the text before you send it to the output (with ?html or ?xml or ?rtf, ...etc. depends on the output format).

  • Processing instruction node: call handler called @pi if you have created such user-defined directive, otherwise do nothing (ignore the node).

  • Comment node, document type node: Do nothing (ignore the node).

  • Document node: Call recurse, that is, visit all children of the document node.

Element and attribute nodes will be handled according to the usual, XML independent mechanism. That is, @node_type will be called as handler, and if that's not defined, then an error stops template processing.

In the case of element nodes, this means that if you define a macro (or other kind of user-defined directive) called @element, that will catch all element nodes, which has no more specific handler. If you have no @element handler, then you must define a handler for all possible elements.

Attribute nodes are not visited by the recurse directive, so you don't need to write handlers for them.

Visiting a single node

With the visit directive you can visit a single node, instead of the children of the node: <#visit nodeToVisist>. This can be useful sometimes.

XML namespaces

We said that the name of the handler user-defined directive (like a macro) for an element is the name of the element. In fact, it is the full-qualified name of the element: prefix:elementName. The rules regarding the usage of prefix-es is the same as with imperative processing. Thus, the user-defined book directive handles only element book that does not belong to any XML namespace (unless you have specified a default XML namespace). So if the example XML would use XML namespace http://example.com/ebook:

<book xmlns="http://example.com/ebook">
...

Then the FTL should look as this:

Template
<#ftl ns_prefixes={"e":"http://example.com/ebook"}>

<#recurse doc>

<#macro "e:book">
  <html>
    <head>
      <title><#recurse .node["e:title"]></title>
    </head>
    <body>
      <h1><#recurse .node["e:title"]></h1>
      <#recurse>
    </body>
  </html>
</#macro>

<#macro "e:chapter">
  <h2><#recurse .node["e:title"]></h2>
  <#recurse>
</#macro>

<#macro "e:para">
  <p><#recurse>
</#macro>

<#macro "e:title">
  <#--
    We have handled this element imperatively,
    so we do nothing here.
  -->
</#macro>

<#macro @text>${.node?html}</#macro>

Or, you can define a default XML namespace, and then the further part of the template remains the same as in the original XML namespace free example:

Template
<#ftl ns_prefixes={"D":"http://example.com/ebook"}>

<#recurse doc>

<#macro book>
...

But in this case don't forge that in XPath expressions (we didn't used any in the example) the default XML namespace must be accessed with an explicit D: since names without prefix always refer to nodes with no XML namespace in XPath. Also note that with the same logic as with imperative XML processing, the name of handlers for elements that has no XML namespace is N:elementName if (and only if) there is a default XML namespace. However, for nodes that are not of type element (such as text nodes), you never use the N prefix in the handler name, because those nodes are free of the idea of XML namespaces. So for example, the handler for text nodes is always just @text.

For more detailed information, please read the reference of recurse and visit directives.