MySQL UpdateXML函数更新第二个XML节点未生效问题
问题根因
XPath中的位置索引是匹配执行时刻DOM结构下的实时顺位,不是初始XML里的静态位置,你的逐次替换流程实际执行逻辑如下:
- 初始XML有3个
<b>节点,顺位1为111、顺位2为222、顺位3为333。第一次替换/a/b[1]成功将111替换为<e>节点,此时XML内只剩2个<b>节点:顺位1是222、顺位2是333。 - 第二次执行替换时你写的匹配规则是
/a/b[2],此时匹配到的是当前排第2位的333,于是把333替换为<e>节点,这时候XML里只剩1个<b>节点:顺位1是222。 - 第三次执行替换时你写的匹配规则是
/a/b[3],当前DOM里总共只有1个<b>节点,无法找到顺位3的匹配目标,因此这步UpdateXML不会做任何修改,值为222的<b>节点就被保留下来,最终得到你看到的错误结果。
可行解决方案
你可以任选一种方式修复:
方案1:固定每次替换当前第一个<b>节点
每次替换都匹配顺位1的<b>节点,替换掉第一个之后,原来排第二的节点会自动成为新的顺位1,不需要动态调整索引:
SET @xml = '<a><b>111</b><b>222</b><b>333</b></a>'; SELECT UpdateXML(@xml, '/a/b[1]', Concat('<e>', Extractvalue(@xml,'/a/b[1]'),'</e>')) INTO @xml; SELECT UpdateXML(@xml, '/a/b[1]', Concat('<e>', Extractvalue(@xml,'/a/b[1]'),'</e>')) INTO @xml; SELECT UpdateXML(@xml, '/a/b[1]', Concat('<e>', Extractvalue(@xml,'/a/b[1]'),'</e>')) INTO @xml; SELECT @xml; -- 正确输出:<a><e>111</e><e>222</e><e>333</e></a>
方案2:从后往前反向替换
替换靠后的节点不会影响前面节点的顺位,因此从最大的索引开始往前替换,不会出现索引偏移问题:
SET @xml = '<a><b>111</b><b>222</b><b>333</b></a>'; -- 按3→2→1的顺序从后往前替换 SELECT UpdateXML(@xml, '/a/b[3]', Concat('<e>', Extractvalue(@xml,'/a/b[3]'),'</e>')) INTO @xml; SELECT UpdateXML(@xml, '/a/b[2]', Concat('<e>', Extractvalue(@xml,'/a/b[2]'),'</e>')) INTO @xml; SELECT UpdateXML(@xml, '/a/b[1]', Concat('<e>', Extractvalue(@xml,'/a/b[1]'),'</e>')) INTO @xml; SELECT @xml; -- 正确输出:<a><e>111</e><e>222</e><e>333</e></a>
注意:MySQL的
UpdateXML单次只能替换匹配到的第一个节点,不支持批量替换多节点,如果<b>节点数量不固定,建议写存储过程循环判断是否还存在<b>节点,每次替换第一个直到没有匹配节点为止。
内容的提问来源于stack exchange,提问作者RickyBelmont
相关产品推荐
相关产品推荐

