该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2009-02-23
最后修改:2009-10-31
IKExpressionV2.0简易表达式解析器使用说明
目录
注:V2.1.2已发布,请参考 http://linliangyi2007.iteye.com/blog/481407 1. IK表达式介绍(IK Expression Introduction) IK Expression是一个开源的(OpenSource),可扩展的(Extensible),基于java语言开发的一个超轻量级(Super lightweight)的公式化语言解析执行工具包。 IK ExpressionV2.0不依赖于任何第三方的java库。它做为一个简单的jar,可以集成于任意的Java应用中。这包括了JavaEE应用(基于应用服务器的), Java桌面应用以及Java WebStart方式的应用。 IK Expression最初诞生的原因是为了能增强工作流引擎,如jBPM等对流程配置的灵活度。使其能在流程运行期获得同配置期一样灵活地对执行逻辑条件进行变更。经过扩展后的IK Expression还可以适用于各种常规业务系统的动态条件配置,如需要图形化配置应用的场合,或是模拟Excel电子表格的公式运算的场景。 同EL和BeanScript不同,IK Expression的设计目标是面向最终用户的,因此它被设计成语法简单(像数学算式),通俗易懂(支持中文变量及函数名)但功能有限的解析引擎。如果你需要一个功能强大的表达式引擎,也许IK Expression并不是最好的选择。 1.1 概要(OverView) IK Expression是一个采用逆波兰式算法结合指针栈优化的公式解析引擎,它由表达式编译、、表达式执行、变量容器、以及函数配置管理四部分构成。它具有以下特点:
IK Expression 组件结构图
1.2 升级变更(Changes Log) Version2.0.2的变更:
Version2.0.1的变更:
Version2.0.0相对于V1.0的变更:
2. 快速入门(Quick Start) 2.1 下载(Downloadables Overview) GoogleCode开源项目:http://code.google.com/p/ik-expression/ GoogleCode SVN下载:http://ik-expression.googlecode.com/svn/trunk/ 2.2 安装部署 IK Expression 的安装部署十分简单,安装包包含:
2.3 API简易教程(API Tutorial) 代码样例HelloWorld /** * Hello World Example * @param args */ public static void main(String[] args){ if(args.length == 0){ args = new String[1]; args[0] = "IK Expression"; } //定义表达式 String expression = "\"Hello World \" + 用户名"; //给表达式中的变量 "用户名" 付上下文的值 List<Variable> variables = new ArrayList<Variable>(); variables.add(Variable.createVariable("用户名", args[0])); //执行表达式 Object result = ExpressionEvaluator.evaluate(expression, variables); System.out.println("Result = " + result); } 执行结果: Hello World IK Expression API说明 *类org.wltea.expression.ExpressionEvaluator 方法1: public static Object evaluate(String expression, Collection<Variable> variables) 说明:传入表达式和表达式上下文的变量,执行表达式返回结果 参数1 :String expression, 要传入执行的表达式 参数2 :Collection<Variable> variables 表达式上下文的变量集合(详细请看类org.wltea.expression.datameta.Variable的说明)。 返回值:表达式执行结果,可能是以下类型的java对象中的一种: Int、Long、Float、Double、Boolean、String、Date、List、Object。 方法2: public static Object evaluate(String expression) 说明:对方法1的重载,执行简单的没有变量的表达式。请参考方法1说明. *类org.wltea.expression.datameta.Variable 该类是用来表示表达式的上下文变量的,上面的例子中用到了别名为“用户名”的上下文变量,这是也是表达式最有用的地方。例如,在jBPM的流程定义中,我们需要定义一个报销审批流程中,用来决定流程分支走向的表达式: (申请金额 > 10000)?“总经理审批”:“部门经理审批” 这里需要定义一个别名为“申请金额“变量。变量通过evaluate(String expression, Collection<Variable> variables)方法中的variables参数传入表达式中。而Variable类型变量的构造十分的简单,它是标准的POJO。 方法1: public static Variable createVariable(String varName , Object varValue) 说明:根据参数别名和参数值,构造 Variable 实例 参数1 :String varName, 参数的别名,可以是中文别名 参数2 :Object varValue,参数的值 , 可以是下类型的java对象中的一种: Int、Long、Float、Double、Boolean、String、Date、List、Object。 返回值:org.wltea.expression.datameta.Variable类的实例 方法2:(直接使用构造函数) public Variable(String varName , DataType varDataType , Object varValue) 说明:根据指定的参数类型、参数别名和参数值,构造 Variable 实例 参数1 :String varName, 参数的别名,可以是中文别名 参数2 :DataType varDataType, 变量类型,它是 org.wltea.expression.datameta. BaseDataMeta.DataType枚举类型,包括的枚举值有:
参数3 :Object varValue,参数的值 , 可以是下类型的java对象中的一种: Int、Long、Float、Double、Boolean、String、Date、List、Object。 返回值:org.wltea.expression.datameta.Variable类的实例 3. 表达式公式规范(Expression Formula Specification) 3.1 数据类型(Types, Values, and Variables) a) 数字型 : i. 整形 integer : -2321 , 34234 ii. 长整型 long :3245235235L iii. 单精度浮点 float : 342.555F iv. 双精度浮点 double: 234234.3423 b) 字符型:“a-zA-Z012456789” c) 布尔型:true、false d) 日期时间型:[2008-08-08] 或 [2009-01-01 12:33:14] e) 扩展类型:List对象集合 (该类型不支持表达式字面定义,由操作符或函数运算结果生成) f) 通用对象:Object类型 (该类型不支持表达式字面定义,由操作符或函数运算结果生成) 3.2 运算符(Operators) 3.3 分割符(Separators)
3.4 内部函数(Inner Functions) 内置函数是目前解析器已经实现的一些非常简单、实用的函数 3.5 语法约束(Lexical Structure)
3.6 公式样例(Formula Example) 1. +、- 、* 、/ 、%(取模) 常规的算术运算,支持括号优先级 : 如:常见的OA中用于年休假工资计算公式 3000 / 21.5 *(12 - 转正月份)/ 2 其中,“转正月份”可以是上下文变量 2. 不同数据类型的字符串连接 : “ABC”+(123+10) 运算结果 “ABC133” “ABC”+ 123 + 10 运算结果“ABC12310” “[2009-08-08] + false + 123 + \"a String\" + null” 运算结果 “2009-08-08 00:00:00false123a String” (PS:忽略 null型变量) 3. > >= < <= == !=逻辑比较运算,返回布尔值 :
4. 逻辑与、逻辑或、逻辑非运算: true && $DAYEQUALS([2008-01-01] , [2008-11-01]) ——false true || $DAYEQUALS([2008-01-01] , [2008-11-01]) —— true true && !$DAYEQUALS([2008-01-01] , [2008-11-01]) —— true 5. 结果连接运算“#”: 1000/10 # [2008-12-23]>$SYSDATE() # “ABC”+123 运算结果 包含 100 , false , “ABC123”三种不同类型对象的List 6. 函数与操作符混合、嵌套调用,如: $DAYEQUALS( $CALCDATE( $SYSDATE() , 0 , 0 , (8+11-5*(6/3)) * (2- 59 % 7) , 0 ,0,0 ), [2009-10-01] ) 运算结果 false 4. 高级特性(Advance) 4.1 函数定制(Functions Customize) IK-Expression最吸引人的特性莫过于它允许你以非常简单的方式扩展你的自定义函数。IK-Expression带有一个xml配置文件functionConfig.xml。在使用IK-Expression时,该配置文件应放置于class的根目录中(如同spring和hibernate等的配置文件一样)。配置文件内部格式如下: functionConfig.xml <?xml version="1.0" encoding="UTF-8"?> <function-configuration> <!-- 系统函数默认配置 --> <bean class="org.wltea.expression.function.SystemFunctions"> <function name="CONTAINS" method="contains"> <parameter-type>java.lang.String</parameter-type> <parameter-type>java.lang.String</parameter-type> </function> <function name="STARTSWITH" method="startsWith"> <parameter-type>java.lang.String</parameter-type> <parameter-type>java.lang.String</parameter-type> </function> <function name="ENDSWITH" method="endsWith"> <parameter-type>java.lang.String</parameter-type> <parameter-type>java.lang.String</parameter-type> </function> <function name="CALCDATE" method="calcDate"> <parameter-type>java.util.Date</parameter-type> <parameter-type>int</parameter-type> <parameter-type>int</parameter-type> <parameter-type>int</parameter-type> <parameter-type>int</parameter-type> <parameter-type>int</parameter-type> <parameter-type>int</parameter-type> </function> <function name="SYSDATE" method="sysDate" /> <function name="DAYEQUALS" method="dayEquals"> <parameter-type>java.util.Date</parameter-type> <parameter-type>java.util.Date</parameter-type> </function> </bean> <!-- 用户函数配置 ,请在这里定制您自己的函数--> </function-configuration> 配置文件中默认配置了系统内部函数定义(在没有绝对必要的原因下,不建议修改系统默认函数配置)。在默认配置的下方,用户可以定义自己的函数,格式如下: 用户自定义函数配置 <bean class="org.wltea.expression.test.TestFunctions"> <constructor-args> <constructor-arg type="java.lang.Integer">123</constructor-arg> <constructor-arg type="java.lang.String">aa</constructor-arg> </constructor-args> <function name="问好" method="sayHello"> <parameter-type>java.lang.String</parameter-type> </function> </bean> 这里自定义了一个名称为“问好”的函数,它有一个String类型的参数。该函数映射对应于org.wltea.expression.test.TestFunctions类的sayHello方法,而类org.wltea.expression.test.TestFunctions具有一个构造函数,构造函数带有Integer型和String型的参数。配置中给出了构造函数的初始化参数“123”和“aa”。通过上述定义,用户就可以在表达式中使用该函数,如: $问好(当前用户) , 其中“当前用户”为表达式的上下文变量。 上述例子直观的展示了用户函数自定义的过程。下面,我们将系统的了解一下IK-Expression的函数扩展定义规则和约束: 1. 在IK-Expression中,函数直接对应于java的一个类的一个明确的方法。如:$CONTAINS对应org.wltea.expression.function.SystemFunctions类的contains方法; 2. 所有的函数定义前,必须先定义对应的java类。如果该类使用带参数的构造函数,则必须提供明确的构造参数,如: <bean class="org.wltea.expression.test.TestFunctions"> <constructor-args> <constructor-arg type="java.lang.Integer">123</constructor-arg> <constructor-arg type="java.lang.String">aa</constructor-arg> </constructor-args> <function name="问好" method="sayHello"> <parameter-type>java.lang.String</parameter-type> </function> </bean> 3. java类的加载和实例化在初始化阶段一次性完成。目前IK-Expression仅支持单例形式的加载,即对一个java类仅实例化一次。 4. 定义函数时,必须明确定义函数对应java方法,以及java方法的参数类型和顺序,如: <function name="CONTAINS" method="contains"> <parameter-type>java.lang.String</parameter-type> <parameter-type>java.lang.String</parameter-type> </function> 你可以使用不同的函数名(英文的和中文的),对应相同的java方法,但对java中的方法重载必须使用不同的函数名对应(即,IK-Expression不支持函数名重载) 5. 函数的参数和返回值只能是IK-Expression支持的数据类型(请参考3.1数据类型 章节). 6. 为了增加灵活性,IK-Expression给出了一个通过编码方式添加自定义函数的static方法。 函数扩展API说明 *类org.wltea.expression.function.FunctionLoader 方法1: public static void addFunction(String functionName, Object instance, Method method) 参数1 :String functionName, 要定义的函数名称(中英文皆可)。 参数2 :Object instance 函数要映射的java 类的实例。 参数3 :Method method 函数要映射的java 类的方法对象。 (全文终)
下载地址:http://code.google.com/p/ik-expression/downloads/list 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-02-23
牛B啊!!!
|
|
返回顶楼 | |
发表时间:2009-02-23
现在正需要这个东西呢。谢谢!楼主!
|
|
返回顶楼 | |
发表时间:2009-02-23
不错啊 hr里 正需要这东西
|
|
返回顶楼 | |
发表时间:2009-02-23
很高兴能对大伙起帮助:)
|
|
返回顶楼 | |
发表时间:2009-02-23
linliangyi的东东一定要支持!O(∩_∩)O哈哈~
|
|
返回顶楼 | |
发表时间:2009-02-24
支持,支持,希望用上的人都来发表一下意见。。呵呵~~
|
|
返回顶楼 | |
发表时间:2009-02-24
呵呵,我目前用的是BeanShell。
如果以后业务有需求,我会考虑用用编译原理的“语法解析器”进行处理,典型的框架有 antlr,Hibernate用的就是他,效率也不低。 |
|
返回顶楼 | |
发表时间:2009-02-24
佩服楼主的水平,但一般表达式我用动态语言来解决,比如groove.一来稳定,性能也非常好,并且各种运算函数包齐。
|
|
返回顶楼 | |
发表时间:2009-02-24
这个,,,jdk6里有现成的js解析器,把js写在条件表达式里,然后在jvm里执行可以达到同样的效果.
|
|
返回顶楼 | |