我在SQL服务器中有一个包含Xml列的表,我在查询时遇到问题。我不太了解XPath以确定我的查询是否错误,或者是否因为看起来像是冲突的命名空间。这是一个示例xml:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<!-- snip -->
</s:Header>
<s:Body>
<FetchRequest xmlns="http://www.foobar.org/my/schema">
<Contract xmlns:a="http://www.foobar.org/2014/04/datacontracts"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:RequestedBy>John Doe</a:RequestedBy>
<a:TransactionId>ABC20140402000201</a:TransactionId>
</Contract>
</FetchRequest>
</s:Body>
</s:Envelope>
我想从xml中检索TransactionId。我试过的问题是:
SELECT TOP 100
MessageXml,
MessageXml.value('
declare namespace s="http://www.w3.org/2003/05/soap-envelope";
declare namespace a="http://www.w3.org/2005/08/addressing";
(/s:Envelope/s:Body/FetchRequest/Contract/a:TransactionId)[1]', 'varchar(max)')
FROM dbo.Message
我的MessageXml.value返回NULL。如果我删除s之后的所有内容:Body我似乎得到了一堆串联的文本,但是一旦我添加了FetchRequest,我就会在结果中得到NULL。
我注意到Contract元素定义了a的命名空间,而Envelope也定义了a的命名空间,但我不确定这是否是一个问题。
如果给出上面的xml示例,我如何使用XPath查询检索TransactionId?
答案 0 :(得分:23)
我知道答案已被接受,但实际上有更简单的方法,如果你唯一需要做的就是选择节点值。只需使用*
作为命名空间名称:
SELECT MessageXml
, MessageXml.value('(/*:Envelope/*:Body/*:FetchRequest/*:Contract/*:TransactionId)[1]'
, 'varchar(max)')
FROM dbo.Message
答案 1 :(得分:14)
您有两个问题:
<FetchRequest>
节点a:
前缀的XML命名空间首先在<s:Envelope>
节点上定义,并在<Contract>
节点上重新声明(在我看来真的是非常糟糕的做法)和您需要将{em> second 声明用于<Contract>
节点以下的任何内容。所以你需要这样的东西(我更喜欢在WITH XMLNAMESPACES()
语句中预先定义XML名称空间):
;WITH XMLNAMESPACES('http://www.w3.org/2003/05/soap-envelope' AS s,
'http://www.foobar.org/2014/04/datacontracts' AS a,
'http://www.foobar.org/my/schema' AS fb)
SELECT
MessageXml,
MessageXml.value('(/s:Envelope/s:Body/fb:FetchRequest/fb:Contract/a:TransactionId)[1]', 'varchar(max)')
FROM
dbo.Message
这将输出整个查询以及第二列的值ABC20140402000201
。
答案 2 :(得分:5)
FetchRequest
和Contract
位于名称空间http://www.foobar.org/my/schema
中,别名a
在文档中重新定义。你需要:
SELECT TOP 100
MessageXml,
MessageXml.value('declare namespace s="http://www.w3.org/2003/05/soap-envelope";
declare namespace a="http://www.w3.org/2005/08/addressing";
declare namespace f="http://www.foobar.org/my/schema";
declare namespace x="http://www.foobar.org/2014/04/datacontracts";
(/s:Envelope/s:Body/f:FetchRequest/f:Contract/x:TransactionId)[1]', 'varchar(max)')
FROM dbo.Message;