【问题标题】:Generate complex XML with T-SQL syntax使用 T-SQL 语法生成复杂的 XML
【发布时间】:2015-07-06 10:08:12
【问题描述】:

我正在尝试构建一个返回或多或少复杂的 XML 结构的查询。这是我想要的预期输出:

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
    <s:Header>
        <a:Action s:mustUnderstand="1">http://tempuri.org/IGeocodeService/HereRouteMatchExtension</a:Action>
        <a:MessageID>urn:uuid: some_messageID</a:MessageID>
        <a:ReplyTo>
            <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
        </a:ReplyTo>
        <a:To s:mustUnderstand="1">ServiceURL</a:To>
    </s:Header>
    <s:Body>
                 <HereRouteMatchExtension xmlns="http://tempuri.org/">
                       <vehicleTrace xmlns:b="http://schemas.datacontract.org/2004/07/FMCommonTypes.WCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                                  <s:Latitude>2</s:Latitude>
                                  <s:Longitude>2</s:Longitude>
                                  <s:PositionGuid>577AF773-C7A8-4D65-82DA-37A15CC7611D</s:PositionGuid>
                       </vehicleTrace>
                 </HereRouteMatchExtension>
    </s:Body>
</s:Envelope>

我正在使用以下代码:

CREATE TABLE #test
(
    Latitude INT,
    Longitude INT, 
    PositionGuid UNIQUEIDENTIFIER
)

INSERT INTO #test VALUES (1,1,NEWID())
INSERT INTO #test VALUES (2,2,NEWID())



WITH XMLNAMESPACES ('http://www.w3.org/2003/05/soap-envelope' AS s, 'http://www.w3.org/2005/08/addressing' AS a)
SELECT
( SELECT '1' AS  [a:Action/@mustUnderstand], 
 'http://tempuri.org/IGeocodeService/HereRouteMatchExtension' AS [a:Action]
  FOR XML PATH (''), TYPE
),
'urn:uuid: some_messageID' AS 'a:MessageID',
( SELECT  'http://www.w3.org/2005/08/addressing/anonymous' AS [a:Address]
  FOR XML PATH ('a:ReplyTo'), TYPE
),
( SELECT '1' AS  [a:To/@mustUnderstand], 
 'ServiceURL' AS [a:To]
  FOR XML PATH (''), TYPE
),
( SELECT '1' AS  [a:Action/@mustUnderstand]
FOR XML PATH (''), TYPE

),
(SELECT Latitude AS 's:Latitude',
       Longitude      AS 's:Longitude', 
       PositionGuid     AS 's:PositionGuid'
FROM #test
FOR XML PATH ('s:Body'),  TYPE
)

FOR XML RAW ('s:Header'), ELEMENTS, ROOT('s:Envelope')

我生成的代码有2个问题:

1) 参考网址在每个小节中,我希望只有一次;

2) 正文标签在标题内,它应该直接在它之后...

我怎样才能做到这一点?这是我得到的结果:

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope" mustUnderstand="1">http://tempuri.org/IGeocodeService/HereRouteMatchExtension</a:Action>
    <a:MessageID>urn:uuid: some_messageID</a:MessageID>
    <a:ReplyTo xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
    <a:To xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope" mustUnderstand="1">ServiceURL</a:To>
    <a:Action xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope" mustUnderstand="1" />
    <s:Body xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
      <s:Latitude>1</s:Latitude>
      <s:Longitude>1</s:Longitude>
      <s:PositionGuid>34BD8E91-8567-4D58-A18E-61C3FBBF5C8F</s:PositionGuid>
    </s:Body>
  </s:Header>
</s:Envelope>

【问题讨论】:

  • “引用 URL”是指 xmlns:a 等命名空间声明吗?

标签: sql-server xml sql-server-2008 sql-server-2008-r2 sql-server-2012


【解决方案1】:

试试看

DECLARE  @test TABLE
(
    Latitude INT,
    Longitude INT, 
    PositionGuid UNIQUEIDENTIFIER
)

INSERT INTO @test VALUES (1,1,NEWID());
INSERT INTO @test VALUES (2,2,NEWID());

    WITH XMLNAMESPACES ('http://www.w3.org/2003/05/soap-envelope' AS s, 'http://www.w3.org/2005/08/addressing' AS a)
    SELECT
        1 AS [s:Envelope/s:Header/a:Action/@s:mustUnderstand],
        'http://tempuri.org/IGeocodeService/HereRouteMatchExtension' AS [s:Envelope/s:Header/a:Action],
        'urn:uuid: some_messageID' AS [s:Envelope/s:Header/a:MessageID],
        'http://www.w3.org/2005/08/addressing/anonymous' [s:Envelope/s:Header/a:ReplyTo/a:Address],
        1  as [s:Envelope/s:Header/To/@s:mustUnderstand],
        'ServiceURL' as  [s:Envelope/s:Header/To],
        Latitude as [s:Envelope/s:Body/s:Latitude],
        Longitude as  [s:Envelope/s:Body/s:Longitude],
        PositionGuid as  [s:Envelope/s:Body/s:PositionGuid]
        FROM @test
        FOR XML PATH('')

这样您就可以为@table 的每一行生成两个Envelope 元素。

编辑:

在使用 FOR XML PATH 的子查询中使用 TYPE 生成时,我找不到从子元素中删除额外命名空间的方法。

我想出了这个不能完全满足我的解决方案:

DECLARE  @test TABLE
(
    Latitude INT,
    Longitude INT, 
    PositionGuid UNIQUEIDENTIFIER,
    x xml
)



DECLARE @x xml = 
'<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
    <s:Header>
        <a:Action s:mustUnderstand="1">http://tempuri.org/IGeocodeService/HereRouteMatchExtension</a:Action>
        <a:MessageID>urn:uuid: some_messageID</a:MessageID>
        <a:ReplyTo>
            <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
        </a:ReplyTo>
        <a:To s:mustUnderstand="1">ServiceURL</a:To>
    </s:Header>
    <s:Body>
                <HereRouteMatchExtension xmlns="http://tempuri.org/">
                       <vehicleTrace xmlns:b="http://schemas.datacontract.org/2004/07/FMCommonTypes.WCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                                  <s:Latitude>2</s:Latitude>
                                  <s:Longitude>2</s:Longitude>
                                  <s:PositionGuid>577AF773-C7A8-4D65-82DA-37A15CC7611D</s:PositionGuid>
                       </vehicleTrace>
                 </HereRouteMatchExtension>
    </s:Body>
</s:Envelope>'

INSERT INTO @test VALUES (10,10,NEWID(),@x);
INSERT INTO @test VALUES (20,20,NEWID(),@x);


UPDATE @test
SET x.modify('declare namespace s="http://www.w3.org/2003/05/soap-envelope";declare default element  namespace "http://tempuri.org/";
replace value of (/s:Envelope/s:Body/HereRouteMatchExtension/vehicleTrace/s:Latitude/text())[1] with sql:column("Latitude")')
UPDATE @test
SET x.modify('declare namespace s="http://www.w3.org/2003/05/soap-envelope";declare default element  namespace "http://tempuri.org/";
replace value of (/s:Envelope/s:Body/HereRouteMatchExtension/vehicleTrace/s:Longitude/text())[1] with sql:column("Longitude")')
UPDATE @test
SET x.modify('declare namespace s="http://www.w3.org/2003/05/soap-envelope";declare default element  namespace "http://tempuri.org/";
replace value of (/s:Envelope/s:Body/HereRouteMatchExtension/vehicleTrace/s:PositionGuid/text())[1] with sql:column("PositionGuid")')


SELECT * FROM @test

全部插入:

DECLARE  @test TABLE
(
    Latitude INT,
    Longitude INT, 
    PositionGuid UNIQUEIDENTIFIER,
    x xml
)



DECLARE @x xml = 
'<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
    <s:Header>
        <a:Action s:mustUnderstand="1">http://tempuri.org/IGeocodeService/HereRouteMatchExtension</a:Action>
        <a:MessageID>urn:uuid: some_messageID</a:MessageID>
        <a:ReplyTo>
            <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
        </a:ReplyTo>
        <a:To s:mustUnderstand="1">ServiceURL</a:To>
    </s:Header>
    <s:Body>
                <HereRouteMatchExtension xmlns="http://tempuri.org/">
                 </HereRouteMatchExtension>
    </s:Body>
</s:Envelope>'

INSERT INTO @test VALUES (10,10,NEWID(),@x);
INSERT INTO @test VALUES (20,20,NEWID(),@x);

UPDATE @test
SET x.modify('declare namespace s="http://www.w3.org/2003/05/soap-envelope";declare default element  namespace "http://tempuri.org/";
insert  <vehicleTrace xmlns:b="http://schemas.datacontract.org/2004/07/FMCommonTypes.WCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><s:Latitude>{sql:column("Latitude")}</s:Latitude>
        <s:Longitude>{sql:column("Longitude")}</s:Longitude>
        <s:PositionGuid>{sql:column("PositionGuid")}</s:PositionGuid></vehicleTrace> into (/s:Envelope/s:Body/HereRouteMatchExtension)[1]')


SELECT * FROM @test

【讨论】:

  • 谢谢。这正是我问的。不过我稍微修改了一下问题,请您看一下...。我已经稍微更改了代码。
  • 我认为也可以用一个插入而不是三个替换来完成
  • 第二个和第三个 sn-ps 代码不会生成。它已经在那里了。在第一种情况下,代码只是替换了经度、纬度和 PositionGuid 元素的值。在第二个中,它插入了一个构造好的 vehicleTrace 元素。
  • 我的意思是我稍微修改了问题(在 标签内)。你能告诉我怎么做吗?
  • 第二个和第三个是基于修改后的问题你试过运行它们吗?
猜你喜欢
  • 2020-06-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多