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 ...
随机推荐
- [转]notepad++各种插件
http://www.crifan.com/files/doc/docbook/rec_soft_npp/release/htmls/npp_common_plugins.html
- 关于sqoop与datax。 和sqoop to oracle插件OraOop
之前我还在想了解下datax,是否有可能替换sqoop,但了解后发现,datax和sqoop的业务场景是不同的.前者适合异构数据库的同步,后者适合hdfs与rdbms互相之间的同步.针对sq ...
- 关于Scala JDK与IDEA版本兼容的问题
文章来自:http://www.cnblogs.com/hark0623/p/4174652.html 转发请注明 我刚装上Scala和IDEA时发现运行代码后总是出现 xxx is already ...
- Hark的数据结构与算法练习之简单选择排序
/* * 简单选择排序 */ public class SimpleSort { public static void main(String[] args) { int[] arrayData = ...
- Stay教你程序员泡妞攻略
七天大长假,得瑟的人们又要粗来秀恩爱晒旅途了,苦逼的程序员们要么加班(说好的三倍呢),要么宅家自lu.想想都觉得悲哀.一来我们抱怨生活只有代码,二来只让代码充斥自己的生活.在Stay看来,学会生活要比 ...
- JDK QUEUE队列
Java Queue基础 Queue: 基本上,一个队列就是一个先入先出(FIFO)的数据结构. offer,add区别: 一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被 ...
- 最短路(Bellman_Ford) POJ 3259 Wormholes
题目传送门 /* 题意:一张有双方向连通和单方向连通的图,单方向的是负权值,问是否能回到过去(权值和为负) Bellman_Ford:循环n-1次松弛操作,再判断是否存在负权回路(因为如果有会一直减下 ...
- jQuery Select操作大集合
jQuery获取Select选择的Text和Value: 语法解释: $("#select_id").change(function(){//code...}); //为S ...
- 【wikioi】1913 数字梯形问题(费用流)
http://wikioi.com/problem/1913/ 如果本题没有询问2和3,那么本题和蚯蚓那题一模一样.http://www.cnblogs.com/iwtwiioi/p/3935039. ...
- COJ978 WZJ的数据结构(负二十二)
试题描述 输入两个正整数N.K,以及N个整数Ai,求第K小数. 输入 第一行为两个正整数N.K.第二行为N个正整数Ai. 输出 输出第K小数. 输入示例 5 41 2 3 3 5 输出示例 3 其他说 ...