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<Object>
。
映射
以{
开始,后跟一个或多个以,
分隔的键值对key : value
,以}
结束,如{ "one" : 1, "two" : 2, "three" : 3, "more": "many more" }
。这个语法将创建HashMap<Object, Object>
。
函数
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
等价。
小于
常用的<
运算符,与缩写lt
等同使用,举例:val1 < val2
与val1 lt 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;}