我们使用如下示例的XML文档:
<book>
<title>Test Book</title>
<chapter>
<title>Ch1</title>
<para>p1.1</para>
<para>p1.2</para>
<para>p1.3</para>
</chapter>
<chapter>
<title>Ch2</title>
<para>p2.1</para>
<para>p2.2</para>
</chapter>
</book>W3C 的 DOM 定义XML文档模型为结点树。上面XML的结点树可以被视为:
document
|
+- element book
|
+- text "\n "
|
+- element title
| |
| +- text "Test Book"
|
+- text "\n "
|
+- element chapter
| |
| +- text "\n "
| |
| +- element title
| | |
| | +- text "Ch1"
| |
| +- text "\n "
| |
| +- element para
| | |
| | +- text "p1.1"
| |
| +- text "\n "
| |
| +- element para
| | |
| | +- text "p1.2"
| |
| +- text "\n "
| |
| +- element para
| |
| +- text "p1.3"
|
+- element
|
+- text "\n "
|
+- element title
| |
| +- text "Ch2"
|
+- text "\n "
|
+- element para
| |
| +- text "p2.1"
|
+- text "\n "
|
+- element para
|
+- text "p2.2"请注意,烦扰的 "\n " 是行的中断
(这里用 \n 指示,在FTL字符串中使用转义序列)
和标记直接的缩进空格。
请注意和DOM相关的术语:
-
一棵树最上面的结点称为根 root,在XML文档中,它通常是"文档"结点, 而不是最顶层元素(本例中的
book)。 -
如果B是A的 直接 后继, 我们说B结点是A结点的子结点 child。比如, 两个
chapter元素是book元素的子结点, 但是para元素就不是。 -
如果A是B的 直接 前驱,也就是说, 如果B是A的子结点,我们说结点A是结点B的父结点 parent。比如,
book元素是两个chapter元素的父结点, 但是它不是para元素的父结点。 -
XML文档中可以出现几种成分,比如元素,文本,注释,处理指令等。 所有这些成分都是DOM树的结点,所以就有元素结点,文本结点,注释结点等。 原则上,元素的属性也是树的结点--它们是元素的子结点--, 但是,通常我们(还有其他XML相关的技术)不包含元素的子结点。 所以基本上它们不被记为子结点。
程序员将DOM树的文档结点放到 FreeMarker 的数据模型中, 那么模板开发人员可以以变量为出发点来使用DOM树。
FTL中的DOM结点和 node variables
结点变量对应。这是变量类型,和字符串,数字,哈希表等类型相似。
结点变量类型使得 FreeMarker 来获取一个结点的父结点和子结点成为可能。
这是技术上需要允许模板开发人员在结点间操作,也就是,使用node 内建函数 或者 visit 和
recurse
指令;我们会在后续章节中展示它们的使用。