最近在做一个银行支付的需求,测试银行的支付反馈,银行通知回来的是一个xml格式的字符串,示例如下
<shopOrderService version='1.0'> <orderData id='63340519408918945280394799954349' shopTraceNo='7' success='00'> <submitTime>20160810142922</submitTime> <merchant id='002777982990003' /> <transData type='020211'> <installments timing='3'></installments> <shopBatchNo>20101110</shopBatchNo> <remark>分期测试</remark> <addData>测试</addData> <transAmount>200000</transAmount> <totalAmount currency='156'>200000</totalAmount> <hbAmount>0</hbAmount> <returnCode>00</returnCode> <returnMessage>支付成功</returnMessage> <authCode>737722</authCode> <traceNo>757798</traceNo> <batchNo>881170</batchNo> <invoiceNo>757798</invoiceNo> <hostTransTime>20160810142922</hostTransTime> </transData> <pospOrderId>563620</pospOrderId> <card no='************2599'></card> </orderData> </shopOrderService>
然后,众多的属性和节点中,每个订单返回的xml数据格式还不一定一致,但是肯定的是 id='63340519408918945280394799954349'属性 和
returnMessage 节点是一定能有返回值的,而恰好,我这里只需要取得这两个值就可以了
以往的经验刚开始的第一思路都是要解析xml方式获取这两个值,判断属性是不是id,判断节点是不是returnMessage,等,然后在想了想我只需要获取以上两个值就可以了,使用xml方式是不是有点太繁琐,而且效率也不高。干脆直接使用正则表达式来匹配算了,正好最近使用正则表达式中的零宽断言,我想肯定会搞出来的!
首先我的第一版是这样的
String content = "<shopOrderService version='1.0'><orderData id='63340519408918945280394799954349' shopTraceNo='7' success='00'><submitTime>20160810142922</submitTime><merchant id='002777982990003' /><transData type='020211'><installments timing='3'></installments><shopBatchNo>20101110</shopBatchNo><remark>分期测试</remark><addData>测试</addData><transAmount>200000</transAmount><totalAmount currency='156'>200000</totalAmount><hbAmount>0</hbAmount><returnCode>00</returnCode><returnMessage>支付成功</returnMessage><authCode>737722</authCode><traceNo>757798</traceNo><batchNo>881170</batchNo><invoiceNo>757798</invoiceNo><hostTransTime>20160810142922</hostTransTime></transData><pospOrderId>563620</pospOrderId><card no='************2599'></card></orderData></shopOrderService>"; // 匹配订单号 Pattern pattern = Pattern.compile("(?<=id=\')\\d{32}+"); Matcher matcher = pattern.matcher(content); while(matcher.find()){ System.out.println("订单号:"+matcher.group()); } // 匹配状态码 Pattern pattern2 = Pattern.compile("(?<=<returnMessage>)([^<])+"); Matcher matcher2 = pattern2.matcher(content); while(matcher2.find()){ System.out.println("状态:"+matcher2.group()); } 结果: 订单号:63340519408918945280394799954349 状态:支付成功
搞定,就是这么soeasy,上面正则用到了零宽断言语法,不明白的在站点搜索关键字:零宽断言
但是感觉还是不够美观,有点强迫症的我,就像,两个需求能不能用一条正则表达式来写,这样,我就可以用一个while循环遍历我需要的结果,这么做不是可以做到代码优化了么?,说干就干
第二个版本代码如下
Pattern pattern = Pattern.compile("((?<=id=\')\\d{32}+|(?<=<returnMessage>)([^<])+)"); Matcher matcher = pattern.matcher(content); while(matcher.find()){ System.out.println(matcher.group()); } 结果: 订单号:63340519408918945280394799954349 状态:支付成功
这段正则中使用了 |
表达式,表示或,(正则A | 正则B)
是不是代码一下子变得简洁了许多,然而,这就完了,怎么可能,仔细想想,如果上面的xml中不是一个id匹配,或不是一个returnMessage匹配,那上吗的代码匹配出来的结果,可就不一定正确了,很有可能你匹配的前几行都是id也不一定。所以第三版代码就行了正确优化
Pattern pattern = Pattern.compile("((?<id>(?<=id=\')\\d{32}+)|(?<return>(?<=<returnMessage>)([^<])+))"); Matcher matcher = pattern.matcher(content); while(matcher.find()){ if (matcher.group("id") != null) { System.out.println(matcher.group("id")); } if (matcher.group("return") != null) { System.out.println(matcher.group("return")); } } 结果: 订单号:63340519408918945280394799954349 状态:支付成功
这样看起来,就放心多了。
第三版中使用了,java中matcher.group(string name)的语法,不明白的可以看看我的上一篇文章《Java 正则表达式 Pattern类与Matcher类详解》 关于零宽断言的其他用途,可以在站点中搜索关键字: 零宽断言