Freemarker的初次使用之FTL标签嵌套与map的使用
入职第二周了,在熟悉了公司自动化测试脚本的编写(使用什么数据库,使用哪种语言,框架带了哪些方法)后,现在开始熟悉模拟器,我们把请求发到服务器1,服务器1根据请求参数处理后将结果发给模拟器,模拟器根据服务器1的处理结果再次调用脚本进行处理,然后将结果返回。我需要做的就是编写模拟器所调用的脚本。前两天使用的是SimpleTemplateEngine模版,进行简单的处理,然后周三的时候换成FreemarkerTemplate模版来进行处理。
Freemarker这个我以前根本就没接触,赶紧从官网下载资料学习,而在这个过程中,我看到网上有几篇帖子批评Freemarker(比如这个帖子:http://flym.iteye.com/blog/750454),其中有一点是“3.2 map问题,即freemarker中不能支持非string的key值,这样在进行一些复杂迭代时就需要作一些其他的转换,如将一个map拆分为两个或多个map。”唉,当时眼花了,以为是freemarker中不能支持非String的value值。然后又从官网文档中看到FTL标签不可以在其他FTL标签和插值中使用。而我要完成的任务是分别将RoomTypeCandidates、RatePlanCandidates、LOSCandidate的子节点的文本保存成列表,
<RoomTypeCandidates>
<RoomTypeCandidate>2QueenBalconyOr</RoomTypeCandidate>
<RoomTypeCandidate>1King</RoomTypeCandidate>
<RoomTypeCandidate>1KingAccessible</RoomTypeCandidate>
</RoomTypeCandidates>
<RatePlanCandidates>
<RatePlanCandidate>HiltonFlexibleRetail</RatePlanCandidate>
<RatePlanCandidate>HiltonAdvanceLongRetail</RatePlanCandidate>
</RatePlanCandidates>
<LOSCandidates>
<LOSCandidate>1</LOSCandidate>
<LOSCandidate>2</LOSCandidate>
<LOSCandidate>3</LOSCandidate>
然后将结果<RoomStay RoomTypeCode="RoomTypeCandidate" RatePlanCode="RatePlanCandidate" LengthOfStay="LOSCandidate" RoomCount="9">中。从给我的结果文件来看,需要输出RoomTypeCandidates、RatePlanCandidates、LOSCandidate的所有排列组合,也就是3*2*3次。模版文件只能有这一行。 这样的话我就不得不在模版中使用list,而map的value也不可避免要使用list类型,并且FTL标签肯定要嵌套。当时心里只有个想法,这完全不科学啊,于是我在将文本取出存入list后就不知道该怎么办了,赶紧问带我的师傅拿份模版和脚本的样例。
在看那份脚本的样例时,我心凉了半截,因为连我这个门外汉都看出来这个脚本太不正规了,有一个方法跟另一个方法功能重复(不是重载),还有一个方法,居然在迭代循环中把同样的key和不同的value存入hashMap中。没办法,硬着头皮看下去,发现对方直接将json存入map中然后用Freemarker调用,Freemarker模版也是FTL标签嵌套(<#list ...><#list ...></#list></#list>).赶紧向师傅提出疑问,师傅只是让我试试。我想试试就试试吧。我于是往map的value中存入list,然后也是用FTL标签嵌套。结果居然成了。
现在看看官网文档
FTL标签不可以在其他FTL标签和插值中使用。下面这样写就是错的:
<#if <#include 'foo'>='bar'>...</#if> 也许<#include 'foo'>是在<#if和>中间,而不是<#if>和</#if>中间,官网才说它是错的
我把我写的脚本贴上来,感兴趣的朋友可以试试,文件路径自己改。
Groovy脚本:
import freemarker.template.Configuration
import freemarker.template.Template
import groovy.text.SimpleTemplateEngine
import org.dom4j.DocumentException
import org.dom4j.DocumentHelper
import org.jaxen.JaxenException
import org.jaxen.SimpleNamespaceContext
import org.jaxen.XPath
import org.jaxen.dom4j.Dom4jXPath
import org.dom4j.Element
import org.dom4j.io.SAXReader
import org.dom4j.Document
import org.joda.time.LocalDate
import javax.xml.xpath.XPathConstants
import javax.xml.xpath.XPathFactory
import com.derby.nuke.common.module.config.ApplicationConfiguration
public class XMLUtil {
private static final HashMap<String, String> NAMESPACES = new HashMap<String, String>()
static {
NAMESPACES.put("ari", "http://www.XXX.com/nuke/ari")
NAMESPACES.put("rac", "http://www.XXX.com/dswitch/rac")
NAMESPACES.put("ota", "http://www.XXX.org/OTA/2003/05")
NAMESPACES.put("", "")
}
public static List<Element> getElements(Document document,
String xpathString) throws JaxenException {
XPath xpath = new Dom4jXPath(xpathString)
xpath.setNamespaceContext(new SimpleNamespaceContext(NAMESPACES))
return xpath.selectNodes(document)
}
public static String getElementAttribute(String attribute,
Document document, String xpathString) throws JaxenException {
XPath xpath = new Dom4jXPath(xpathString)
xpath.setNamespaceContext(new SimpleNamespaceContext(NAMESPACES))
Element element = (Element) xpath.selectSingleNode(document)
if (element == null) {
return null
}
return element.attributeValue(attribute)
}
public List<String> getElementTextList(Document doc,String xpathString){
List<String> ls=new ArrayList()
List<Element> le=XMLUtil.getElements(doc, xpathString)
if(le.size()!=0){
for(Element e:le){
ls.add(e.getText())
}
return ls
}else{
return null
}
}
public String useFreemarkerTemplate(request){
Document doc=DocumentHelper.parseText(request)
List roomTypeCandidateList=getElementTextList(doc,"//ari:RoomTypeCandidate")
List ratePlanCandidateList=getElementTextList(doc,"//ari:RatePlanCandidate")
List lOSCandidateList=getElementTextList(doc,"//ari:LOSCandidate")
String hotelCode=XMLUtil.getElementAttribute("HotelCode",doc,"//ari:RetrieveChangeCriteria")
String start=XMLUtil.getElementAttribute("Start",doc,"//ari:DateSpan")
String end=XMLUtil.getElementAttribute("End",doc,"//ari:DateSpan")
Map responsemap=new HashMap();
responsemap.put("HotelCode",hotelCode);
responsemap.put("Start",start);
responsemap.put("End",end);
responsemap.put("roomTypeCandidateList",roomTypeCandidateList);
responsemap.put("ratePlanCandidateList",ratePlanCandidateList);
responsemap.put("lOSCandidateList",lOSCandidateList);
Configuration config=new Configuration();
// String resourceHome = ApplicationConfiguration.get().getApplicationConfigDirectory() + "/dispatch/";
String resourceHome ="D:/testTool/apache-tomcat-7.0.61/person/simulator/dispatch"
config.setDirectoryForTemplateLoading(new File(resourceHome));
config.setDefaultEncoding("UTF-8");
Template templateFile=config.getTemplate("_simulator_justtest.xml");
StringWriter writer = new StringWriter();
templateFile.process(responsemap, writer);
return writer.toString();
}
String request="""<?xml version="1.0" encoding="UTF-8"?>
<soap11:Envelope xmlns="http://www.derbysoft.com/nuke/ari" xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/">
<soap11:Body>
<GetDailyChangeRequest Token="293FE0D7-CBB7-4035-B76A-DE6E24FEFF0D">
<Contract ChannelCode="AA9011CA33A2E854774EA76F2EBF423336C6" SupplierCode="HILTON"/>
<RetrieveChangeCriteria HotelCode="code01" Type="All">
<DateSpan Start="2016-04-04" End="2016-04-16"/>
<RoomTypeCandidates>
<RoomTypeCandidate>2QueenBalconyOr</RoomTypeCandidate>
<RoomTypeCandidate>1King</RoomTypeCandidate>
<RoomTypeCandidate>1KingAccessible</RoomTypeCandidate>
</RoomTypeCandidates>
<RatePlanCandidates>
<RatePlanCandidate>HiltonFlexibleRetail</RatePlanCandidate>
<RatePlanCandidate>HiltonAdvanceLongRetail</RatePlanCandidate>
</RatePlanCandidates>
<LOSCandidates>
<LOSCandidate>1</LOSCandidate>
<LOSCandidate>2</LOSCandidate>
<LOSCandidate>3</LOSCandidate>
<LOSCandidate>4</LOSCandidate>
<LOSCandidate>5</LOSCandidate>
</LOSCandidates>
<Properties/>
</RetrieveChangeCriteria>
</GetDailyChangeRequest>
</soap11:Body>
</soap11:Envelope>
"""
println useFreemarkerTemplate(request)
下面是Freemarker的模版
<?xml version="1.0" encoding="UTF-8"?>
<soap11:Envelope xmlns="http://www.XXX.com/nuke/ari" xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/">
<soap11:Body>
<GetAvailabilityChangeResponse>
<#-- input hotelcode -->
<AvailabilityUpdate HotelCode="${HotelCode}">
<RoomStays>
<#list roomTypeCandidateList as rtcList>
<#list ratePlanCandidateList as rpcList>
<#list lOSCandidateList as loscList>
<RoomStay RoomTypeCode="${rtcList}" RatePlanCode="${rpcList}" LengthOfStay="${loscList}" RoomCount="9">
<#-- input startdate and enddate -->
<DateSpan Start="${Start}" End="${End}"/>
</RoomRate>
</DateSpan>
</RoomStay>
</#list>
</#list>
</#list>
</RoomStays>
</GetAvailabilityChangeResponse>
</soap11:Body>
</soap11:Envelope>
Freemarker的初次使用之FTL标签嵌套与map的使用的更多相关文章
- HTML5标签嵌套规则
× 目录 [1]分类 [2]子元素 [3]总结 前面的话 在html5中,<a>元素的子元素可以是块级元素,这在以前是被认为不符合规则的.本文将详细介绍html5的标签嵌套规则 分类 ht ...
- IE浏览器下a标签嵌套img标签默认带有边框
最近写在线主页时发现IE浏览器下a标签嵌套img标签默认带有边框: 解决办法:img{border:0 none;} 注意,严格意义上0和none都要加上!
- riot.js教程【五】标签嵌套、命名元素、事件、标签条件
前文回顾 riot.js教程[四]Mixins.HTML内嵌表达式 riot.js教程[三]访问DOM元素.使用jquery.mount输入参数.riotjs标签的生命周期: riot.js教程[二] ...
- a标签嵌套解决方案
在实际网页布局之中,我们有时候需要一整块点击区域中间还要有部分按钮点击,也就是需要a标签嵌套a标签,如下: <!-- a标签进行嵌套的时候 --><a href="#hao ...
- web@HTML常用标签分类,标签嵌套规则
一.html标签又叫做html元素,它分为块级元素和内联元素(也可以叫做行内元素),都是html规范中的概念.1.块级元素块级元素是指本身属性为display:block;的元素.因为它自身的特点,我 ...
- a标签嵌套a标签在实际项目开发中遇到的坑
大家都知道HTML的嵌套规范,其中一个规范是块元素嵌套行内元素,块元素嵌套块元素,行内元素嵌套行内元素,行内元素不能嵌套块元素. 其中需要注意的是行内元素嵌套行内元素,a标签虽然是行内元素,但是a标签 ...
- 转:前端页面a标签嵌套a标签效果的两种解决方案
这是由工作中的一个小改动需求得到的这个解决方案的:那个需求是这样的,如图: 需求原来是球队名字没有点击功能的,而蓝色方框两队之间的比赛点击的时候会跳转到比赛文字直播页面.现在需要要求点击球队名字要 ...
- 前端 HTML 标签嵌套规则
标签嵌套规则 块元素可以包含内联元素或某些块元素,但内联元素却不能包含块元素,它只能包含其它的内联元素,例如: <div><div></div><h1> ...
- 第153天:关于HTML标签嵌套的问题详解
HTML标签 1.块级元素 div.h1~h6.address.blockquote.center.dir.dl.dt.dd.fieldset.form.hr.isindex.menu.noframe ...
随机推荐
- Eclipse中导入外部jar包
首先在项目下创建一个文件夹,保存我们的jar包. 在项目名上右击,依次点击[New]-->[Floder],打开新建文件夹窗口 输入文件夹名称[lib],点击[ok].我们通常在lib文件夹 ...
- easyui的combobox下拉框初始化默认值以及保持该值一直显示的方法
easyui的combobox下拉框默认初始值是空,下面是实现从远程加载数据之后初始化默认值,以及让该值一直排在下拉框的最顶部的方式. 目前的需求是需要在初始化的时候添加"全部数据库&quo ...
- POJ1845 Sumdiv(求所有因数和+矩阵快速幂)
题目问$A^B$的所有因数和. 根据唯一分解定理将A进行因式分解可得:A = p1^a1 * p2^a2 * p3^a3 * pn^an.A^B=p1^(a1*B)*p2^(a2*B)*...*pn^ ...
- silverlinght 项目
silverlinght项目演示: 打开点击其中一个:
- Leetcode 第一遍刷完
2014/10/15 Leetcode第一刷总算结束,时间拖太长了,希望第二遍能快一点,争取一个月能刷完第二遍??哈哈哈哈
- Qt Creator 快捷键
Qt Creator 你必须要掌握的快捷操作 http://jingyan.baidu.com/article/6fb756ecab5158241858fbb0.html 多使用快捷键能显著提高工作效 ...
- SecureCrt脚本(一)顶级对象之Crt
Crt自动化 测试 SecureCrt脚本 JS脚本 1.引言 2.关于脚本表头 3.顶级对象'crt'的子属性和方法 3.1.属性 3.1.1.Dialog 3.1.2.Screen 3.1.3 ...
- e.KeyChar用到的键盘对应ASCII码值(转)
十进制编码 (对应)缩写字符(或功能/解释) 0 NUL(null) 空字符 1 SOH(start of headline) 标题开始 2 STX (start of text) 正文开 ...
- php中alert弹出时单双引号问题
php代码中单双引号问题是个很重要的问题,使用不当会造成很多麻烦.先记录一下今天写alert遇到的麻烦.我做登录的时候,成功时想弹出个提示说登录成功.写alert语句时不显示.其实就是单双引号弄得不对 ...
- php的具体配置学习笔记
1.将php配置为apache的一个模块,使用loadmodule指令完成. 2.写下面的语句,此外需强调的是,每次配置都需要重新启动apache 3.php文件,要指定将其php模块来处理 4.PH ...