}
class Type3 {
public Type1 Field31; }
[代码6]
如果各位有意向把Type2提到跟Type1和Type3同一级别的位置,那么我们要继续修改代码了。把代码2的 <#recurse doc>行(第5行)修改成如下:
<#assign inner_types=pp.newWritableHash()> <#-- 调用fmpp功能函数,生成一个可写的hash -->
<#recurse doc> <#-- 根入口,代码1部分的xml存放在变量doc中,doc变量的填充由fmpp根据config.fmpp中的配置进行 --> <#if inner_types?size gt 0 > <#-- 如果存放有类型 --> <#list inner_types?values as node> <#-- 遍历哈西表的值 -->
<#visit node> <#-- 激活相应的macro处理,类似于xslt的apply-template。大家把visit改成recurse看一下不同的效果 --> #list> #if> [代码7]
11
同时把macro ns:field(第18行)修改成如下:
<#macro \
public ${.node.@type} ${.node.@name};
<#if .node[\如果当前节点下存在type节点 -->
<#local t = .node[\
<@pp.set hash=inner_types key=\哈西表中增加内容,key为嵌套类型的name属性,value为该类型节点 --> #if> #macro>
[代码8]
运行得到输出文件类似这样:
class Type1 {
public Float Field11; public String Field12; public Integer Field13; public Type2 Field14; public Float Field15; }
12
class Type3 {
public Type1 Field31; }
class Type2 {
public String Field21; public Integer Field22; }
[代码9]
大家比较一下,看看我们修改的地方出现了哪些效果?然后记得大家要做另外2件事情,
1。把第一行修改成为<#ftl ns_prefixes={\,然后把所有的 <#macro \修改成<#macro type>,把所有
的.node[\修改成 .node.type,看看能不能运行?是不是觉得简单方便些了?记住,第一行的那个D表示是default namespace的意思哦。
2。在第二行插入<#compress>,在最后一行添加#compress>。再运行一下看看结果有什么不同?
一个例子下来,大家基本对freemaker有了一些感觉了,为了纠正大家认为
13
freemaker就是一个xml处理工具的误解,我们再来做一个简单的实验。这次我们要做的是一个正常的编程题目,做一个100以内的Fibonacci数列的程序。程序如下:
迭代次数: <#list 1 .. 10 as n> ${n} = ${fibo(n)} #list>
<#compress> <#function fibo n> <#if n lte 1> <#return 1> <#elseif n = 2> <#return 1> <#else>
<#return fibo(n-1) + fibo(n-2)> #if> #function> #compress>
[代码10]
14
这个例子里边有一些问题需要注意,大家看我的 #if n lte 1 这一行,为什么我这么写?因为常规的大于小于号和xml的节点有冲突,为了避免问题,所以用 gt(>) gte(>=) lt(<) lte(<=) 来代表。
另外,复杂的字符串处理如何来做?就留作家庭作业吧,大家记得取substr的方法是 str[first .. last] 就可以了。如下的例子可能会给你一点提示:
<#assign str = \<#assign mid = (str?length + 1)/2-1 > <#list mid .. 0 as cnt>
${str[(mid - cnt) .. (mid + cnt)]?left_pad(mid*2)} #list>
[代码11]
最后,说一下非常有用的macro的nested指令,没有它,也许freemaker会失去大部分的魅力。我个人认为这也是freemaker全面超越velocity的地方。大家先看一下代码:
<#assign msg = \<@macro0 ; index > ${msg} ${index} @macro0>
<#macro macro0>
15