XML的XPath验证规则编写及现有表达式评审请求
XPath规则验证与表达式评审
待验证的XML示例
<root> <CUSTOMER_ID>0010059863</CUSTOMER_ID> <PO_NUMBER>6873w/PO_NUMBER</PO_NUMBER> <VENDOR_ORDER_NUMBER>0038447</VENDOR_ORDER_NUMBER> </root>
验证规则
- CUSTOMER_ID必须存在、非空,长度范围1-10
- PO_NUMBER长度1-20,可空或不存在;但仅当VENDOR_ORDER_NUMBER不存在时,PO_NUMBER必须有有效值
- VENDOR_ORDER_NUMBER长度1-10,可空或不存在;但仅当PO_NUMBER不存在时,VENDOR_ORDER_NUMBER必须有有效值
- PO_NUMBER与VENDOR_ORDER_NUMBER至少存在一个,也可同时存在
- 所有字段必须符合长度要求
- PO_NUMBER和VENDOR_ORDER_NUMBER允许为空标签(即标签存在但内容为空)
对你编写的XPath的评审
你的XPath存在以下问题:
- 重复冗余:多次重复验证CUSTOMER_ID的条件,表达式冗长,后期维护成本高
- 逻辑漏洞:未处理PO_NUMBER或VENDOR_ORDER_NUMBER存在但为空标签的合法场景(规则6允许这种情况,但你用
//PO_NUMBER!=""直接排除了空标签) - 长度验证错误:规则要求PO_NUMBER长度上限为20,但表达式里有一处写了
string-length(//PO_NUMBER)<=10,不符合规则要求 - 场景覆盖不全:未覆盖“PO_NUMBER存在但为空,同时VENDOR_ORDER_NUMBER合法”或者“VENDOR_ORDER_NUMBER存在但为空,同时PO_NUMBER合法”的情况
优化后的XPath实现方案
我们可以将条件拆分为独立模块,通过逻辑组合简化表达式,同时覆盖所有规则:
XPath 1.0兼容版本
boolean(//CUSTOMER_ID) and string-length(normalize-space(//CUSTOMER_ID)) >= 1 and string-length(normalize-space(//CUSTOMER_ID)) <= 10 and ( (boolean(//PO_NUMBER) and string-length(normalize-space(//PO_NUMBER)) >= 1 and string-length(normalize-space(//PO_NUMBER)) <= 20) or (boolean(//VENDOR_ORDER_NUMBER) and string-length(normalize-space(//VENDOR_ORDER_NUMBER)) >= 1 and string-length(normalize-space(//VENDOR_ORDER_NUMBER)) <= 10) ) and (boolean(//PO_NUMBER) or boolean(//VENDOR_ORDER_NUMBER)) and (boolean(//PO_NUMBER) or (boolean(//VENDOR_ORDER_NUMBER) and string-length(normalize-space(//VENDOR_ORDER_NUMBER)) >= 1)) and (boolean(//VENDOR_ORDER_NUMBER) or (boolean(//PO_NUMBER) and string-length(normalize-space(//PO_NUMBER)) >= 1))
说明
- 用
normalize-space()处理空标签和纯空格内容,既允许合法的空标签,又排除无效的空白内容 - 将CUSTOMER_ID的验证逻辑抽离,避免重复编写相同条件
- 分模块验证核心规则:确保至少一个订单号存在、当其中一个不存在时另一个必须有效、各自长度符合要求
XPath 2.0+简洁版本
如果环境支持XPath 2.0及以上,使用every...satisfies和exists()函数能让逻辑更清晰:
every $cid in //CUSTOMER_ID satisfies (string-length(normalize-space($cid)) ge 1 and string-length(normalize-space($cid)) le 10) and ( exists(//PO_NUMBER[string-length(normalize-space(.)) ge 1 and string-length(normalize-space(.)) le 20]) or exists(//VENDOR_ORDER_NUMBER[string-length(normalize-space(.)) ge 1 and string-length(normalize-space(.)) le 10]) ) and (exists(//PO_NUMBER) or exists(//VENDOR_ORDER_NUMBER)) and (exists(//PO_NUMBER) or exists(//VENDOR_ORDER_NUMBER[string-length(normalize-space(.)) ge 1])) and (exists(//VENDOR_ORDER_NUMBER) or exists(//PO_NUMBER[string-length(normalize-space(.)) ge 1]))
内容的提问来源于stack exchange,提问作者Sugata Bagchi
相关产品推荐
相关产品推荐

