基于多子节点筛选重复XPath节点的技术方案问询
用XPath筛选XML中的重复ALIAS节点并输出提示信息
需求说明
给定如下XML结构:
<root> <Roles> <Role> <ALIAS> <!-- COMMENT 1--> <alias.src_id>LONDON</alias.src_id> <alias.tms/> <alias.id>0000012345</alias.id> <alias.id_type>CITY</alias.id_type> </ALIAS> <ALIAS> <!-- COMMENT 2--> <alias.src_id>LONDON</alias.src_id> <alias.tms/> <alias.id>0000099999</alias.id> <alias.id_type>PLACE</alias.id_type> </ALIAS> <ALIAS> <!-- COMMENT 3--> <alias.src_id>FRANKFURT</alias.src_id> <alias.tms/> <alias.id>000000001</alias.id> <alias.id_type>CITY</alias.id_type> </ALIAS> <ALIAS> <!-- COMMENT 4--> <alias.src_id>PARIS</alias.src_id> <alias.tms/> <alias.id>0000012345</alias.id> <alias.id_type>CAPITAL</alias.id_type> </ALIAS> <ALIAS> <!-- COMMENT 5--> <alias.src_id>LONDON</alias.src_id> <alias.tms/> <alias.id>0000012345</alias.id> <alias.id_type>CITY</alias.id_type> </ALIAS> </Role> </Roles> </root>
需要筛选出完全重复的ALIAS节点(示例中仅注释1和5的节点重复),并输出类似WARNING! Duplicated comment: LONDON - 0000012345 - CITY的提示信息。
之前尝试的问题
- 单独匹配子节点的表达式:
/root/Roles/Role/ALIAS[alias.src_id=following-sibling::ALIAS/alias.src_id][alias.tms=''][alias.id=following-sibling::ALIAS/alias.id][alias.id_type=following-sibling::ALIAS/alias.id_type]/alias.id/text()
该表达式的问题在于,每个条件独立匹配不同的后续节点(比如src_id匹配一个后续节点,id匹配另一个),而非同一个后续节点满足所有子节点的匹配条件,导致误判所有节点为重复。
- 拼接字符串比较的表达式:
/root/Roles/Role/ALIAS[concat(alias.src_id,' - ',alias.tms,' - ',alias.id,' - ',alias.id_type)=following-sibling::ALIAS/concat(alias.src_id,' - ',alias.tms,' - ',alias.id,' - ',alias.id_type)]/alias_id/text()
部分工具支持此写法,但存在两个潜在问题:一是部分XPath 1.0工具对轴节点内使用concat支持有限;二是表达式末尾拼写错误(应为alias.id/text()而非alias_id/text())。
可行解决方案
方案1:XPath 1.0兼容表达式(定位重复节点)
使用current()函数确保所有子节点匹配的是同一个后续节点,表达式如下:
/root/Roles/Role/ALIAS[following-sibling::ALIAS[ alias.src_id=current()/alias.src_id and alias.tms=current()/alias.tms and alias.id=current()/alias.id and alias.id_type=current()/alias.id_type ]]
该表达式会选中所有后续存在完全相同副本的ALIAS节点(示例中会选中注释1对应的节点)。若要同时选中重复的副本(注释5的节点),可补充preceding-sibling的判断:
/root/Roles/Role/ALIAS[ following-sibling::ALIAS[ alias.src_id=current()/alias.src_id and alias.tms=current()/alias.tms and alias.id=current()/alias.id and alias.id_type=current()/alias.id_type ] or preceding-sibling::ALIAS[ alias.src_id=current()/alias.src_id and alias.tms=current()/alias.tms and alias.id=current()/alias.id and alias.id_type=current()/alias.id_type ] ]
方案2:XPath 2.0+生成提示信息
若工具支持XPath 2.0或更高版本,可直接生成目标提示文本:
for $alias in /root/Roles/Role/ALIAS[ following-sibling::ALIAS[ alias.src_id=$alias/alias.src_id and alias.tms=$alias/alias.tms and alias.id=$alias/alias.id and alias.id_type=$alias/alias.id_type ] ] return concat( 'WARNING! Duplicated comment: ', $alias/alias.src_id/text(), ' - ', $alias/alias.id/text(), ' - ', $alias/alias.id_type/text() )
此表达式会遍历所有存在后续副本的节点,直接输出格式化的警告信息。
方案3:XPath 1.0拼接提示文本
若仅支持XPath 1.0,可通过concat拼接选中节点的信息(仅返回第一个匹配节点的提示,若需所有结果需工具支持迭代):
concat( 'WARNING! Duplicated comment: ', /root/Roles/Role/ALIAS[following-sibling::ALIAS[ alias.src_id=current()/alias.src_id and alias.tms=current()/alias.tms and alias.id=current()/alias.id and alias.id_type=current()/alias.id_type ]]/alias.src_id/text(), ' - ', /root/Roles/Role/ALIAS[following-sibling::ALIAS[ alias.src_id=current()/alias.src_id and alias.tms=current()/alias.tms and alias.id=current()/alias.id and alias.id_type=current()/alias.id_type ]]/alias.id/text(), ' - ', /root/Roles/Role/ALIAS[following-sibling::ALIAS[ alias.src_id=current()/alias.src_id and alias.tms=current()/alias.tms and alias.id=current()/alias.id and alias.id_type=current()/alias.id_type ]]/alias.id_type/text() )
内容的提问来源于stack exchange,提问作者Esteban JR
相关产品推荐
相关产品推荐

