Scriptmark模板引擎

1.什么是 Scriptmark

Scriptmark 是一款模板引擎:一种基于模板的、用来生成输出文本(任何来自于 HTML 格式的文本用来自动生成源代码)的通用工具。它是为 Java 程序员提供的一个开发包或者说 是类库。 它不是面向最终用户, 而是为程序员提供的可以嵌入他们开发产品的一款应用程序。 Scriptmark 的设计实际上是被用来生成 HTML 网页, 尤其是通过基于实现了 MVC(Model View Controller, 模型-视图-控制器)模式的应用程序。 使用 MVC 模式的动态网页的构 思使得你可以将前端设计者(编写 HTML)从程序员中分离出来。所有人各司其职,发挥其擅 长的一面。 网页设计师可以改写页面的显示效果而不受程序员编译代码的影响, 因为应用程 序的逻辑(Java 程序)和页面设计(Scriptmark 模板)已经分开了。页面模板代码不会受到复杂 的程序代码影响。 这种分离的思想即便对一个程序员和页面设计师是同一个人的项目来说都 是非常有用的,因为分离使得代码保持简洁而且便于维护。 尽管 Scriptmark 也有编程能力,内置Javascript引擎,可以像 PHP 那样的一种全面的编程语言。 类似(node.js)但目前主要用于HTML的模板生成,反而Java 程序准备的数据来显示(比如 SQL 查询), 目前主要使用Scriptmark 仅仅使用模板生成文本在页面来呈现,已经准备好的数据。 Scriptmark 不是 Web 应用框架。它是 Web 应用框架中的一个适用的组件,但是 Scriptmark 引擎本身并不知道 HTTP 协议或 Servlet。它仅仅来生成文本。即便这样,它也非 常适用于非 Web 应用环境的开发。要注意的是,我们使用 Scriptmark 作为视图层组件,是 为给如 Struts 这样的 Model 2 框架提供现成的解决方案,Scriptmark 是开源的。 jspx.net 构架最初是使用的Freemarker模板做为本构架引擎。但因为扩展不方便,不能够达到我要求的整合程度所以就放弃了Freemarker。 这之前也考虑了Common Template Language(CTL)模板,虽然它能够有语法外套,但可能是使用习惯了Freemarker。 所以还是偏重Freemarker的标识方式。velocity这些模板的语法感觉更是丑。但 Freemarker的标签并不标准。 所以就产生了scriptmark这个模板引擎。scriptmark的标签和Freemarker差不多。 但是是标准的xml.脚本引擎是使用的javascript引擎, 可以在模板中方便的使用javascript语法和函数。因为能够使用javascript语法和函数。 所以Freemarker的BuildIn函数处理部分就没有了, 统一使用javascript的库实现。 比如求结对值 ${-21321.abs()} 这样就可以了. 日期格式化 ${date.string('yyyy-MM-dd')} 这样用法优美很多。 严格的来说scriptmark是Freemarker的一个替代。scriptmark比Freemarker的功能丰富很多,并且更容易扩展自己的函数功能,性能相当。

2.性能说明

本人对很多模板做了,多线程并发测试,Freemaker 表现相当优秀,而网上一些朋友在单线程下比较,说得Freemaker 一文不值, 我在多线程,交叉模板方式下测试Freemaker 性能相当好, scriptMaker 在高压的时候约有优势,低压要弱一些,总体差不多。 本测试是在2012年:

3.调用模板引擎调用例子

这里演示了如何调用模板引擎:
     TemplateConfigurable configurable = new TemplateConfigurable();
    //这里可以是文件 FileSource  JarSource 模版来源
    Source reader = new StringSource("模板字符串"); 
    ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine(ScriptmarkEnv.noCache, reader, configurable);  
    Writer writer = new StringWriter();  
    scriptMarkEngine.process(writer, map);  
    writer.close();  
    writer.toString();  

4.注释及说明

<!--#注释说明#-->

 在5.2以前版本 使用 <#-->注释说明</#-->,  在5.2+版本 使用<!--#注释说明#-->,目的是为了兼容HTML的注释方式,但使用效果不同。

<!--#注释说明#--> 格式的注释,在执行后将被过滤掉,一般用在不希望别人看到的注释。如果使用html的格式<!--注释说明-->,那么执行后会输出。

5.模板+数据模型 = 输出

假设你在一个在线商店的应用系统中需要一个 HTML 页面,和下面这个页面相似: 比方说,用户名(所有的”Big Joe”)应该是登录这个网页访问者的名字,最新产品的数 据应该来自于数据库,这样它才可以随时更新。在这样的情况下你不能在 HTML 页面中直接 输入登录的用户名,最新产品的 URL 和名称,你不能使用静态的 HTML 代码,那样是不能即 时改变的。 对于这个问题,ScriptMark 的解决方案是使用模板来代替静态 HTML 文本。模板文件同 样是静态的HTML代码, 但是除了这些HTML代码外, 代码中还包括了一些 ScriptMark指令, 这些指令就能够做到动态效果。
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome Big Joe!</h1>
<p>Our latest product:
<a href="products/greenmouse.html">green mouse</a>!
</body>
</html> 
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome ${user}!</h1>
<p>Our latest product:
<a href="${product.url}">${product.name}</a>!
</body>
</html> 
这个模板存放在 Web 服务器上,看上去像是静态的 HTML 页面。但是不管何时,只要有人访问这个页面时,ScriptMark将会介入执行, 然后动态转换模板,用最新的数据内容替换${…}中的部分(例如:用 Big Joe 或者其他的访问者的用户名来代替${user}) , 生成普通的HTML 文本并发送结果到访问者的 Web 浏览器中去显示。所以访问者的 Web 浏览器会接收到类似于第一个 HTML 示例的内容(也就是说,显示普通的 HTML 文本而没有 ScriptMark的指令) ,浏览器也不会感知到ScriptMark 在服务器端被调用了。模板文件本身(存储在Web 服务器端的文件)在这个过程中也不会改变什么,所以这个转换过程发 生在一次又一次的访问中。这样就保证了显示的信息总是即时的。现在,你也许已经注意到, 该模板并没有包含关于如何找出当前的访问者是谁,或者是如何去查询数据库查找最新的产品的指令。它似乎已经知道了这些数据。 确实是这样,ScriptMark 背后(确切的说是 MVC 模式的背后)的重要思想就是表现逻辑和业务逻辑相分离。在模板只是处理显示问题, 也就是视觉设计问题和格式问题。所准备要显示的数据(如用户名等)与 ScriptMark 无关,这通常是使用 Java 语言或其他目的语言来编写的。所以模板开发者不需要关心这些数值是如何计算出来的。事实上,在模板保持不变的同时,这些数 值的计算方式可以完全发生变化。而且,除了模板外,页面外观发生的变化可以完全不触碰其他任何东西。 当模板开发者和程序员是不同一个人的时候, 分离带来的好处更是显而易见的。 ScriptMark(还有模板开发者)并不关心数据是如何计算的,ScriptMark 只是知道真实的数据是什么。 模板能用的所有数据被包装成 data-model 数据模型。数据模型的创建是通过已经存在的程序计算得到的。 至于模板开发者,数据模型像是树状结构(比如硬盘上的文件夹和文件) ,正如本例中的数据模型,就可以如下形式来描述: (为了避免误解:数据模型并不是文本文件,上面所描述的只是一种数据模型的表现形式。 它来自于 Java 对象,但这会成为 Java 程序员要面对的问题。 ) 比较之前你在模板中看到的 ${user} 和 ${product.name} 。作为一种比喻: 数据模型就像计算机文件系统上的内容:根 root 和 product 对应目录(文件夹) , user , url 和 name 对应文件。 url 和 name 在 product 目录中,所以 product.name 就像是说 product 目录的 name 一样。 但是我所说的,这仅仅是个比喻,这里并没有真实的文件和目录。概括地讲,模板和数据模型是 product 所需, 并用来生成输出内容的(比如之前展示的 HTML) :模板+数据模型=输出

6.if 语法

使用 if 指令可以有条件地跳过模板的一部分,这和程序语言中 if 是相似的。假设在第一个示例中,你只想向你的老板 Big Joe (而不是其他人)问好,就可以这样做: 在这里, 我们告诉 ScriptMark 我们尊敬的领导才是 if 条件中那唯一的 user 变量值, 当它和” Big Joe ”相同时才显示出来。那么,当 condition 的判断结果为 false(布尔 值)时,在 <#if where="condition"> 和 标签之间的内容将会被略过。 我们来详细说说 condition 的使用: == 是来判断在它两侧的值相等的操作符,比较的结 果是布尔值,true 或者 false。在 == 的左侧,是引用的变量,我们很熟悉这样的语法,它会 被变量的值来替代。右侧是指定的字符串,在模板中的字符串必须放在引号内。 当 price 是 0 的时候,下面的代码将会打印:”Pythons are free today!” 和前面的示例相似,字符串被直接指定,但是这里则是数字( 0 )被直接指定。注意到 数字是不用放在引号内的。如果将 0 放在引号内( ”0” ) ,FreeMarker 就会将其误判为字符 串了。 当 price 不是 0 的时候,下面的代码将会打印:”Pythons are not free today!” 你也许会猜测了 ,!= 就是不等于。 你也可以这样来写代码(使用数据模型来描述哈希表变量) :
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>
Welcome ${user}
<#if where="user=='Big Joe'">, our beloved leader</#if>!
</h1>
<p>Our latest product:
<a href="${product.url}">${product.name}</a>!
</body>
</html> 
<#if where="animals.python.price==0">
Pythons are free today!
</#if> 
<#if where="animals.python.price != 0">
Pythons are free today!
</#if> 
<#if where="animals.python.price < animals.elephant.price">
Pythons are cheaper than elephants today.
</#if> 
使用< #else>标签可以指定当条件为假时程序执行的内容。例如: 如果蟒蛇的价格比大象的价格低,将会打印”Python are cheaper than elephants today.”, 否则就打印”Pythons are not cheaper than elephants today.” 如果变量本身就是布尔值(true 或者 false) ,那么可以直接让其作为 if 的条件condition

7.list 循环语法

基本语法,数据库查询的返回的list替换a..e就可用输出VO了
<#list x=a..e>
${x_index}.${x}<br/>
</#list>
当需要用列表来遍历集合的内容时,list 指令是非常好用的。 例如,如果在模板中用前面示例描述序列的数据模型。 list 指令的一般格式为:
<#list loopVariable=sequence >repeatThis </#list >
repeatThis 部分将会在给定的 sequence 遍历时在每项中重复, 从第一项开始, 一个接着一个。在所有的重复中, loopVariable 将持有当前项的值。这个循环变量仅 存在于 list 元素之间。 再看一个示例,遍历示例数据模型 fruits。
<#if where="animals.python.price < animals.elephant.price">
Pythons are cheaper than elephants today.
<#else>
Pythons are not cheaper than elephants today.
</#else>
</#if> 

<#if where="animals.python.protected">
    Warning! Pythons are protected animals!
</#if>
这里为了xml标准所以 < /#else > 用法和Freemark有所不同。

8.switch语法

testsw 是一个变量,演示赋值 为1
<#assign testsw=1 />
<#switch var=testsw>
  <#case where=1>is 1</#case>
  <#case where=2>is 2</#case>
  <#default>is 3</#default>
</#switch>
将会输出:is 1

9.assign 赋值

方式1: 直接赋值
<#assign value="aaa" />
方式2:对象赋值
<#assign mail="'chen@other.com'" in=my>
\${my.mail}
方式3:包含赋值
<#assign var="botton">{name:"btname",value:"1111"}</#assign>
<button name="/${botton.name}">/${botton.value}</button>

10.include 包含指令

使用 include 指令,我们可以在当前的模板中插入其他文件的内容。假设要在一些页面中显示版权声明的信息。 那么可以创建一个文件来单独包含版权声明,之后在需要它的地方插入即可。比方说,我们可以将版权信息单独存放在页面文件 copyright_footer.html 中。
<hr>
<i>
Copyright (c) 2000 <a href="http://www.acmee.com">Acmee
Inc</a>,
<br>
All Rights Reserved.
</i>
当需要用到这个文件时,可以使用 include 指令来实现插入。 输出的内容为:
<html>
<head>
<title>Test page</title>
</head>
<body>
<h1>Test page</h1>
<p>Blah blah...
<#include file="copyright_footer.html">
</body>
</html>
如果改变了 copyright_footer.html 中的内容, 那么访问者就会在所有页面中 看到新的版权声明
<html>
<head>
<title>Test page</title>
</head>
<body>
<h1>Test page</h1>
<p>Blah blah...
<hr>
<i>
Copyright (c) 2000 <a href="http://www.acmee.com">Acmee
Inc</a>,
<br>
All Rights Reserved.
</i>
</body>
</html>
更多方式
<#include "*/footer.ftl">
<#include "*/commons/footer.ftl">

11.list,break 指令

<#list item=sequence>
...
</#list>
这里:
<#assign seq = ["winter", "spring", "summer", "autumn"]>
<#list x=seq >
${x_index + 1}. ${x}<#if where="x_has_next">,</#if>
</#list>
输出: 1. winter, 2. spring, 3. summer, 4. autumn
<#list seq as x>
${x}
<#if x = "spring"><#break></#if>
</#list>
通常来说,避免 list 中使用无论何时可能包装了 Iterator 作为参数的集合和使 用包装了 java.util.Collection 或序列的集合是最好的。但是在某些情况,当你 处理时仅仅有一个 Iterator 。要注意如果你传递了一个包装了 Iterator 的集合给 list , 你仅仅可以迭代一次元素, 因为 Iterator s 是由它们一次性对象的特性决定的。 当你尝试第二次列出这样一个集合变量时,错误会中止模板的处理。

12.联合使用指令

在页面也可以多次使用指令,而且指令间可以相互嵌套,正如在 HTML 元素中嵌套使用 标签一样。下面的代码会遍历动物集合,用大号字体来打印大型动物的名字。
<p>We have these animals:
<table border=1>
<tr><th>Name<th>Price
<#list animals as being>
<tr>
<td>
<#if where="being.size=='large'"><font size="+1"></#if>
${being.name}
<#if where="being.size =='large'"></font></#if>
<td>${being.price} Euros
</#list>
</table>
注意到 Scriptmark 并不解析 FTL 标签外的文本,插值和注释,当条件不满足时它也会 忽略所有嵌套的 font 标签

13.处理 不存在 的变量

在实际应用中数据模型经常会有可选的变量(也就是说有时可能不存在实际值) 。除了一些典型的人为原因导致失误, Scriptmark 在一定范围容忍不存在的对象变量,容忍范围和javascript容忍度一样。这里介绍两种典型的处理方法。 这部分对程序员而言:一个异常和一个是 null 的变量,所以这里所指的丢失包含这两种情况。 不论在哪里引用变量, 都可以指定一个默认值来避免变量丢失这种情况, 通过在变量名 后面跟着一个#(默认值) 和默认值。就像下面的例子,当 user 从数据模型中丢失时,模板将会将 user 的值表示为字符串 ”Anonymous” 。 (若 user 并没有丢失,那么模板就会表现 出 ”Anonymous” 不存在一样) :
<h1>Welcome ${user#("Anonymous")}!</h1>
当然也可以在变量名后面通过放置 ? 来询问 Scriptmark 一个变量是否存在。将它和 if 指令合并,那么如果 user 变量不存在的话将会忽略整个问候代码段
<h1>Welcome ${user?user:''}!</h1>
看明白了,这就是一个标准的简化版if 写法。

14.模板支持的函数和方法

搜索支持javascript的所有标准方法和函数,同时封装了常用的方法。可以查看 com.jspx.scriptmark.js.jslib.js 中的提供的方法, 当然你也可以自己添加和其他需要的, 运行后将作为内置方式提供调用。 一般普通的函数javascript有的,就可以直接使用了,应为内置的是javascript引擎。 日期格式 var date=now();
${date.string('yyyy-MM-dd hh:mm')}
indexOf var str="Welcome toMicrosoft! "
str.indexOf("to")
切分 var str="Welcome;to;Microsoft! "
${str.split(";")}
替换 var str="Welcome to Microsoft! "
${str.replace(/Microsoft/g, "w3school")}
切断 var str="Welcome to Microsoft! alskjflsdk "
${str.cut(7, "...")}
切断到特定字符前 var str="Welcome to|Microsoft! "
${str.cutBefore("|")}
清除空格 var str=" Welcome to "
${str.trim()}
数字转中文 var str="4561 "
${str.toChineseCurrency()}
首字母大写 var str="hello "
${str.firstUpperCase()}
首字母小写 var str="Love"
${str.firstUpperCase()}
字符串转换为数字,保留小数位数 var str="465.4654987"
${str.round(2)}
校验手机号码:必须以数字开头,除数字外 var str="1346854698"
${str.isMobile()}
校验QQ
${str.isQQ()}
是否为日期
${str.isDate()}
校验普通电话、传真号码
${str.isPhone()}
是否为邮编
${str.isPostcode()}
是否为整数
${str.isInteger()}
是否为双精度数
${str.isDouble()}
是否为英文
${str.isEnglish()}
转换为数字验证是否在范围内
${str.isBetween(10,20)}
判断长度是否在之内
${str.isLengthBetween(10,20)}
MD5加密
${str.toMd5()}
内置的是javascript引擎,更多的查看javascript手册吧,javascript能用的非UI函数都能用。

15.更多演示

package jspx.example.test;


import com.github.jspxnet.boot.JspxNetApplication;
import com.github.jspxnet.io.AutoReadTextFile;
import com.github.jspxnet.json.JSONObject;
import com.github.jspxnet.scriptmark.ScriptMark;
import com.github.jspxnet.scriptmark.ScriptmarkEnv;
import com.github.jspxnet.scriptmark.XmlEngine;
import com.github.jspxnet.scriptmark.core.ScriptMarkEngine;
import com.github.jspxnet.scriptmark.core.TagNode;
import com.github.jspxnet.scriptmark.load.Source;
import com.github.jspxnet.scriptmark.load.StringSource;
import com.github.jspxnet.scriptmark.parse.XmlEngineImpl;
import com.github.jspxnet.sioc.tag.BeanElement;
import com.github.jspxnet.txweb.support.ActionSupport;
import com.github.jspxnet.txweb.util.RequestMap;
import com.github.jspxnet.txweb.view.ActionLogView;
import com.github.jspxnet.utils.DateUtil;
import com.github.jspxnet.utils.StringUtil;
import org.testng.annotations.*;
import org.testng.Assert;

import javax.script.ScriptException;
import java.io.*;
import java.util.*;

public class TestScriptmark {

    @BeforeClass
    public static void init() {

        JspxNetApplication.autoRun();
        System.out.println("------------开始");
    }

    /**
     * 调用模板引擎
     *
     * @param x       模板字符串
     * @param map     参数
     * @param cacheId
     * @return
     * @throws Exception
     */
    public static String CallScriptMarkEngine(String x, Map map, String cacheId) throws Exception {
        if (StringUtil.isNull(cacheId)) cacheId = ScriptmarkEnv.noCache;
        //这里演示了如何调用模板引擎
        Source reader = new StringSource(x); //这里可以是文件 FileSource  JarSource
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine(cacheId, reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, map);
        writer.close();
        return writer.toString();
    }

    @Test(threadPoolSize = 20,invocationCount = 20)
    public void testAssign() throws Exception {
        String x = "<#assign myv=1+23 />${myv} <#assign my2=[1..3] />${my2.toString()} <#assign my3=['aa','bb'] />${my3.toString()}" +
                "<#assign my=parseInt(\'38\') /> ${\"${user}${user}\\'${user}${user}\" + \"${user}\"} ${my + 4} ${\"Hello ${my}!\"} <#assign var=my>new Date(\"2008-11-12\")</#assign>" +
                "<#assign var=ages>{\"Joe\":30, \"Julia\":18}</#assign>${ages.Joe} ${ages.Julia} " +
                "<#assign var=mysp>\"a|b|c|\".split(\"|\");</#assign>${mysp.toString()}";

        Assert.assertEquals(CallScriptMarkEngine(x, null, "testAssign"), "24 1,2,3 aa,bb ${user}${user}\'${user}${user}${user} 42 Hello ${my}! 30 18 a,b,c,");
    }

    @Test(threadPoolSize = 20,invocationCount = 20)
    public void testexpression() throws Exception {
        String x = "expression=rePassword.equal('${password}')";
        Map map = new HashMap();
        map.put("rePassword", "111111");
        map.put("password", "111111");
        Assert.assertEquals(CallScriptMarkEngine(x, map, "testexpression"), "expression=rePassword.equal('111111')");
    }

    @Test(threadPoolSize = 20,invocationCount = 20)
    public void testVarOut() throws Exception {
        String x = "1${3+4}2 ${aa+\'bbb\'}3\\${ccc}4${xxx}5${(3+3)*10-5}";
        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("aa", "put1");
        bindings.put("xxx", "put2");
        Assert.assertEquals(CallScriptMarkEngine(x, bindings, "testVarOut"), "172 put1bbb3${ccc}4put2555");
    }

    @Test(threadPoolSize = 20,invocationCount = 20)
    public void testIf1() throws Exception {
        String x = "<#if where=1>begin<#if where=true>aaa<#else>bbb</#else>ddd</#if>eee<#if where=1>ee<#else>ff</#else>gg</#if>hhh</#if>";
        Assert.assertEquals(CallScriptMarkEngine(x, null, "testIf1"), "beginaaadddeeeeegghhh");
    }

    @Test(threadPoolSize = 20,invocationCount = 20)
    public void testIf2() throws Exception {
        String x = "<#if where=my&gt;3>hhh<#else where=true>1" +
                "<#if where=\"'a'=='a'\">b<#else>n</#else></#if>" +
                "2</#else><#else>222</#else></#if>";
        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("my", 2);
        Assert.assertEquals(CallScriptMarkEngine(x, bindings, "testIf2"), "1b2");
    }

    @Test(threadPoolSize = 20,invocationCount = 20)
    public void testSwitch() throws Exception {
        String x = "AAA<#switch var=1>\r\n" +
                "<#case where=1>is 1</#case>\r\n" +
                "<#case where=2>is 2</#case>\r\n" +
                "<#default>is 3</#default></#switch>BBB" +

                "<#assign myv=7 /><#switch var=my>" +
                "<#case where=1>is 1</#case>" +
                "<#case where=2>is 2</#case>" +
                "<#case where=myv-4>G3</#case>" +
                "<#default>is 3</#default></#switch>D" +

                "<#assign myv=\"'A'\" /><#switch var=myv>\r\n" +
                "<#case where='A'>is1</#case>\r\n" +
                "<#case where='B'>is 2</#case>\r\n" +
                "<#case where='C'>is3</#case>\r\n" +
                "<#default>isD</#default></#switch>E" +

                "<#assign myv=\"'F'\" /><#switch var=myv>\r\n" +
                "<#case where='A'>is1</#case>\r\n" +
                "<#case where='B'>is 2</#case>\r\n" +
                "<#case where='C'>is3</#case>\r\n" +
                "<#default>isF</#default></#switch>E";


        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("my", 3);
        Assert.assertEquals(CallScriptMarkEngine(x, bindings, "testSwitch"), "AAAis 1BBBG3Dis1EisFE");   //1BBBis3Dis1EisFE
    }

    @Test(threadPoolSize = 20,invocationCount = 20)
    public void testJavascript() throws Exception {
        String x = "<#script>function getMul(x,y){ return x*y;}; var x=getMul(5,8);</#script>${x}-${getMul(3,4)}";
        Assert.assertEquals(CallScriptMarkEngine(x, null, "testJavascript"), "40-12");
    }

    @Test(threadPoolSize = 20,invocationCount = 20)
    public void testMacro() throws Exception {

        String x = "1<#assign \r\nhello=\"'is hello good'\" ></#assign>2" +
                "2<#macro name=button>\r\n" +
                "<input type=\"button\" name=\"${name}\" value=\"${value}\"/>\r\n" +
                "</#macro>8\r\n" +
                "9<@button name=\"bname\" value=${hello + ' x'} />9\r\n" +
                "<#script>function getMul(x,y){ return x*y;} var x=getMul(5,8);</#script>11111A${x}B";
        Assert.assertEquals(CallScriptMarkEngine(x, null, "testMacro"), "1228\r\n9\r\n<input type=\"button\" name=\"bname\" value=\"is hello good x\"/>\r\n9\r\n11111A40B");
    }

    @Test
    public void testTryBlock() throws Exception {
        String x = "<#try>\r\n" +
                "ok\r\n" +
                "<#catch>错误的时候运行</#catch>" +
                "<#finally>一定运行</#finally>" +
                "ok2" +
                "</#try>";

        Assert.assertEquals(CallScriptMarkEngine(x, null, "testTryBlock"), "\r\nok\r\nok2一定运行");
    }

    @Test(threadPoolSize = 20,invocationCount = 20)
    public void testList() throws Exception {


        String x =
                "<#assign var=mylist>[\"winter\",\"spring\",\"summer\",\"autumn\"]</#assign>" +
                        "<#list my=mylist>" +
                        "${my_index}.${my}\r\n" +
                        "</#list>" +

                        "<#list my=mylist2>" +
                        "${my}<#if where=my_has_next>-</#if>" +
                        "</#list>\r\n" +
                        "<!--# xxxxxxx #-->" +
                        "<#list my=mylist3>" +
                        "${my}<#if where=my_has_next>-</#if>" +
                        "</#list>";

        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("mylist2", new String[]{"one", "two"});
        bindings.put("mylist3", new Integer[]{4, 5});
        Assert.assertEquals(CallScriptMarkEngine(x, bindings, "testTryBlock"), "0.winter\r\n1.spring\r\n2.summer\r\n3.autumn\r\none-two\r\n4-5");
    }

    @Test(threadPoolSize = 20,invocationCount = 20)
    public void testArrayList() throws Exception {
        String x =
                "<#list my=mylist>" +
                        "${my_index}.${my}\r\n" +
                        "</#list>";
        List list = new ArrayList();
        list.add("one");
        list.add("two");
        list.add("three");

        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("mylist", list);
        Assert.assertEquals(CallScriptMarkEngine(x, bindings, "testArrayList"), "0.one\r\n1.two\r\n2.three\r\n");
    }

    @Test
    public void testBean() throws Exception {
        List list = new ArrayList();
        TBean tb = new TBean();
        tb.setName("陈");
        tb.setOld(30);
        tb.setMoney(1);
        tb.setTb(new TBean());
        tb.getTb().setName("chld1");
        list.add(tb);

        tb = new TBean();
        tb.setName("唐");
        tb.setOld(28);
        tb.setMoney(10.112);
        tb.setTb(new TBean());
        tb.getTb().setName("chld2");
        list.add(tb);

        String x = "<#list my=mylist>" +
                "${my_index}.${my.name}--${my.old}--${my.money}--${my.tb.name}\r\n" +
                "</#list>\r\n";
        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("mylist", list);
        Assert.assertEquals(CallScriptMarkEngine(x, bindings, "testBeanxx"), "0.陈--30--1--chld1\r\n1.唐--28--10.11--chld2\r\n\r\n");
    }


    @Test
    public void testScrpitMat() throws Exception {
        String x = "<#assign re=/[^a-zA-Z0-9-]/g />" +
                "1234是否为数字:${!re.test(1234)};" +
                "调用js替换方法:${\"aaaaa\".replace(\"aaa\", \"X\") }";

        Assert.assertEquals(CallScriptMarkEngine(x, null, "testScrpitMat"), "1234是否为数字:true;调用js替换方法:Xaa");
    }

    @Test
    public void testBuiltIn() throws Exception {
        String x = "<#assign var=my>\"111<a>aaaaa</a><b>cccc</b>222\"</#assign>" +
                "${my.deleteHtml()}";
        Assert.assertEquals(CallScriptMarkEngine(x, null, "testBuiltIn"), "111aaaaacccc222");
    }

    @Test
    public void testBuiltInString() throws Exception {

        //var date = new Date(2008,11,13,01,01,01);
        String x =
                "<#assign my=1 /><#assign my2=false />" +
                        "${my.string(\"yes\",\"no\")} " +
                        "${my2.string(\"yes\",\"否\")} " +
                        "${date.string(\'yyyy年MM月dd日 hh:mm\')}";

        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("date", StringUtil.getDate("2008-12-13 01:26:02"));
        String out = CallScriptMarkEngine(x, bindings, "testBuiltInString");
        System.out.println(out);
        Assert.assertEquals(out, "yes 否 2008年12月13日 01:26");
    }

    @Test
    public void testAssginType() throws Exception {
        //java 控制台 嵌入适用

        String x = "<#assign my=parseInt(\'38\') /> ${\"${user}${user}${user}${user}\" + \"${user}\"} ${my + 4} <#assign y=29+1 /> ${y+4} <#assign var=yd>new Date(2006, 11, 25,12,15,10)</#assign> ${yd.string('yyyy年MM月dd日 HH:mm:ss')}";
        Assert.assertEquals(CallScriptMarkEngine(x, null, "testAssginType"), " ${user}${user}${user}${user}${user} 42  34  2006年12月25日 12:15:10");
    }

    @Test
    public void testArrayString() throws Exception {
        String x = "<#assign var=users>[{\"name\":\"Joe\",\"hidden\":false},{\"name\":\"James Bond\", \"hidden\":true},{\"name\":\"Julia\",\"hidden\":false}]</#assign>" +
                "<#list user=users >" +
                "<#if !user.hidden>${user.name}\r\n</#if>" +
                "</#list>";
        Assert.assertEquals(CallScriptMarkEngine(x, null, "testArrayString"), "Joe\r\nJulia\r\n");
    }

    @Test
    public void testJsLib() throws Exception {
        String str = "<#assign mys=\"'my test word \\<a\\>cy\\</a\\>.'\" />" +
                "${mys.deleteHtml()}" +
                "${mys.countMatches('t')} " +
                "${\"123.34543\".toNumber(2)} " +
                "${\"中文\".isChinese()} " +
                "${\"23434\".isNumber()} " +
                "${mys.escape()} " +
                "${mys.deleteHtml(8,\'@@\')} " +
                "${123456.789.round(2)} " +
                "${123456.389.round(0)}";

        Source reader = new StringSource(str);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testJsLib", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, null);
        writer.close();
        Assert.assertEquals(writer.toString(), "my test word cy.2 123.35 true true my test word &lt;a&gt;cy&lt;/a&gt;. my test @@ 123456.79 123456");
    }

    @Test
    public void testBeanJsLib() throws Exception {
        TBean tb = new TBean();
        tb.setName("陈sda1sfds<a>cxxc</a>");
        tb.setOld(30);
        tb.setMoney(4654.4656);
        tb.setTb(new TBean());
        tb.getTb().setName("chl+d1");
        tb.setCreateDate(StringUtil.getDate("2008年11月05日 02:53"));
        String str = "${tbean.name.deleteHtml() + ' ' + tbean.tb.name.indexOf(\'+\')} createDate=${tbean.createDate.string('yy年MM月dd日 hh:mm')}";
        Source reader = new StringSource(str);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testBeanJsLib", reader, null);
        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("tbean", tb);

        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, bindings);
        writer.close();
        Assert.assertEquals(writer.toString(), "陈sda1sfdscxxc 3 createDate=08年11月05日 02:53");
    }

    @Test
    public void testDateJsLib() throws Exception {

        String str =
                "<#script>var beginDate=new Date(1228325382171);" +
                        "var endDate=new Date(1228925382171);</#script>" +
                        "compareHour=${endDate.getTime().compareHour(beginDate).toInt().abs()} " +
                        "max=${max(1, 10, 100, 2, 3, 1000, 4, 5, 10000, 6)} " +
                        "min=${min(1, 10, 100, 2, 3, 1000, 4, 5, 10000, 6)} " +
                        "sum=${sum(1, 10, 100, 2, 3, 1000, 4, 5, 10000, 6)}";

        Source reader = new StringSource(str);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testDateJsLib", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, null);     //compareHour
        writer.close();
        Assert.assertEquals(writer.toString(), "compareHour=167 max=10000 min=1 sum=11131");
    }

    @Test
    public void testDateTypeJsLib() throws Exception {
        ///java 日期转换为了 js的日期
        String str = "${date.string(\'yyyy年MM月dd日 hh:mm\')}";
        Source reader = new StringSource(str);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testDateTypeJsLib", reader, null);
        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("date", StringUtil.getDate("2008-01-01 02:03"));
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, bindings);
        writer.close();
        Assert.assertEquals(writer.toString(), "2008年01月01日 02:03");
    }

    @Test
    public void testMap() throws Exception {
        //map 的用法,使用 LinkedMap
        Map map = new LinkedHashMap();
        TBean tb = new TBean();
        tb.setName("陈sda1sfds<a>cxxc</a>");
        tb.setOld(30);
        tb.setMoney(4654.4656);
        tb.setTb(new TBean());
        tb.getTb().setName("chl+d1");
        map.put("one", tb);

        TBean tb2 = new TBean();
        tb2.setName("第二个");
        tb2.setOld(21);
        tb2.setMoney(2432);
        tb2.setTb(new TBean());
        tb2.getTb().setName("chl+d1");
        map.put("two", tb2);

        String str = "<#list my=myMap>" +
                "${my_index}.${my.name}\r\n" +
                "</#list>" +
                "<#list my=myMap.keySet() >" +
                "${my_index}.${myMap.get(my).name}\r\n" +
                "</#list>" +
                "show=${myMap.get('one').name.deleteHtml()} " +
                "${myMap.get('two').old#(\'无\')} " +
                "${myMap.get('ccc')#(\'无\')}";

        Source reader = new StringSource(str);
        ScriptMark scriptMarkEngine = new ScriptMarkEngine("testMap", reader, null);
        Map<String, Object> bindings = new HashMap<String, Object>();

        bindings.put("myMap", map);

        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, bindings);
        writer.close();
        Assert.assertEquals(writer.toString(), "0.陈sda1sfds<a>cxxc</a>\r\n1.第二个\r\n0.陈sda1sfds<a>cxxc</a>\r\n1.第二个\r\nshow=陈sda1sfdscxxc 21 无");
    }


    @Test
    public void testToUbb() throws Exception {
        String s1 = "[color=\"0000\"]xxxx[/color][b]who am I[/b] yyy [fly]fly88[/fly][b]who am [/b][i]test[/i] http://www.jspx.net" +
                "[b]xxxxxxxxxxx[/b][code=\"java\"]" +
                "public void writeLineNumber(Writer writer, int type) throws IOException {\n" +
                "    if (showLineNumber == true) {\n" +
                "      switch (type) {\n" +
                "        case HEAD:\n" +
                "          writer.write(\"<ol>\");\n" +
                "          break;\n" +
                "        case LINE:\n" +
                "          writer.write(\"<li>\");\n" +
                "          break;\n" +
                "        case END:\n" +
                "          writer.write(\"</ol>\");\n" +
                "          break;\n" +
                "      }\n" +
                "    }\n" +
                "  }\n[/code]";

        String str = "${mo.toUbb()}";
        Source reader = new StringSource(str);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testToUbb", reader, null);
        Map<String, Object> bindings = new HashMap<String, Object>();

        bindings.put("mo", s1);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, bindings);
        writer.close();
    }

    @Test
    public void testArray() throws Exception {
        String str = "<#list x=3..1>${x}\r\n</#list>" +
                "<#list x=a..c >${x}\r\n</#list>";
        Source reader = new StringSource(str);
        ScriptMark scriptMarkEngine = new ScriptMarkEngine("testArray", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, null);
        writer.close();
        Assert.assertEquals(writer.toString(), "3\r\n2\r\n1\r\na\r\nb\r\nc\r\n");
    }

    @Test
    public void testXML() throws Exception {
        String f = "d:\\website\\webapps\\root\\WEB-INF\\classes\\jspx.net.xml";
        AutoReadTextFile artf = new AutoReadTextFile();
        artf.setFile(f);

        XmlEngine xe = new XmlEngineImpl();
        xe.putTag("bean", BeanElement.class.getName());
        List<TagNode> list = xe.getTagNodes(artf.getContent());
        for (TagNode tnode : list) {
            System.out.println("1----------" + tnode.getSource());
        }
    }

    @Test
    public void testExists() throws Exception {
        //exists
        String str = "<#if where=typeof(mm) >typeof<#else>false</#else></#if>";
        Source reader = new StringSource(str);
        ScriptMark scriptMarkEngine = new ScriptMarkEngine("testExists", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, null);
        writer.close();
        Assert.assertEquals(writer.toString(), "false");
    }

    @Test
    public void testCut() throws Exception {
        //演示切短,一般用在新闻标题输出
        String str = "${'adsfasdlkjf;lsadf'.cut(10,'..')}";
        Source reader = new StringSource(str);
        ScriptMark scriptMarkEngine = new ScriptMarkEngine("testCut", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, null);
        writer.close();
        System.out.println("----" + writer.toString());
        Assert.assertEquals(writer.toString(), "adsfasdl..");
    }

    @Test
    public void testXmlA() throws Exception {
        //XML自动修复,不推荐非标准写法
        String x = "<#assign mya=1+23>xx<#assign myv=2+23><a>xx${mya}x</a>${myv}";
        Source reader = new StringSource(x);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testXmlA", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, null);
        writer.close();
        Assert.assertEquals(writer.toString(), "xx<a>xx24x</a>25");
    }

    @Test
    public void testAssignAttr() throws Exception {
        String x = "<#assign myv='xjsla\\\\\\\\x'.replace('\\\\\\\\','/') />${myv} ${\"123\\\"456\\'789\".replace('\\'','/') + 'jcms/'}";
        Source reader = new StringSource(x);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testAssignAttr", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, null);
        writer.close();
        Assert.assertEquals(writer.toString(), "xjsla/x 123\"456/789jcms/");
    }

    @Test
    public void testDeleteHtml() throws Exception {
        Map map = new Hashtable();
        TBean tb = new TBean();
        tb.setName("陈sda1sfds123234231");
        tb.setOld(30);
        tb.setMoney(4654.4656);
        tb.setTb(new TBean());
        tb.getTb().setName("chl+d1");
        map.put("one", tb);

        String x = "${one.name.deleteHtml(10,\"..\")}";
        Source reader = new StringSource(x);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testDeleteHtml", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, map);
        writer.close();

        Assert.assertEquals(writer.toString(), "陈sda1sfds..");
    }

    @Test
    public void testValidation() throws Exception {
        Map map = new Hashtable();
        map.put("mycode", "522321780705491");
        map.put("mycode2", "52232119780705491X");
        String x = "mycode=${mycode.isCardCode()} mycode2=${mycode2.isCardCode()}";
        Source reader = new StringSource(x);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testValidation", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, map);
        writer.close();
        Assert.assertEquals(writer.toString(), "mycode=true mycode2=true");
    }

    @Test
    public void testDate() throws Exception {
        Map map = new Hashtable();
        map.put("myd", "780705");
        map.put("myd2", "2008-01-02");
        map.put("myname", "中文名称");


        String x = "myd=${myd.toDate().string('yyyy-MM-dd')} myd2=${myd2.toDate().string('yyyy-MM-dd')} isGoodName=${myname.isGoodName()}";
        Source reader = new StringSource(x);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testDate", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, map);
        writer.close();
        Assert.assertEquals(writer.toString(), "myd=1978-07-05 myd2=2008-01-02 isGoodName=true");
    }

    @Test
    public void testDate2() throws Exception {
        Map<String, Object> valueMap = new HashMap<String, Object>();
        Date date = StringUtil.getDate("2013-07-02 03:04");
        valueMap.put("date", date);

        String x = "date=${date.string('yyyy-MM-dd')}";

        Source reader = new StringSource(x);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testDate2", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, valueMap);
        writer.close();

        System.out.println("----writer.toString()=" + writer.toString());
        Assert.assertEquals(writer.toString(), "date=2013-07-02");
    }

    @Test
    public void testcongealType() throws Exception {
        Map map = new Hashtable();
        map.put("congealType", 1);
        String x = "<td><input name=\"congealType\" type=\"checkbox\" value=\"1\" <#if where=congealType>selected=\"checked\"</#if> /></td>";
        Source reader = new StringSource(x);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testcongealType", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, map);
        writer.close();
        Assert.assertEquals(writer.toString(), "<td><input name=\"congealType\" type=\"checkbox\" value=\"1\" selected=\"checked\" /></td>");
    }

    @Test
    public void testIsDate() throws Exception {
        Map map = new Hashtable();
        //2002年11月13日 上午12时00分00秒
        map.put("congealdate", "2002-11-13");
        String x = "${congealdate.isDate()}";
        Source reader = new StringSource(x);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testIsDate", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, map);
        writer.close();
        Assert.assertEquals(writer.toString(), "true");
    }

    @Test
    public void testChineseNumber() throws Exception {
        Map map = new Hashtable();
        //2002年11月13日 上午12时00分00秒
        map.put("mynum", "123456");
        String x = "${mynum.toChineseCurrency()} ${mynum.toChineseNumber()}";
        Source reader = new StringSource(x);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testChineseNumber", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, map);
        writer.close();
        Assert.assertEquals(writer.toString(), "壹拾贰万叁仟肆佰伍拾陆圆整 一十二万三千四百五十六");
    }


    @Test
    public void testNULL() throws Exception {
        Map map = new Hashtable();
        map.put("myValue", "");
        String x = "<#if where=myValue>true<#else>false</else></#if>";
        Source reader = new StringSource(x);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testNULL", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, map);
        writer.close();
        Assert.assertEquals(writer.toString(), "false");


    }

    @Test
    public void testDateSQL() throws Exception {
        Date date = new Date();
        Date startDate = DateUtil.getStartDateTime(date);
        Map valueMap = new Hashtable();
        valueMap.put("date", date);
        valueMap.put("beginDateTime", startDate);
        String x = "select count(*)<150 from jcms_matter where createDate>='${beginDateTime.string('yyyy-MM-dd HH:mm:ss')}' \r\n${date.string('yyyy-MM-dd HH:mm:ss')}";
        Source reader = new StringSource(x);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testDateSQL", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, valueMap);
        writer.close();
        Assert.assertEquals(writer.toString(), "select count(*)<150 from jcms_matter where createDate>='" + DateUtil.toString(startDate, DateUtil.FULL_ST_FORMAT) + "' \r\n" +
                DateUtil.toString(date, DateUtil.FULL_ST_FORMAT));
    }


    @Test
    public void testJson3() throws Exception {
        //格式转换 json 和 xml
        Map map = new Hashtable();
        TBean tb = new TBean();
        tb.setName("陈sda1sfds<a>cxxc</a>");
        tb.setOld(30);
        tb.setMoney(4654.4656);
        tb.setTb(new TBean());
        tb.getTb().setName("chl+d1");
        map.put("one", tb);

        tb = new TBean();
        tb.setName("第二个");
        tb.setOld(21);
        tb.setMoney(2432);
        tb.setTb(new TBean());
        tb.getTb().setName("chl+d1");
        map.put("two", tb);

        String[] strs = new String[]{"one", "two", "three"};
        String str = "${json(mo)}\n${json(ms)}";
        Source reader = new StringSource(str);
        ScriptMark scriptMarkEngine = new ScriptMarkEngine("testJson3", reader, null);
        Map<String, Object> bindings = new HashMap<String, Object>();

        bindings.put("mo", map);
        bindings.put("ms", strs);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, bindings);
        writer.close();

    }


    @Test
    public void testXiaoWang() throws Exception {
        HashMap<String, Object> context = new HashMap<String, Object>();
        context.put("data", Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7",
                "8", "9", "A", "B", "C", "D", "E", "F"));
        context.put("name", "test");
        context.put("border", "1px");
        context.put("testString", "1");


        String x = "<div>\n" +
                "<h1>${name}</h1>\n" +
                "<table border=\"${border}\">\n" +
                "\t<tr>\n" +
                "\t\t<th>&#160;</th>\n" +
                "<#list cell=data>\n" +
                "\t\t<th>${cell}</th>\n" +
                "</#list>\n" +
                "\t</tr>\n" +
                "<#list row=data>\n" +
                "\t<tr>\n" +
                "\t\t<th>${row}</th>\n" +
                "<#list cell=data>\n" +
                "\t\t<td>&#x${row}${cell};</td>\n" +
                "</#list>\n" +
                "\t</tr>\n" +
                "</#list>\n" +
                "</table>\n" +
                "</div>";
        Source reader = new StringSource(x);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testXiaoWang", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, context);
        writer.close();


        writer = new StringWriter();
        scriptMarkEngine.process(writer, context);
        writer.close();

    }

    @Test
    public void testDateFormat() throws Exception {


        Map valueMap = new HashMap();
        valueMap.put("date", StringUtil.getDate("2010-01-01 12:12:12"));
        String x = "${date.string('yyyy年MM月dd日 HH:mm:ss')}";
        String result = CallScriptMarkEngine(x, valueMap, "testDateFormat1");
        Assert.assertEquals(result, "2010年01月01日 12:12:12");

        valueMap.put("date", StringUtil.getDate("2010-01-02 15:12:12"));
        x = "${date.string('yyyy年MM月dd日 HH:mm')}";
        result = CallScriptMarkEngine(x, valueMap, ScriptmarkEnv.noCache);
        Assert.assertEquals(result, "2010年01月02日 15:12");

        Date date = StringUtil.getDate("2010-03-04 06:19:12");
        x = "<#assign var=date>new Date('2010/03/04 06:19:12')</#assign>${date.string('yyyy年MM月dd日 HH:mm:ss')}";
        result = CallScriptMarkEngine(x, valueMap, ScriptmarkEnv.noCache);
        Assert.assertEquals(result, DateUtil.toString(date, "yyyy年MM月dd日 HH:mm:ss"));


        valueMap.put("date", "2010-01-01 12:12:18");
        x = "${date.toDate().string('yyyy年MM月dd日 hh:mm:ss')}";
        result = CallScriptMarkEngine(x, valueMap, ScriptmarkEnv.noCache);
        Assert.assertEquals(result, "2010年01月01日 12:12:18");


        TBean tb = new TBean();
        tb.setCreateDate(StringUtil.getDate("2012-03-04 11:2:6"));
        valueMap.put("tb", tb);

        x = "${tb.createDate.string(\"yyyy年MM月dd日 HH:mm\")}";
        result = CallScriptMarkEngine(x, valueMap, ScriptmarkEnv.noCache);
        Assert.assertEquals(result, "2012年03月04日 11:02");


        date = StringUtil.getDate("2012-03-04 11:2:6");
        tb.setCreateDate(date);
        valueMap.put("tb", tb);
        valueMap.put("date", date);
        System.out.println(date);
        x = "${date.string(\"yyyy年MM月dd日 HH:mm\")},${tb.createDate.string(\"yyyy年MM月dd日 HH:mm\")}";
        result = CallScriptMarkEngine(x, valueMap, "testDateFormat2tbTest");
        Assert.assertEquals(DateUtil.toString(date, DateUtil.FULL_ST_FORMAT), "2012-03-04 11:02:06");
        Assert.assertEquals(result, "2012年03月04日 11:02,2012年03月04日 11:02");
    }


    @Test
    public void testNullObject() throws Exception {
        Map valueMap = new HashMap();
        String x = "<#if where=typeof(xx)>1<#else>2</#else></#if> ${typeof(xx)=='undefined'} 3:${isEmpty(typeof(xx))} 4:<#if where=!isEmpty(typeof(xx))>true</if>";
        String result = CallScriptMarkEngine(x, valueMap, "testNullObject");
        Assert.assertEquals(result, "2 true 3:false 4:true");
    }

    public static final String COLUMN_NAME = "column_name";
    public static final String COLUMN_LENGTH = "column_length";
    public static final String COLUMN_NOT_NULL = "column_not_null";
    public static final String COLUMN_DEFAULT = "column_default";

    @Test
    public void testIFOther() throws Exception {
        Map valueMap = new HashMap();
        valueMap.put("column_length", 200);
        valueMap.put(COLUMN_NAME, "my");
        valueMap.put(COLUMN_NOT_NULL, "true");
        valueMap.put(COLUMN_DEFAULT, "");
        String x = "${" + COLUMN_NAME + "} <#if where=" + COLUMN_LENGTH + "&lt;255>varchar(${" + COLUMN_LENGTH + "})<#else>text</#else></#if> <#if where=" + COLUMN_NOT_NULL + ">NOT NULL</#if> <#if where=" + COLUMN_DEFAULT + ">default '${" + COLUMN_DEFAULT + "}'</#if>";
        String result = CallScriptMarkEngine(x, valueMap, "testIFOther1");
        Assert.assertEquals(result, "my varchar(200) NOT NULL ");
        valueMap.put("column_length", 400);
        result = CallScriptMarkEngine(x, valueMap, "testIFOther2");
        Assert.assertEquals(result, "my text NOT NULL ");

    }

    @Test
    public void testIf() throws Exception {
        Map valueMap = new HashMap();
        valueMap.put("allMoney", 32);
        valueMap.put("allLogisticPrice", 12);
        valueMap.put("storeMoney", 34);
        System.out.println(34 > (32 + 12));
        String x = "<#if where='storeMoney ge (allMoney+allLogisticPrice)'>1<#else>2</#else></#if>";
        String result = CallScriptMarkEngine(x, valueMap, "testIf");
        Assert.assertEquals(result, "2");
    }

    @Test
    public void testNULL2() throws Exception {
        Map valueMap = new HashMap();
        valueMap.put("aa", null);
        valueMap.put("bb", "");

        String x = "${aa#('one')},${bb#('two')},${aa+bb#('无')}";
        String result = CallScriptMarkEngine(x, valueMap, "testNULL2");
        Assert.assertEquals(result, "one,two,无");
    }

    @Test
    public void testBreak() throws Exception {
        Map valueMap = new HashMap();
        String x = "<#list a=1..8><#if where='a_index gt 2'><#break /></#if>${a}</#list>";
        String result = CallScriptMarkEngine(x, valueMap, "testBreak");
        Assert.assertEquals(result, "123");
    }

    @Test
    public void testBreak2() throws Exception {
        Map valueMap = new HashMap();
        valueMap.put("list", new String[]{"a", "b", "c", "d", "e", "f"});
        String x = "<#list og=list><#if where='og_index gt 2'><#break /></#if>${og}</#list>";
        String result = CallScriptMarkEngine(x, valueMap, "testBreak2");
        Assert.assertEquals(result, "abc");
    }

    @Test
    public void testBreak3() throws Exception {

        Map valueMap = new HashMap();
        valueMap.put("list", new String[]{"a", "b", "c", "d", "e", "f"});
        String x = "<#list o=1..9 >${o}<#list og=list><#if where='og_index gt 3'><#break /></#if>${og}</#list></#list>";
        String result = CallScriptMarkEngine(x, valueMap, "testBreak3");
        Assert.assertEquals(result, "1abcd2abcd3abcd4abcd5abcd6abcd7abcd8abcd9abcd");
    }

    @Test
    public void testContinue() throws Exception {

        Map valueMap = new HashMap();
        valueMap.put("list", new String[]{"a", "b", "c", null, "d", "e", "f"});
        String x = "<#list og=list><#if where='og==null' ><#continue /></#if>${og}</#list>";
        String result = CallScriptMarkEngine(x, valueMap, "testContinue");
        Assert.assertEquals(result, "abcdef");
    }

    @Test
    public void testJsonQuote() throws Exception {

        //格式转换 json 和 xml
        String checkStr = "555555\"6\"555\'5\'";
        Map map = new Hashtable();
        String[] test = new String[3];
        test[0] = "1";
        test[1] = checkStr;

        map.put("test", test);

        String str = "${json(test)}";
        Source reader = new StringSource(str);
        ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine("testJsonQuote1", reader, null);
        Writer writer = new StringWriter();
        scriptMarkEngine.process(writer, map);
        Assert.assertEquals(writer.toString(), "[\"1\",\"555555\\\"6\\\"555'5'\",null]");

        map.put("mo", writer.toString());

        str = "${mo.jsonToArray()[1]}";
        reader = new StringSource(str);
        scriptMarkEngine = new ScriptMarkEngine("testJsonQuote2", reader, null);
        writer = new StringWriter();
        scriptMarkEngine.process(writer, map);
        writer.close();
        Assert.assertEquals(checkStr, writer.toString());

    }

    @Test
    public void testListA() throws Exception {
        String x =
                "<#list my=2..2 equals=\"false\">" +
                        "${my}" +
                        "</#list>\r\n";

        Map<String, Object> bindings = new HashMap<String, Object>();
        Assert.assertEquals(CallScriptMarkEngine(x, bindings, "testListA"), "\r\n");
    }

    @Test
    public void testListObject() throws Exception {

        List<TBean> list = new ArrayList<TBean>();
        TBean bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("A");
        list.add(bean);

        bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("B");
        list.add(bean);

        bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("C");
        list.add(bean);

        bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("D");
        list.add(bean);

        String x =
                "<#assign myList=list /><#list my=myList >${my.tb.name}</#list>";

        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("list", list);

        Assert.assertEquals(CallScriptMarkEngine(x, bindings, "testListObject"), "ABCD");
    }

    @Test
    public void testErrorList() {

        List<TBean> list = new ArrayList<TBean>();
        TBean bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("A");
        list.add(bean);

        bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("B");
        list.add(bean);

        bean = new TBean();
        bean.setTb(null);
        list.add(bean);

        bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("D");
        list.add(bean);

        String x = "<#list my=list >${my.tb.name}</#list>";
        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("list", list);

        Writer writer = new StringWriter();
        String result = null;
        String error = null;
        try {

            Source reader = new StringSource(x); //这里可以是文件 FileSource  JarSource
            ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine(ScriptmarkEnv.noCache, reader, null);
            scriptMarkEngine.process(writer, bindings);
            writer.close();

        } catch (Exception e) {
            //测试屏蔽异常
            error = e.getLocalizedMessage();
        } finally {
            result = writer.toString();
        }
        Assert.assertEquals(result, "ABD");

    }

    @Test
    public void testErrorList2() {

        List<TBean> list = new ArrayList<TBean>();
        TBean bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("A");
        list.add(bean);

        bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("B");
        list.add(bean);

        bean = new TBean();
        bean.setTb(null);
        list.add(bean);

        bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("D");
        list.add(bean);

        String x =
                "<#list my=list >${my.tb==null}</#list>";

        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("list", list);

        try {
            Assert.assertEquals(CallScriptMarkEngine(x, bindings, "testErrorList2"), "falsefalsetruefalse");
        } catch (Exception e) {
            // e.printStackTrace();
        }
    }


    @Test
    public void testErrorLineNumber() {

        List<TBean> list = new ArrayList<TBean>();
        TBean bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("A");
        list.add(bean);

        bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("B");
        list.add(bean);

        bean = new TBean();
        bean.setTb(new TBean());
        bean.setTb(null);
        list.add(bean);

        bean = new TBean();
        bean.setTb(new TBean());
        bean.getTb().setName("D");
        list.add(bean);

        String x = "1\r\n2\r\n3\r\n<#if where=1>${error.name}<#if>4\r\n5\r\n";
        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("list", list);

        Writer writer = new StringWriter();
        String result = null;
        String error = null;
        try {

            Source reader = new StringSource(x); //这里可以是文件 FileSource  JarSource
            ScriptMarkEngine scriptMarkEngine = new ScriptMarkEngine(ScriptmarkEnv.noCache, reader, null);
            scriptMarkEngine.process(writer, bindings);
            writer.close();

        } catch (Exception e) {
            //测试屏蔽异常
            error = e.getMessage();
        } finally {
            result = writer.toString();
        }
        System.out.println("----------result=" + result);
    }

    @Test
    public void testAssignObject() throws Exception {
        String str = "<#assign mail=\"'chen@other.com'\" in=my> <#assign mail=\"'jsmith@other.com'\" in=you>*${my.mail},${you.mail}";
        Map<String, Object> bindings = new HashMap<String, Object>();
        Assert.assertEquals(CallScriptMarkEngine(str, bindings, "testAssignObject"), " *chen@other.com,jsmith@other.com");
    }

    @Test
    public void testAssignObject2() throws Exception {
        String str = "<#assign mail=one in=\"my\"> <#assign mail=\"two\" in=you>*${my.mail},${you.mail}";
        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("one", "chen@other.com");
        bindings.put("two", "jsmith@other.com");
        Assert.assertEquals(CallScriptMarkEngine(str, bindings, "testAssignObject2"), " *chen@other.com,jsmith@other.com");
    }

    @Test
    public void testAssignJson() throws Exception {
        String str = "<#assign var=\"botton\">{name:\"btname\",value:\"1111\"}</#assign>${botton.name}";
        Map<String, Object> bindings = new HashMap<String, Object>();
        Assert.assertEquals(CallScriptMarkEngine(str, bindings, "testAssignJson"), "btname");
    }

    @Test
    public void testAssignNULL2() throws Exception {
        String str = "<#assign test=\"''\" /><#if where=!test>true</#if><#if where=!test>1<#else>2</#else></#if>";
        Map<String, Object> bindings = new HashMap<String, Object>();
        String temp = CallScriptMarkEngine(str, bindings, "testAssignNULL2");
        Assert.assertEquals(temp, "true1");
    }

    @Test
    public void testRequestNULL() throws Exception {
        String str = "1=${request.get('id').toBoolean()?true:false}2=${(!request.get('id').toBoolean())?true:false}3=${''?true:false}4=${(tmp.toBoolean())?true:false}";
        Map request = new RequestMap(null);
        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("tmp", "");
        bindings.put("request", request);
        String temp = CallScriptMarkEngine(str, bindings, "testRequestNULL");
        Assert.assertEquals(temp, "1=false2=true3=false4=true");
    }

    @Test
    public void testTypeOf() throws Exception {
        String str = "${!''?true:false} ${!'1'?true:false}";
        Map<String, Object> bindings = new HashMap<String, Object>();
        String temp = CallScriptMarkEngine(str, bindings, "testTypeOf");
        Assert.assertEquals(temp, "true false");
    }

    @Test
    public void testDateString() throws Exception {
        Date date = StringUtil.getDate("2012-01-12 12:37");
        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("date", date);
        String str = "${date.string('yyyy-MM-dd hh:mm')}";
        String temp = CallScriptMarkEngine(str, bindings, "testDateString");
        Assert.assertEquals(temp, "2012-01-12 12:37");
    }

    @Test
    public void testArrayFun() throws Exception {
        Map valueMap = new HashMap();
        valueMap.put("jumpFields", new String[]{"putUid", "putName", "ip"});
        String x = "${jumpFields.contains('ip')}${jumpFields.contains('xxx')}";
        String result = CallScriptMarkEngine(x, valueMap, "testArrayFun");
        Assert.assertEquals(result, "truefalse");
    }

    @Test
    public void testOptions() throws Exception {
        Map valueMap = new HashMap();
        valueMap.put("list", "调度证书;本科学历;健康证明;驾驶证".split(";"));
        valueMap.put("selected", "驾驶证");
        String x = "${list.options(selected)}";
        String result = CallScriptMarkEngine(x, valueMap, "testOptions");
        Assert.assertEquals(result, "<option value=\"调度证书\">调度证书</option><option value=\"本科学历\">本科学历</option><option value=\"健康证明\">健康证明</option><option value=\"驾驶证\" selected=\"selected\">驾驶证</option>");
    }

    @Test
    public void testBeanOptions() throws Exception {

        CertBean bean = new CertBean();
        Map valueMap = new HashMap();
        valueMap.put("bean", bean);
        String x = "${getOptions(bean,'certType')}";
        String result = CallScriptMarkEngine(x, valueMap, "testBeanOptions");
        Assert.assertEquals(result, "0:上岗证;1:奖状;2:处分");
    }

    @Test
    public void testBeanOptions2() throws Exception {

        CertBean bean = new CertBean();
        Map valueMap = new HashMap();
        bean.setInputType("textarea");
        valueMap.put("bean", bean);
        String x = "<#macro name=options>${list.options(selected)}</#macro><@options list=\"radio:单选;checkbox:多选;textfield:填空;textarea:简述题;line:分割线\" selected=bean.inputType />";
        String result = CallScriptMarkEngine(x, valueMap, "testBeanOptions2");
        Assert.assertEquals(result, "<option value=\"radio\">单选</option><option value=\"checkbox\">多选</option><option value=\"textfield\">填空</option><option value=\"textarea\" selected=\"selected\">简述题</option><option value=\"line\">分割线</option>");
    }

    @Test
    public void testBeanOptions3() throws Exception {

        CertBean bean = new CertBean();
        bean.setSortType(4);

        Map valueMap = new HashMap();
        valueMap.put("bean", bean);

        String x = "<#macro name=options>${list.options(selected)}</#macro><@options list=\"1:单选;2:多选;3:填空;4:简述题;5:分割线\" selected=bean.sortType />";
        String result = CallScriptMarkEngine(x, valueMap, "testBeanOptions3");
        Assert.assertEquals(result, "<option value=\"1\">单选</option><option value=\"2\">多选</option><option value=\"3\">填空</option><option value=\"4\" selected=\"selected\">简述题</option><option value=\"5\">分割线</option>");
    }

    @Test
    public void testImageFile() throws Exception {

        Map valueMap = new HashMap();
        valueMap.put("file1", "l23ij41l3/sda.foi/9udsf.jpg");
        valueMap.put("file2", "l23ij41l3/sda.foi/9udsf.jPg");
        valueMap.put("file3", "l23ij4fs1l3/1/9udsf.xpg");

        String x = "${file1.isImage()},${file2.isImage()},${file3.isImage()}";
        String result = CallScriptMarkEngine(x, valueMap, "testImageFile");
        Assert.assertEquals(result, "true,true,false");
    }

    @Test
    public void testIsGoodName() throws Exception {

        Map valueMap = new HashMap();
        valueMap.put("file1", "陈原");
        valueMap.put("file2", "[陈原]");
        valueMap.put("file3", "l2");

        String x = "${file1.isGoodName()},${file2.isGoodName()},${file3.isGoodName()}";
        String result = CallScriptMarkEngine(x, valueMap, "testIsGoodName");
        Assert.assertEquals(result, "true,false,true");
    }


    @Test
    public void testDate12() throws Exception {

        Map valueMap = new HashMap();
        String str1 = "2012-11-24 00:58:01";
        String str2 = "2012-11-24 00:01";
        String str3 = "2012-11-24 12:01";

        valueMap.put("date1", StringUtil.getDate(str1));
        valueMap.put("date2", StringUtil.getDate(str2));
        valueMap.put("date3", StringUtil.getDate(str3));


        String x = "${date1.string('yyyy-MM-dd hh:mm')},${date2.string('yyyy-MM-dd hh:mm')},${date3.string('yyyy-MM-dd hh:mm')}";
        String result = CallScriptMarkEngine(x, valueMap, "testDate12");
        Assert.assertEquals(result, "2012-11-24 12:58,2012-11-24 12:01,2012-11-24 12:01");
    }


    @Test
    public void testFormat() throws Exception {
        Map valueMap = new HashMap();
        String x = "<!--function content() parse begin-->";
        String result = CallScriptMarkEngine(x, valueMap, "testFormat");
        Assert.assertEquals(result, x);
    }

    @Test
    public void testShow1() throws Exception {
        Map valueMap = new HashMap();
        valueMap.put("mylist", "0:拟稿;2:待批;4:通过;6:不过;7:强制关闭;9:未知状态");
        valueMap.put("selected", "2");
        String x = "${mylist.show(selected)}";
        String result = CallScriptMarkEngine(x, valueMap, "testShow1");
        Assert.assertEquals(result, "待批");
    }


    @Test
    public void testShow() throws Exception {
        Map valueMap = new HashMap();
        valueMap.put("mylist", "0:拟稿;2:待批;4:通过;6:不过;7:强制关闭;9:未知状态");
        valueMap.put("sel", "2");
        String x = "<#macro name=show>${list.show(selected)}</#macro><@show list=mylist selected=sel />";
        String result = CallScriptMarkEngine(x, valueMap, "testShow");
        Assert.assertEquals(result, "待批");
    }

    @Test
    public void testType() throws Exception {

        Map valueMap = new HashMap();
        valueMap.put("mylist", "0:拟稿;2:待批;4:通过;6:不过;7:强制关闭;9:未知状态");
        valueMap.put("mylists", StringUtil.split("0:拟稿;2:待批;4:通过;6:不过;7:强制关闭;9:未知状态", ";"));
        valueMap.put("sel", 2);

        String x = "${mylists.getClass().getName()}";
        String result = CallScriptMarkEngine(x, valueMap, "testType");
        Assert.assertEquals(result, "[Ljava.lang.String;");

    }

    @Test
    public void testNote() throws Exception {
        String x =
                "<#assign var=mylist>[\"winter\",\"spring\",\"summer\",\"autumn\"]</#assign>" +
                        "<#list my=mylist>" +
                        "${my_index}.${my}\r\n" +
                        "</#list>" +

                        "<#list my=mylist2>" +
                        "${my}<#if where=my_has_next>-</#if>" +
                        "</#list>\r\n" +
                        "<!--#xxxxxxx#-->" +
                        "<#list my=mylist3>" +
                        "${my}<#if where=my_has_next>-</#if>" +
                        "</#list>";

        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("mylist2", new String[]{"one", "two"});
        bindings.put("mylist3", new Integer[]{4, 5});
        Assert.assertEquals(CallScriptMarkEngine(x, bindings, "testNote"), "0.winter\r\n1.spring\r\n2.summer\r\n3.autumn\r\none-two\r\n4-5");
    }

    @Test
    public void testErrorNote() throws Exception {
        String x =
                "123<!--#xxxxxxx #--<#list my=mylist3>${my}<#if where=my_has_next>-</#if></#list>";

        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("mylist2", new String[]{"one", "two"});
        bindings.put("mylist3", new Integer[]{4, 5});
        Assert.assertEquals(CallScriptMarkEngine(x, bindings, "testNote"), "123");
    }

    @Test
    public void testCodeFormatDef() throws Exception {
        String x = "<#assign var=codeFormatDef>\"\\${startDate.string('yyMMdd')}\\${createDate.string('dd')}\\${id.keepLength(4)}\"</#assign>${codeFormatDef}";
        Map<String, Object> bindings = new HashMap<String, Object>();
        bindings.put("startDate", StringUtil.getDate("2014-01-02 13:03"));
        String xxx = CallScriptMarkEngine(x, bindings, "testCodeFormatDef");
        Assert.assertEquals("${startDate.string('yyMMdd')}${createDate.string('dd')}${id.keepLength(4)}", xxx);
    }

    @Test
    public void testJson() throws Exception {

        String x = "<a href=\"http://www.mopaas.com/appDevContest/index.jsp\">开源应用开发大赛</a>";
        JSONObject json = new JSONObject();
        json.put("vv", x);
        Assert.assertEquals("{\"vv\":\"<a href=\\\"http://www.mopaas.com/appDevContest/index.jsp\\\">开源应用开发大赛</a>\"}", json.toString());
    }

    @Test
    public void testAssiagen() throws Exception {

        String x = "${var aa='testView@demo'.action(false,false)}${aa}";
        Map<String, Object> bindings = new HashMap<String, Object>();
        ActionSupport action = new ActionLogView();
        bindings.put("action", action);
        String xxx = CallScriptMarkEngine(x, bindings, "none");
        Assert.assertEquals(xxx.contains("jspx.example.view.TestView"), true);
    }

    @Test
    public void toChineseCurrency() throws Exception {

        String x = "${'123'.toChineseCurrency()}";
        Map<String, Object> bindings = new HashMap<String, Object>();
        String xxx = CallScriptMarkEngine(x, bindings, "none");
        Assert.assertEquals(xxx, "壹佰贰拾叁圆整");
    }

    @AfterClass
    public void afterExit() throws ScriptException {
        String zone = System.getProperty("user.timezone");
    }
}