入职第二周了,在熟悉了公司自动化测试脚本的编写(使用什么数据库,使用哪种语言,框架带了哪些方法)后,现在开始熟悉模拟器,我们把请求发到服务器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的使用的更多相关文章

  1. HTML5标签嵌套规则

    × 目录 [1]分类 [2]子元素 [3]总结 前面的话 在html5中,<a>元素的子元素可以是块级元素,这在以前是被认为不符合规则的.本文将详细介绍html5的标签嵌套规则 分类 ht ...

  2. IE浏览器下a标签嵌套img标签默认带有边框

    最近写在线主页时发现IE浏览器下a标签嵌套img标签默认带有边框: 解决办法:img{border:0 none;} 注意,严格意义上0和none都要加上!

  3. riot.js教程【五】标签嵌套、命名元素、事件、标签条件

    前文回顾 riot.js教程[四]Mixins.HTML内嵌表达式 riot.js教程[三]访问DOM元素.使用jquery.mount输入参数.riotjs标签的生命周期: riot.js教程[二] ...

  4. a标签嵌套解决方案

    在实际网页布局之中,我们有时候需要一整块点击区域中间还要有部分按钮点击,也就是需要a标签嵌套a标签,如下: <!-- a标签进行嵌套的时候 --><a href="#hao ...

  5. web@HTML常用标签分类,标签嵌套规则

    一.html标签又叫做html元素,它分为块级元素和内联元素(也可以叫做行内元素),都是html规范中的概念.1.块级元素块级元素是指本身属性为display:block;的元素.因为它自身的特点,我 ...

  6. a标签嵌套a标签在实际项目开发中遇到的坑

    大家都知道HTML的嵌套规范,其中一个规范是块元素嵌套行内元素,块元素嵌套块元素,行内元素嵌套行内元素,行内元素不能嵌套块元素. 其中需要注意的是行内元素嵌套行内元素,a标签虽然是行内元素,但是a标签 ...

  7. 转:前端页面a标签嵌套a标签效果的两种解决方案

      这是由工作中的一个小改动需求得到的这个解决方案的:那个需求是这样的,如图: 需求原来是球队名字没有点击功能的,而蓝色方框两队之间的比赛点击的时候会跳转到比赛文字直播页面.现在需要要求点击球队名字要 ...

  8. 前端 HTML 标签嵌套规则

    标签嵌套规则 块元素可以包含内联元素或某些块元素,但内联元素却不能包含块元素,它只能包含其它的内联元素,例如: <div><div></div><h1> ...

  9. 第153天:关于HTML标签嵌套的问题详解

    HTML标签 1.块级元素 div.h1~h6.address.blockquote.center.dir.dl.dt.dd.fieldset.form.hr.isindex.menu.noframe ...

随机推荐

  1. 如何应对Session丢失》》State Server

    Session丢失已经是一种习以为常的问题了,在自己也了解一些如何解决的问题,但是也一直没有机会去用,现在由于新的项目要在B/S下开发,所以不得不让我考虑Session的问题. 解决session丢失 ...

  2. 在CentOS 6上搭建私有的Docker Registry

    在CentOS 6上搭建私有的Docker Registry v2Registry概念 :Registry是一个无状态的, 高可扩展的服务器端应用程序, 用于存储和分发Docker Image. 依赖 ...

  3. javascript优化--08模式(代码复用)01

    优先使用对象组合,而不是类继承: 类式继承:通过构造函数Child()来获取来自于另一个构造函数Parent()的属性: 默认模式:子类的原型指向父类的一个实例 function inherit(C, ...

  4. js:数据结构笔记1---数组

    JS中数组: 只是一种特殊的对象,比其他语言中效率低: 属性是用来表示偏移量的索引:在JS中,数字索引在内部被转化为字符串类型(这也是为什么写对象属性的时候可以不叫引号),因为对象中的属性必须是字符串 ...

  5. 简单几何(直线与线段相交) POJ 1039 Pipe

    题目传送门 题意:一根管道,有光源从入口发射,问光源最远到达的地方. 分析:黑书上的例题,解法是枚举任意的一个上顶点和一个下顶点(优化后),组成直线,如果直线与所有竖直线段有交点,则表示能穿过管道. ...

  6. bzoj1021 [SHOI2008]Debt 循环的债务

    前天打了一场比赛,让我知道自己Dp有多弱了,伤心了一天,没刷bzoj. 昨天想了一天,虽然知道几何怎么搞,但我还是不敢写,让我知道自己几何有多弱了,伤心了一天,没刷bzoj 1021: [SHOI20 ...

  7. 数据挖掘十大经典算法[0]-K-Means算法

    K-Means算法的输入N,K和一个size为N的向量组vector.输出K个两两互不相交的向量组.其本质是将给定的向量组划分成K个类别,使得同类别的向量相似度比较大,而不同类别的向量之间的相似度较小 ...

  8. Ubuntu 12.04安装Google Chrome

    详细请参照:http://hi.baidu.com/kevin276/item/29bc1c96a208fabc82d29542 至于安装之后怎么打开,在终端输入google-chrome即可打开并会 ...

  9. juniper防火墙 L2TP VPN配置

    juniper防火墙 L2TP  VPN配置 建立L2TP_POOL 创建连接的用户: 创建用户组: 更改L2TP的连接池: 更改L2TP的隧道: 设置防火墙的策略: Win7连接:

  10. windows渗透被人忽视的一些小命令

    cmdkey /list 可以列出域内网之间可用的凭据. wmic   useraccount get name,sid gpresult /r