freeMarker(十五)——XML处理指南之声明的XML处理
2017-01-18 14:08
274 查看
学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net
最经常使用来处理声明方式的指令就是
将会输出(这里已经移除了输出内容中一些烦扰的空白):
如果调用
将会输出(这里已经移除了输出内容中一些烦扰的空白):
已经看到了如何来为元素结点定义处理器,但不是为文本结点定义处理器。 因为处理器的名字是和它处理的结点名字相同的,作为所有文本结点的结点名字是
请注意
这个模板就是转换XML到完整的HTML:
将会输出(这里包含了那些烦扰的空白):
请注意,可以在输出中使用trim 指令,如
你也许会说FTL处理它的这些必要方法可以更短些。那是对的, 但是示例XML使用了非常简单的模式,正如之前说过的, 声明方法带和XML模式一同来了它的格式, 而这个模式关于这里可以出现什么元素是不固定的。所以, 介绍元素
那么
文本结点:打印其中的文本。要注意,在很多应用程序中, 这对你来说并不好,因为你应该在你发送它们到输出 (使用
处理指令结点:如果你定义了自定义指令,可以通过调用处理器调用
注释结点,文档类型结点:什么都不做(忽略这些结点)。
文档结点:调用
元素和属性结点通常将会被XML独立机制处理。也就是,
元素结点的情形,这意味着如果你定义了一个称为
属性结点在
那么FTL就会像这样:
或者你可以定义一个默认的XML命名空间, 那后面部分的模板保持和源XML命名空间相同,比如:
但是这种情形下不要忘了在XPath表达式(我们在默认中没有使用)中, 默认的XML命名空间必须通过明确的
译自 Email: ddekany at users.sourceforge.net
1.基本内容
因为XML处理的方法非常必要--这在前面章节中已经展示-- 编写一个FTL程序来遍历树,为了找到不同种类的结点。而使用声明的方法, 宁愿定义如何控制不同种类的结点,之后让 FreeMarker 遍历那棵树, 调用你定义的处理器。这个方法对于复杂的XML模式非常有用, 相同元素可以作为其他元素的子元素出现。 这样的模式的示例就是XHTML和XDocBook。最经常使用来处理声明方式的指令就是
recurse指令, 这个指令获取结点变量,并把它作为是参数,从第一个子元素开始, 一个接一个地"访问"所有它的子元素。"访问"一个结点意味着它调用了用户自定义的指令 (比如宏),它的名字和子结点(
?node_name)的名字相同。 我们这么说,用户自定义指令操作结点。使用用户自定义指令 处理 的结点作为特殊变量
.node是可用的。例如,这个FTL:
1 <#recurse doc> 2 3 <#macro book> 4 I'm the book element handler, and the title is: ${.node.title} 5 </#macro>
将会输出(这里已经移除了输出内容中一些烦扰的空白):
I'm the book element handler, and the title is: Test Book
如果调用
recurse而不用参数,那么它使用
.node,也就是说,它访问现在处理这个结点的所有子结点。 所以这个FTL:
1 <#recurse doc> 2 3 <#macro book> 4 Book element with title ${.node.title} 5 <#recurse> 6 End book 7 </#macro> 8 9 <#macro title> 10 Title element 11 </#macro> 12 13 <#macro chapter> 14 Chapter element with title: ${.node.title} 15 </#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:
1 <#recurse doc> 2 3 <#macro book> 4 <html> 5 <head> 6 <title><#recurse .node.title></title> 7 </head> 8 <body> 9 <h1><#recurse .node.title></h1> 10 <#recurse> 11 </body> 12 </html> 13 </#macro> 14 15 <#macro chapter> 16 <h2><#recurse .node.title></h2> 17 <#recurse> 18 </#macro> 19 20 <#macro para> 21 <p><#recurse> 22 </#macro> 23 24 <#macro title> 25 <#-- 26 We have handled this element imperatively, 27 so we do nothing here. 28 --> 29 </#macro> 30 31 <#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就会像这样:
1 <#ftl ns_prefixes={"e":"http://example.com/ebook"}> 2 3 <#recurse doc> 4 5 <#macro "e:book"> 6 <html> 7 <head> 8 <title><#recurse .node["e:title"]></title> 9 </head> 10 <body> 11 <h1><#recurse .node["e:title"]></h1> 12 <#recurse> 13 </body> 14 </html> 15 </#macro> 16 17 <#macro "e:chapter"> 18 <h2><#recurse .node["e:title"]></h2> 19 <#recurse> 20 </#macro> 21 22 <#macro "e:para"> 23 <p><#recurse> 24 </#macro> 25 26 <#macro "e:title"> 27 <#-- 28 We have handled this element imperatively, 29 so we do nothing here. 30 --> 31 </#macro> 32 33 <#macro @text>${.node?html}</#macro>
或者你可以定义一个默认的XML命名空间, 那后面部分的模板保持和源XML命名空间相同,比如:
1 <#ftl ns_prefixes={"D":"http://example.com/ebook"}> 2 3 <#recurse doc> 4 5 <#macro book> 6 ...
但是这种情形下不要忘了在XPath表达式(我们在默认中没有使用)中, 默认的XML命名空间必须通过明确的
D:来访问, 因为在XPath中没有前缀的名称通常指代没有XML命名空间的结点。 而且注意到命令式的XML处理也是相同的逻辑,如果(当且仅当)没有默认XML命名空间时, 元素处理器的名字没有XML命名空间是
N:elementName。 然而,对于不是元素类型的结点(比如文本结点),你不能在处理器名称中使用前缀
N,因为这些结点在XML命名空间中是没有这些概念的。 所以对于示例,文本结点的处理器通常就是
@text。
译自 Email: ddekany at users.sourceforge.net
相关文章推荐
- freeMarker(十三)——XML处理指南之揭示XML文档
- freeMarker(十四)——XML处理指南之必要的XML处理
- CSS权威指南之css声明,伪类,文本处理--(简要笔记一)
- xml--语法01--文档声明(乱码处理)
- (七)freeMarker之XML处理
- xml声明、处理指令
- EXIF格式分析及通过XML处理(1)
- [导入]利用xslt对xml进行缩进格式化处理
- XML文件处理的思考[2004年5月11日 10:18]
- 利用xslt对xml进行缩进格式化处理
- XML中二进制数据的处理方法[转载]
- EXIF格式分析及通过XML处理(2)
- 使用XMLBeans处理XML数据和文档入门 作者:肖菁 (dev2dev ID: powerise) 湖南省长沙铁道学院科创计算机系统集成有限公司软件中心软件工程师
- 利用xslt对xml进行缩进格式化处理
- XML文件处理的思考
- 利用xslt对xml进行缩进格式化处理
- XML + XSL + JS 构建小型Web App (十五)
- .NET中用于处理XML的方法和相关类
- EXIF格式分析及通过XML处理(4)
- Henry的VB.NET之旅(十五)—动态事件处理方法