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

Dis*_*ile 8 xml sql-server 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>
Run Code Online (Sandbox Code Playgroud)

我想从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
Run Code Online (Sandbox Code Playgroud)

我为MessageXml.value返回NULL.如果我删除s之后的所有内容:Body我似乎得到了一堆串联的文本,但是一旦我添加了FetchRequest,我就会在结果中得到NULL.

我注意到Contract元素定义了a的命名空间,而Envelope也定义了a的命名空间,但我不确定这是否是一个问题.

在给定上面的xml示例的情况下,如何使用XPath查询检索TransactionId?

vit*_*ore 27

我知道答案是可以接受的,但实际上有更简单的方法,如果您需要做的唯一事情就是选择节点值.只需使用*命名空间名称:

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

  • 这是我唯一可以接受的答案.我在第三方数据库中工作,他们在同一列中使用各种命名空间,但它们大多遵循相同的模式(至少我关心提取的模式路径).这种方法还意味着更简单/更少的脚本编写,并避免在命名空间更改(或版本化以添加更多架构)时打破时间.谢谢! (2认同)
  • 这正是我所需要的,谢谢 (2认同)

mar*_*c_s 15

你有两个问题:

  • 您不尊重<FetchRequest>节点上的隐式默认XML命名空间
  • 带有a:前缀的XML命名空间首先在<s:Envelope>节点上定义,并在节点上重新声明<Contract>(在我看来真的是非常糟糕的做法),你需要在节点下面使用第二个声明<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
Run Code Online (Sandbox Code Playgroud)

这将输出整个查询和ABC20140402000201第二列的值.


Stu*_*tLC 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;
Run Code Online (Sandbox Code Playgroud)

小提琴: