具有多个名称空间的SQL Server Xml查询

时间:2014-04-02 17:20:28

标签: sql-server xml xpath

我在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?

3 个答案:

答案 0 :(得分:23)

我知道答案已被接受,但实际上有更简单的方法,如果你唯一需要做的就是选择节点值。只需使用*作为命名空间名称:

SELECT MessageXml
     ,  MessageXml.value('(/*:Envelope/*:Body/*:FetchRequest/*:Contract/*:TransactionId)[1]'
                       , 'varchar(max)')
FROM   dbo.Message

答案 1 :(得分:14)

您有两个问题

  • 您不尊重<FetchRequest>节点
  • 上的隐式默认XML命名空间
  • 带有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)

FetchRequestContract位于名称空间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;

Fiddle here:

相关问题