学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net

1.基本内容

  因为XML处理的方法非常必要--这在前面章节中已经展示-- 编写一个FTL程序来遍历树,为了找到不同种类的结点。而使用声明的方法, 宁愿定义如何控制不同种类的结点,之后让 FreeMarker 遍历那棵树, 调用你定义的处理器。这个方法对于复杂的XML模式非常有用, 相同元素可以作为其他元素的子元素出现。 这样的模式的示例就是XHTML和XDocBook。

  最经常使用来处理声明方式的指令就是 recurse 指令, 这个指令获取结点变量,并把它作为是参数,从第一个子元素开始, 一个接一个地"访问"所有它的子元素。"访问"一个结点意味着它调用了用户自定义的指令 (比如宏),它的名字和子结点(?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(参考该表), 为文本结点定义处理器,可以是这样的:

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

  请注意,可以在输出中使用trim 指令,如 <#t> 来大幅减少多余的空白。参考:模板开发指南/其它/空白处理

  你也许会说FTL处理它的这些必要方法可以更短些。那是对的, 但是示例XML使用了非常简单的模式,正如之前说过的, 声明方法带和XML模式一同来了它的格式, 而这个模式关于这里可以出现什么元素是不固定的。所以, 介绍元素 mark, 应该把文本标记为红色, 而和你在哪儿使用它无关;在 title 或在 para 中。对于这点,使用声明的方法,你可以增加一个宏:

<#macro mark><font color=red><#recurse></font></#macro>

  那么 <mark>...</mark> 将会自动起作用。 所以对于命令式的XML模式,声明的XML处理确实将会很短,而且更重要的是, 对于必要的XML处理,FTL-s会更清晰。但这都依赖于你的决定,什么时候使用哪种方法; 不要忘记你可以自由混合两种方法。也就是说,在一个元素处理器中, 你可以使用命令式的方法来处理元素的内容。

2.具体细节

默认处理器

  对于一些XML结点类型,有默认的处理器, 这会处理你不给这些结点定义处理器的结点 (也就是说,如果没有可用的,和结点名称相同的用户自定义指令)。 这里的结点类型,默认的处理器会做:

  • 文本结点:打印其中的文本。要注意,在很多应用程序中, 这对你来说并不好,因为你应该在你发送它们到输出 (使用 ?html?xml?rtf 等,这基于输出的格式)前转义这些文本。

  • 处理指令结点:如果你定义了自定义指令,可以通过调用处理器调用 @pi,否则将什么都不做(忽略这些结点)。

  • 注释结点,文档类型结点:什么都不做(忽略这些结点)。

  • 文档结点:调用 recurse,也就是说, 访问文档结点的所有子结点。

  元素和属性结点通常将会被XML独立机制处理。也就是, @node_type 将会被调用作为处理器, 如果它没有被定义,那么错误会阻止模板的处理。

  元素结点的情形,这意味着如果你定义了一个称为 @element 的宏(或其他种类的用户自定义指令),没有其他特定的处理器时, 那么它会捕捉所有元素结点。如果你没有 @element 处理器, 那么 必须 为所有可能的元素定义处理器。

  属性结点在 recurse 指令中不可见, 所以不需要为它们编写处理器。

访问单独结点

  使用visit 指令 可以访问单独的结点,而不是结点的子结点: <#visit nodeToVisist>。 有时这会很有用。

XML命名空间

  我们说过对于一个元素的处理器,用户自定义指令(比如宏)的名字就是元素的名字。 事实上,它是元素的完全限定名: prefix:elementName。 这个关于 prefix 的使用规则和命令式处理是相同的。 因此,用户自定义指令 book 仅仅处理不属于任何XML命名空间 (除非你已经定义了默认的XML命名空间)的 book 元素。 所以示例XML将会使用XML命名空间 http://example.com/ebook

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

  那么FTL就会像这样:

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

  或者你可以定义一个默认的XML命名空间, 那后面部分的模板保持和源XML命名空间相同,比如:

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

 <#recurse doc>

 <#macro book>
 ...

  但是这种情形下不要忘了在XPath表达式(我们在默认中没有使用)中, 默认的XML命名空间必须通过明确的 D: 来访问, 因为在XPath中没有前缀的名称通常指代没有XML命名空间的结点。 而且注意到命令式的XML处理也是相同的逻辑,如果(当且仅当)没有默认XML命名空间时, 元素处理器的名字没有XML命名空间是 N:elementName。 然而,对于不是元素类型的结点(比如文本结点),你不能在处理器名称中使用前缀 N,因为这些结点在XML命名空间中是没有这些概念的。 所以对于示例,文本结点的处理器通常就是 @text

译自 Email: ddekany at users.sourceforge.net

freeMarker(十五)——XML处理指南之声明的XML处理的更多相关文章

  1. freeMarker(十四)——XML处理指南之必要的XML处理

    学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net 1.基本内容 假设程序员在数据模型中放置了一个XML文档,就是名为 d ...

  2. Android笔记(四十五) Android中的数据存储——XML(一)DOM解析器

    DOM解析XML在j2ee开发中比较常见,在Dom解析的过程中,是先把dom全部文件读入到内存中,然后使用dom的api遍历所有数据,检索想要的数据,这种方式显然是一种比较消耗内存的方式,对于像手机这 ...

  3. Gradle 1.12用户指南翻译——第六十五章. Maven 发布(新)

    其他章节的翻译请参见:http://blog.csdn.net/column/details/gradle-translation.html翻译项目请关注Github上的地址:https://gith ...

  4. Gradle 1.12用户指南翻译——第四十五章. 应用程序插件

    本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  5. Gradle 1.12用户指南翻译——第二十五章. Scala 插件

    其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://g ...

  6. Gradle 1.12用户指南翻译——第三十五章. Sonar 插件

    本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  7. 第一百二十五节,JavaScript,XML

    JavaScript,XML 学习要点: 1.IE中的XML 2.DOM2中的XML 3.跨浏览器处理XML 随着互联网的发展,Web应用程序的丰富,开发人员越来越希望能够使用客户端来操作XML技术. ...

  8. (十五)xml模块

    xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要 ...

  9. WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇]

    原文:WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇] 在[WS标准篇]中我花了很大的篇幅介绍了WS-MEX以及与它相关的WS规范:WS-Policy.WS-Tra ...

随机推荐

  1. C语言基础知识【判断】

    C 判断1.判断结构要求程序员指定一个或多个要评估或测试的条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的).C 语言把任何非零和非空的值假定为 true,把零或 null ...

  2. 使用Swoole加速Laravel(正式环境中)

    1 Laravel的速度瓶颈在哪? 1.1 已有的一些优化方法 1.1.1 laravel官方提供了一些优化laravel的优化方法 php artisan optimize php artisan ...

  3. CentOS升级Python2.6到Python2.7

    个人博客:https://blog.sharedata.info/ 貌似CentOS 6.X系统默认安装的Python都是2.6版本的?平时使用以及很多的库都是要求用到2.7版本或以上,所以新系统要做 ...

  4. lua(仿类)

    Account = { balance = } function Account:deposit(v) self.balance = self.balance + v end function Acc ...

  5. E - What Is Your Grade?

    E - What Is Your Grade? Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & % ...

  6. php建立一个空类: stdClass

    $pick = new stdClass; $pick->type = 'full'; ;

  7. Android中关于系统Dialog无法全屏的问题(dialog样式)

    自定义一个Dialog,继承了系统Dialog的样式.这时候会发现,即使布局文件中写的width和height都是match_parent,依然无法达到全屏的效果. 原因是:系统dialog的样式.默 ...

  8. Struts详解

    1.什么是MVC? MVC是Model,View,Controller的缩写,MVC是Application开发的设计模式, 也就是大家所知道的Model2.在MVC的设计模式中,它包括三类对象:(1 ...

  9. python 的for else语句

    for中间不是break出来的,是正常循环完跳出循环的会执行else内的语句 while else语句也是如此 这个以前的常见语言没有,特此记录

  10. git入门篇-----本地操作

    一 ,git的简介 1 ,git的历史 概念性的知识,大家百度一下,就会出现好多优秀的文章供参考,这里我就不多说了. 如果不是当年BitMover公司威胁Linux社区,可能现在我们就没有免费而超级好 ...