On this page
Basics
Note:
本部分使用 DOM 树和在上一章中创建的变量。
使用强制性 XML 处理方法(如上一章所示),您可以编写一个 FTL 程序,该程序遍历树以查找不同种类的节点。使用声明性方法,您可以定义如何处理不同类型的节点,然后让 FreeMarker 遍历树并调用您已定义的处理程序。这种方法对于复杂的 XML 模式非常有用,在复杂的 XML 模式中,同一元素可能与许多其他元素的子元素一样出现。这种模式的示例是 XHTML 和 XDocBook。
声明性方法中最常使用的指令是recurse directive。该指令将节点变量作为参数,并从第一个孩子开始一个接一个地“访问”其所有子节点。 “访问”节点意味着它调用一个用户定义的指令(如宏),该指令与子节点的名称(?node_name
)具有相同的名称。我们在此说,用户定义的指令“处理”节点。用户定义指令刚处理的节点可以作为特殊变量.node
来使用。例如,此 FTL:
<#recurse doc>
<#macro book>
I'm the book element handler, and the title is: ${.node.title}
</#macro>
将打印(我从输出中删除了一些令人烦恼的空白):
I'm the book element handler, and the title is: Test Book
如果调用不带参数的recurse
,则它使用.node
,即,它访问当前已处理节点的所有子节点。所以这个 FTL:
<#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>
将打印(我从输出中删除了令人烦恼的空白):
Book element with title Test Book
Title element
Chapter element with title: Ch1
Chapter element with title: Ch2
End book
您已经看到了如何为元素节点定义处理程序,但没有看到如何为文本节点定义处理程序。由于处理程序的名称与其处理的节点的节点名称相同,并且所有文本节点的节点名称均为@text
(请参见the table),因此您可以为文本节点定义处理程序,如下所示:
<#macro @text>${.node?html}</#macro>
请注意?html
。由于生成 HTML 格式的输出,因此必须 HTML 换码文本。
这是将 XML 转换为完整 HTML 的模板:
<#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>
输出将是(现在我将诚实地包含烦人的空白...):
<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>
请注意,您可以使用_作为<#t>
来减少输出中多余的空白量。另请参阅:模板作者指南/其他/空白处理
您可能会说,使用命令式方法进行操作的 FTL 要短得多。没错,但是示例 XML 使用的是非常简单的模式,正如我所说的,声明性方法将其形式带入 XML 模式,这种模式对在哪里出现什么元素不太确定。例如,介绍元素mark
,该元素应将文本颜色更改为红色,而不在您使用的位置进行匹配;在title
或para
中。为此,使用声明性方法,您只需添加一个宏:
<#macro mark><font color=red><#recurse></font></#macro>
然后<mark>...</mark>
将自动在任何地方工作。因此,对于某些 XML 模式,声明性 XML 处理实际上将比命令性 XML 处理更短,更重要的是,FTL 更清晰。由您决定何时使用哪种方法。不要忘记,您可以自由地混合使用这两种方法。假设在元素处理程序中,您可以使用命令式方法来处理该元素的内容。