项目场景
在一个数据清洗、同步的需求中;有一个要求是判断两个数值是否在正常范围内,并根据判断结果给出异常标记。但这两个数值是以XML的格式存储在Oracle的CLOB字段中,且在同一个XML节点中。该节点的内容如下:
"OD: 17.4 mmHg OS: 15.1 mmHg"
必须取出其中的17.4,15.1两个值才可以进行判断。这个点还是困扰了我个把个小时,各种百度没有一个理想的结果。
问题分析
从XML中取出该节点是很简单的,直接在SQL中就可以取出,代码如下:
(因为涉及到公司业务隐私,表名、字段名都做了匿名化改动,且删除了无关字段)
SELECT
SUBSTR(NMB1.RPT_CONT,
INSTR(NMB1.RPT_CONT,'<findings>')+10,
(INSTR(NMB1.RPT_CONT,'</findings>') - INSTR(NMB1.RPT_CONT,'<findings>' ) - 10)) AS FINDINGS
/*CHANGE_FLAG的判断在这里写太复杂难看,放在js组件中去判断*/
FROM NMB1
无论从上帝视角还是问题未解决前的情况来看的话,写SQL也能解决将两个数值从一个字符串中取出的问题,但那样的SQL太臭太长了。所以将其放到kettle的Java script 组件中去写代码解决。
按照既往的经验,可以用正则表达式很轻松的取出一个字符串中的数字,代码如下:
var price ="价格10000元,不贵";
var num = price.replace(/[^0-9|.]/ig,""); //小数点不排除掉(保留小数点)
但是这次的情况是需要取出 一个字符串中的两个数值,如果还是按照上述正则方法的话,只能得到【17.415.1】这样的数字,做不了判断,没有意义。
咋办勒?
这个时候就需要一句名人名言了:“技术太菜,曲线救国”
- 把"OD: 17.4 mmHg OS: 15.1 mmHg"这个字符串拆分成两个字符串;
- 每个字符串中只包含一个数值
- 然后再用上文叙述的正则方法取出其中的数值
- 拿到数值后再进行正常范围判断
那怎么将"OD: 17.4 mmHg OS: 15.1 mmHg"这种字符串拆成分别包含一个数值的两个字符串呢?
大家还记得我们上面是怎么把xml节点取出来的吗?是混合使用了substr和instr函数;那么在此处我们依然可以用该思路去做。但kettle的Java script组件中是没有instr函数的,与之类似功能的函数是indexOf(),我们就可以利用Java script的内置函数indexOf()和substr()去落实该思路。
代码展现
下面就是上述思路的一个完整代码(Java script组件)
//Script here
var CHANGE_FLAG = "";
var maxvalue = 21;
var minvalue = 10;
var FINDINGS = FINDINGS;
var index1 = 0;
var str1 = "";
var OD = 0
if(FINDINGS != null && FINDINGS.length != 0){
index1 = indexOf(FINDINGS,"mmHg")
str1 = substr(FINDINGS,0,index1)
OD = str1.replace(/[^0-9|.]/ig,"")
}else{
OD = 0
}
var index2 = 0;
var str2 = "";
var OS = 0
if(FINDINGS != null || FINDINGS.length != 0){
index2 = indexOf(FINDINGS,"OS")
str2 = substr(FINDINGS,0,index2)
OS = str2.replace(/[^0-9|.]/ig,"")
}else{
OS = 0
}
if(OD > maxvalue || OS > maxvalue || OD < minvalue || OS < minvalue){
CHANGE_FLAG = "异常"
}
下面是Java script组件的实际例子,大家可以参考。
下图是预览数据片段,已经达到期望要求。