PostgreSQL中XPath查询返回空,疑为命名空间问题求解决
问题描述
我编写了PostgreSQL的xpath查询:
WITH cte AS ( SELECT message::xml as res FROM messages_table a WHERE a.id = '123' AND a.service = 'MY_SERVICE' AND a.call_type = 'RESPONSE' ) SELECT xpath('/g:Message/g:Result/text()', res, array[array['g','http://www.nw.co.uk/ni/ws/2004/02/Standard']]) as result -- SELECT res FROM cte;
查询结果返回空数组:
result xml[] ------- {}
对应的XML内容结构如下:
<?xml version="1.0" encoding="UTF-8"?> <Message Type="Response" Version="1" xmlns:dp="nw.co.uk:dp-1" xmlns:nu="http://www.nw.co.uk/ni/ws/2004/02/Standard"> <Result Completed="Y" ErrorCount="0" Ref="RF"> <Data Type="Output" dp:Instance="1"> <Item dp:Instance="1"> <Item_Class Val="5"/> <Item_Rate Val="1"/> <Item_Age Val="45.68306"/> <Item_AgeOfYoungestDriver Val="150"/> <Item_No Val="2"/> </Item> <Item dp:Instance="2"> <Item_Age Val="0"/> <Item_No Val="0"/> </Item> </Data> </Result> </Message>
请问该问题是否与XML中存在两个命名空间属性有关?若有关,应如何解决?
问题分析与解决
这个问题和XML里的命名空间有关,但核心是前缀绑定错误+XPath路径逻辑错误:
- 命名空间前缀绑定不匹配:你在查询里把
http://www.nw.co.uk/ni/ws/2004/02/Standard绑定到了g前缀,但XML里该命名空间的前缀是nu;更关键的是,Message和Result元素没有带任何前缀,它们不属于这个命名空间(XML里仅声明了命名空间前缀,没有把该空间设为默认,也没有给元素加前缀)。 - XPath路径逻辑错误:你写的
/g:Message/g:Result/text()是想取Result的文本内容,但Result内部是Data子元素,没有直接文本节点,自然返回空。
正确处理方案
场景1:获取Result的属性值(如Completed)
因为Message和Result不属于任何命名空间,直接写路径即可:
WITH cte AS ( SELECT message::xml as res FROM messages_table a WHERE a.id = '123' AND a.service = 'MY_SERVICE' AND a.call_type = 'RESPONSE' ) SELECT xpath('/Message/Result/@Completed', res) as result FROM cte;
返回结果:{"Y"}
场景2:若目标元素属于nu命名空间(假设XML漏写前缀)
如果XML里的Message和Result应该带nu:前缀,需正确绑定前缀后查询:
WITH cte AS ( SELECT message::xml as res FROM messages_table a WHERE a.id = '123' AND a.service = 'MY_SERVICE' AND a.call_type = 'RESPONSE' ) SELECT xpath('/nu:Message/nu:Result/@Completed', res, array[array['nu','http://www.nw.co.uk/ni/ws/2004/02/Standard']]) as result FROM cte;
场景3:获取Result下子元素的属性值(如第一个Item_Class的Val)
直接按层级路径查询即可:
WITH cte AS ( SELECT message::xml as res FROM messages_table a WHERE a.id = '123' AND a.service = 'MY_SERVICE' AND a.call_type = 'RESPONSE' ) SELECT xpath('/Message/Result/Data/Item[1]/Item_Class/@Val', res) as result FROM cte;
返回结果:{"5"}
场景4:获取带dp前缀的属性值(如dp:Instance)
需绑定dp对应的命名空间:
WITH cte AS ( SELECT message::xml as res FROM messages_table a WHERE a.id = '123' AND a.service = 'MY_SERVICE' AND a.call_type = 'RESPONSE' ) SELECT xpath('/Message/Result/Data/@dp:Instance', res, array[array['dp','nw.co.uk:dp-1']]) as result FROM cte;
返回结果:{"1"}
内容的提问来源于stack exchange,提问作者runnerpaul
相关产品推荐
相关产品推荐

