Apache Commons JEXL 语法
27 Jun 2016
Reading time ~3 minutes
Apache Commons JEXL 语法
概述
这个参考分为以下章节:
如需JEXL语法的更多技术细节,你可以从Parser.jjt获取JEXL的JavaCC定义。
语法元素
注释
从##或//开始直至行末,如## 这是注释或// 这是注释。多行注释使用/*...*/,如
/* 这是一个
多行注释 */
标识符/变量
必须以a-z, A-Z, _, $开始,后边可以跟0-9, a-z, A-Z, _, $。举例: 合法:var1,_a99,$1
非法:9v,!a99,1$
变量名称是 大小写相关 的,如var1和Var1是不同的变量。 注意: JEXL 不支持变量名中出现连字符,如commons-logging // 非法的变量名(连字符) 是非法的变量,但是被作为变量commons减去变量logging处理。 JEXL 支持ant-style变量,my.dotted.var是一个合法的变量名。 注意 以下关键字是保留的,不能用做变量名或(点操作符后的)属性名。or and eq ne lt gt le ge div mod not null true false new var return。例如:下面的是非法的my.new.dotted.var // 非法 ('new' 是关键字),在这种情况下,应使用单引号或[]操作符以示区别,例如: my.'new'.dotted.var,my['new'].dotted.var
脚本(Scripts)
JEXL中的脚本包含0个或多个语句。脚本能够从字符串、文件或者URL读取。 脚本中可以包含命名参数,命名参数在执行时作为参数提供。 默认情况下,脚本将最后一个表达式的结果作为脚本的值返回。使用关键字return,脚本可返回紧跟其后的表达式(或 null )。
本地变量
使用关键字var定义本地变量,命名规则与上下文变量相同。 基本声明:var x;
赋值声明:var theAnswer = 42;
非法声明:var x.y;
本地变量的作用范围是当前脚本,并且比上下文变量优先生效。脚本包含的命名参数与本地变量表现一致。本地变量不能使用ant-style命名,只能包含一个标识符。
声明
声明可以是空的,分号,块,赋值和表达式。声明末尾的分号是可选的。
块
块是由大括号({, })包围的多个声明。
赋值
赋值给一个变量(my.var = 'a value')时,初始从JexlContext获取变量。同时支持 beans 和 ant-ish 方式的变量赋值。
方法调用
调用一个对象的方法,如"hello world".hashCode()将调用"hello world"字符串的hashCode方法。在多参数及重载情况下,JEXL 会尽力调用最恰当的无歧义的方法。
编译注解
声明一个编译注解,script用来与执行环境进行通讯,例如#pragma execution.option 42,将声明一个名称为execution.option值为42的编译注解。 编译注解的名称可以为标识符或链式名称,值可以是常量(boolean, integer, real, string, null, NaN) 和链式名称。
常量
整数常量
一个或多个数字(从0到9),如42。
浮点常量
一个或多个数字(从0到9),后跟小数点和1个或多个数字(从0到9),可选的以f或F结尾。如42.0或42.0f。
长整型常量
一个或多个数字(从0到9)后缀为l或L,如42l。
双精度常量
一个或多个数字(从0到9),后跟小数点和1个或多个数字(从0到9),以d或D结尾。如42.0d。
大整形常量
一个或多个数字(从0到9),以h或H结尾。(为了适应OGNL,不支持16进制数字),如42h。
大精度常量(BigDecimal)
一个或多个数字(从0到9),后跟小数点和1个或多个数字(从0到9),以b或B结尾。如42.0b。
自然常量 - 二进制和十六进制支持
自然常量(如:整型、长整型、大整型)支持与Java相同的二进制或十六进制表示。即:前缀0表示二进制,前缀0x或0X为十六进制。举例:010或0x10。
实数常量 - 指数支持
实数(即:浮点数、双精度数、大精度)能使用Java形式的指数符号表示。即:以紧跟+或-符号后跟一个或多个十进制数字的e或E作为后缀。如:42.0E-1D、42.0E+3B。
字符串常量
以'或"界定符开始和结束的量,即"你好世界"和'你好世界'等价。逃逸字符为\\;仅用来逃逸字符串界定符号。
多行格式字符串常量
以\界定符开始和结束的量,如`你好世界`。逃逸字符为\;仅用来逃逸字符串界定符号。这种格式的常量可以跨多行,并支持Unified JEXL表达式(类JSTL表达式)变量替换。如:环境中有一个变量(不论是本地还是全局变量)user值为JEXL,对`你好${user}`求得的值为你好JEXL`。
布尔量
常量true和false可以被使用,如:val1 == true
Null
Java中的null值用null表示,如val1 == null
数组
以[开始,后跟一个或多个以,分隔的表达式,以]结束,如[ 1, 2, "three"]。 JEXL尝试使用强类型数组;如果所有记录都是同一class或都为数值(Number的实例),数组两将为MyClass[]或Number[]。 此外,如果数组内所有记录都是同一类,且该类有等价的原始类型,数组将返回原始数组,如:[1, 2, 3]将求值为int[]。
集合
以{开始,后跟一个或多个以,分隔的表达式,以}结束,如{"one", 2, "more"}。这个语法创建一个HashSet。
映射
以{开始,后跟一个或多个以,分隔的键值对key : value,以}结束,如{ "one" : 1, "two" : 2, "three" : 3, "more": "many more" }。这个语法将创建HashMap。
函数
empty
判断一个表达式是否为’空’。当参数为如下值时返回真(true): null
C类的实例,C类在 JexlArithmetic 中重载实现了public boolean empty(C arg)且该函数对该实例返回true
空字符串
空集合(长度为0)
空映射(map)
实现了方法public boolean isEmpty(),并且该方法返回true
其它情况下返回false(除错误外)。 empty(arg)
size
获取一个表达式的’大小’。将返回: 0 如果参数null
返回JexlArithmetic中重载的public int size(C arg),如果参数是C的实例。
数组的长度
字符串的长度
Collection的大小
映射(Map)的大小
参数实现的public int size()的值
其它情况下返回0(除错误外)。 size("Hello")返回5。
new
使用全限定的类名或类创建一个新实例:new("java.lang.Double", 10)返回10.0。 注意:new的第一个参数可以为变量或者值为字符串或Class的表达式;余下的参数将被作为构造函数的参数。 多构造函数的情况下,JEXL 会尽力调用最恰当的无歧义的构造方法。
ns:function
可以注册对象或类到JexlEngine作为函数命名空间。这种情况下表达式为math:cosinus(23.0)。
自定义函数
在脚本内自定义函数,经常关联到一个本地变量。var fun = function(x, y) { x + y }。调用函数的习惯用法为:fun(17, 25)。 注意:方法可以使用声明时可见的本地变量和参数。var t = 20; var s = function(x, y) {x + y + t}; t = 54; s(15, 7),这个方法闭包使用声明时t的值;计算结果为15+7+20 = 42。
运算符
布尔and
常用的&&运算符,与单词and等同使用,举例:cond1 and cond2与cond1 && cond2等价。
布尔or
常用的||运算符,与单词or等同使用,举例:cond1 or cond2与cond1 || cond2等价。
布尔not
常用的!运算符,与单词not等同使用,举例:!cond1与not cond1等价。
位and
常用&运算符,举例:33 & 4,0010 0001 & 0000 0100 = 0。
位or
常用|运算符,举例:33 | 4,0010 0001 | 0000 0100 = 0010 0101 = 37。
位xor
常用^运算符,举例:33 ^ 4,0010 0001 ^ 0000 0100 = 0010 0101 = 37。
位complement
常用~运算符,举例:~33,~0010 0001 = 1101 1110 = -34。
三元条件?:
通常情况下三元条件condition ? if_true : if_false运算符。特定情况下能缩写为value ?: if_false,该缩写将返回value如果value为非空非假值。如:val1 ? val1 : val2和val1 ?: val2等效。 注意: 如果条件指向未定义变量或null,条件求值为false。这样能够方便的处理未定义或空或假这种情况。
等于
常用的==运算符,与缩写eq等同使用,举例:val1 == val2与val1 eq val2等价。 null仅与null相等,如果你比较空与任何非空值,结果为假。
等于使用java的equals方法。
不等
常用的!=运算符,与缩写ne等同使用,举例:val1 != val2与val1 ne val2等价。
小于
常用的
小于等于
常用的<=运算符,与缩写le等同使用,举例:val1 <= val2与val1 le val2等价。
大于
常用的>运算符,与缩写gt等同使用,举例:val1 > val2与val1 gt val2等价。
大于等于
常用的>=运算符,与缩写ge等同使用,举例:val1 >= val2与val1 ge val2等价。
包含或匹配 =~
得益于Perl的语法=~运算符能够被用来检查一个字符串匹配一个正则表达式(表达式可以为字符串或java.util.regex.Pattern)。如:"abcdef" =~ "abc.*返回真。它也检查任何集合或映射(用键)是否包含该值;在这种情况下,它的行为像’in’运算符。注意:数组被对待为”鸭子类型“的集合,就像类型暴露了一个contains方法。"a" =~ ["a","b","c","d","e",f"]返回真。
不包含或不匹配 !~
得益于Perl的语法!~运算符能够被用来检查一个string不匹配一个正则表达式(表达式可以为字符串或java.util.regex.Pattern)。如:"abcdef" !~ "abc.*返回假。它也检查任何集合或映射(用键)是否包含该值;在这种情况下,它的行为像’not in’运算符。注意:数组被对待为”鸭子类型“的集合,就像类型暴露了一个contains方法。"a" !~ ["a","b","c","d","e",f"]返回假。注:鸭子类型,暴露了公有contains方法的用户类,可以作为右操作数使用。
开始于=^
得益于CSS3的语法,=^运算符作为startsWith方法的简写。举例"abcdef" ^= "abc"返回真。注:作为鸭子类型,暴露了公有方法startsWith的用户类的实例可以作为左运算数。
不开始于!^
这是’开始于’操作符的反运算。a !^ "abc"等价于!(a =^ "abc")
结束于=$
得益于CSS3的语法,=$运算符作为endsWith方法的简写。举例"abcdef" =$ "def"返回真。注:作为鸭子类型,暴露了公有方法endsWith的用户类的实例可以作为左运算数。
不开始于!$
这是’开始于’操作符的反运算。a !$ "abc"等价于!(a =$ "abc")
范围..
这个操作符创建’范围’值(作为Java的iterable)。举例: for(var x: 1 .. 3) {}将循环3遍,x的值分别为1, 2, 3。
加
常规使用+运算符。如val1 + val2。 注意 字符串与其它类型相加时,所有操作数将作为字符串相加。即:'1'+2 == '12'。
减
常规使用-运算符。如val1 - val2。
乘
常规使用*运算符。如val1 * val2。
除
常规使用/运算符,或者使用div操作符。如val1 / val2或val1 div val2。
求余
常规使用%运算符,或者使用mod操作符。如5 mod 2 == 1等价于5 % 2 ==1。
取反
一元操作符-。-12
数组存取
数组元素可以使用方括号包围的或点后的数字存取,即:arr1[0]和arr1.0是等价的。
映射存取
映射元素使用方括号存取,即:map[0]; map['name']; map[var];。需要注意的是map['7']和map[7]指向不同的元素。以数值作为键的映射可以使用点操作符存取元素,即:map[0]和map.0是等效的。
条件语句
if
传统的if/else语句,即:
if ((x * 2) == 5) {
y = 1;} else {
y = 2;}
for
循环处理数组、集合、映射、迭代器、枚举,如:
for(item : list) {
x = x + item;}
item和list是变量。 不再支持 JEXL 1.1 中的foreach(item in list)语法。
while
循环处理直到满足条件。如:
while (x lt 10) {
x = x + 2;}