获取 XML 的属性值

ROA*_*OAL 0 xml sql-server

我在 SE 上至少回答了 5 个问题,但我一定已经因为沮丧而做了一些非常糟糕的事情。

我有一个存储过程,它返回这样的 XML:

<pmsg:Messages>
    <pmsg:Message Info="blah" />
</pmsg:Messages>
Run Code Online (Sandbox Code Playgroud)

我需要获取Info.

DECLARE @xmlMessage XML;

EXEC procReturnsXml @xmlMessage OUTPUT;

 -- returns 0 rows
WITH XMLNAMESPACES('pmsg' AS pmsg)
SELECT msgs.msg.value('@Info', 'nvarchar(max)')
FROM   @xmlMessage.nodes('pmsg:Messages/pmsg:Message') msgs(msg);

 -- returns NULL
WITH XMLNAMESPACES('pmsg' AS pmsg)   
SELECT @xmlMessage.value('(/pmsg:Messages/pmsg:Message/@Info)[1]', 'nvarchar(max)');

-- returns NULL
WITH XMLNAMESPACES('pmsg' AS pmsg)  
SELECT t.x.value('(/pmsg:Messages/pmsg:Message/@Info)[1]', 'nvarchar(max)') AS INFO
FROM   @xmlMessage.nodes('/*') t(x); 
Run Code Online (Sandbox Code Playgroud)

一般来说,我根本不明白这些是什么意思。你能提供一个关于这个案例的例子吗?

小智 5

我相信您得到这些结果的原因是 xml 的命名空间与 select 语句中的命名空间不同。我已经改变了你的例子来简要解释每个案例。

declare @xmlMessage xml

set @xmlMessage ='<pmsg:Messages xmlns:pmsg="pmsg">
    <pmsg:Message Info="blah"/>
    <pmsg:Message Info="blah"/>
</pmsg:Messages>'

;WITH XMLNAMESPACES('pmsg' as pmsg)
SELECT msgs.msg.value('@Info', 'nvarchar(max)') FROM @xmlMessage.nodes('pmsg:Messages/pmsg:Message') msgs(msg); 
-- return twos rows 'blah'
Run Code Online (Sandbox Code Playgroud)

nodes() 表达式提供了一组两个 pmsg:Message 节点,select 从每一行读取 @Info 的值。

;WITH XMLNAMESPACES('pmsg' as pmsg)
SELECT @xmlMessage.value('(/pmsg:Messages/pmsg:Message/@Info)[1]', 'nvarchar(max)'); 
--Returns a single rowset of one row containing 'blah'
Run Code Online (Sandbox Code Playgroud)

这只会返回一行 'blah',因为查询中的 [1] 限制为找到的第一项。实际上在这种形式中 [1] 是必需的。SQL 会抛出您不包含它的异常,因为表达式必须评估为单个值。

;WITH XMLNAMESPACES('pmsg' as pmsg)
SELECT t.x.value('(/pmsg:Messages/pmsg:Message/@Info)[1]', 'nvarchar(max)') as INFO FROM @xmlMessage.nodes('/*') t(x);
--Returns a rowset of one row containing 'blah'
Run Code Online (Sandbox Code Playgroud)

与前面的示例一样,xpath 查询计算为单个项目,并且 nodes() 表达式在顶级节点上提供了一个行集: