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:
<#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:
<#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.