[英]T-SQL Parse XML Response in table format
我正在努力解析我擁有的 XML 響應。 我需要標題值是列,記錄值是它們各自行內的數據。 下面是帶有標題值和 1 條記錄的返回示例。
其中記錄顯示 xsi:nil="true" 將為 NULL
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<ns2:getReportResultResponse xmlns:ns2="http://service.apiendpoint.com">
<return>
<header>
<values>
<data>CUSTOMER NAME</data>
<data>DISPOSITION GROUP A</data>
<data>DISPOSITION GROUP B</data>
<data>DISPOSITION GROUP C</data>
<data>DISPOSITION PATH</data>
<data>FIRST DISPOSITION</data>
<data>LAST DISPOSITION</data>
<data>LIST NAME</data>
</values>
</header>
<records>
<values>
<data>Mark Smith</data>
<data>12</data>
<data>19</data>
<data>23</data>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data>Tier 1</data>
</values>
</records>
</return>
</ns2:getReportResultResponse>
</env:Body>
</env:Envelope>
declare @x xml = N'
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<ns2:getReportResultResponse xmlns:ns2="http://service.apiendpoint.com">
<return>
<header>
<values>
<data>CUSTOMER NAME</data>
<data>DISPOSITION GROUP A</data>
<data>DISPOSITION GROUP B</data>
<data>DISPOSITION GROUP C</data>
<data>DISPOSITION PATH</data>
<data>FIRST DISPOSITION</data>
<data>LAST DISPOSITION</data>
<data>LIST NAME</data>
</values>
</header>
<records>
<values>
<data>Mark Smith</data>
<data>12</data>
<data>19</data>
<data>23</data>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data>Tier 1</data>
</values>
<values>
<data>B</data>
<data>2</data>
<data>22</data>
<data>222</data>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="false" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/><!-- ?? -->
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data>Tier 2</data>
</values>
</records>
</return>
</ns2:getReportResultResponse>
</env:Body>
</env:Envelope>
';
select @x;
declare @sql nvarchar(max) = N'';
with xmlnamespaces ('http://schemas.xmlsoap.org/soap/envelope/' as env, 'http://service.apiendpoint.com' as ns2)
select
@sql = @sql + ',r.rec.value(''data[' + cast(colid as nvarchar(10)) + '][not(@xsi:nil="true")]'', ''nvarchar(500)'') as ' + colname
from
(
select
quotename(hd.h.value('.', 'sysname')) as colname,
row_number() over(order by hd.h) as colid
from @x.nodes('/env:Envelope/env:Body/ns2:getReportResultResponse/return/header/values/data') as hd(h)
) as src
order by colid;
select @sql = stuff(@sql, 1, 1, N'');
select @sql = N'with xmlnamespaces (''http://schemas.xmlsoap.org/soap/envelope/'' as env, ''http://service.apiendpoint.com'' as ns2, ''http://www.w3.org/2001/XMLSchema-instance'' as xsi)
select
' + @sql + N'
from @x.nodes(''/env:Envelope/env:Body/ns2:getReportResultResponse/return/records/values'') as r(rec)
';
exec sp_executesql @stmt = @sql, @params = N'@x xml', @x = @x;
假設您在 SQL Server 變量@XmlData
有 XML 數據,您可以使用此 XQuery 來獲取列名(“標題”):
WITH XMLNAMESPACES ('http://schemas.xmlsoap.org/soap/envelope/' AS env, 'http://service.apiendpoint.com' AS ns2)
SELECT
XCol.value('(.)[1]', 'varchar(50)')
FROM
@XmlData.nodes('/env:Envelope/env:Body/ns2:getReportResultResponse/return/header/values/data') AS XHdr(XCol);
這相當簡單,因為您可以假設每個標頭實際上都是一個字符串(因此您可以執行.value('(.)[1]', 'varchar(50)')
調用並安全起見)。
但是,對於數據 - 正如@Serg 已經在評論中提到的那樣 - 除非您能以某種方式知道(或找出)數據元素的數據類型是什么,否則這將更加棘手......使用相同的方法 - 假設一切都是一個字符串 -會起作用- 但是你可能會丟失關於你的數據位的有價值的信息:
WITH XMLNAMESPACES ('http://schemas.xmlsoap.org/soap/envelope/' AS env, 'http://service.apiendpoint.com' AS ns2)
SELECT
XCol.value('(.)[1]', 'varchar(50)')
FROM
@XmlData.nodes('/env:Envelope/env:Body/ns2:getReportResultResponse/return/records/values/data') AS XData(XCol)
這是另一種解決方案。 它非常接近@lptr 的方法。
它使用XQuery和FLWOR 表達式來構造最終 SQL 語句的動態SELECT
子句。
SQL
DECLARE @x xml = N'
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<ns2:getReportResultResponse xmlns:ns2="http://service.apiendpoint.com">
<return>
<header>
<values>
<data>CUSTOMER NAME</data>
<data>DISPOSITION GROUP A</data>
<data>DISPOSITION GROUP B</data>
<data>DISPOSITION GROUP C</data>
<data>DISPOSITION PATH</data>
<data>FIRST DISPOSITION</data>
<data>LAST DISPOSITION</data>
<data>LIST NAME</data>
</values>
</header>
<records>
<values>
<data>Mark Smith</data>
<data>12</data>
<data>19</data>
<data>23</data>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data>Tier 1</data>
</values>
<values>
<data>B</data>
<data>2</data>
<data>22</data>
<data>222</data>
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data xsi:nil="false" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/><!-- ?? -->
<data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<data>Tier 2</data>
</values>
</records>
</return>
</ns2:getReportResultResponse>
</env:Body>
</env:Envelope>';
DECLARE @sql NVARCHAR(MAX) = N''
, @separator CHAR(1) = ',';
WITH XMLNAMESPACES ('http://schemas.xmlsoap.org/soap/envelope/' as env, 'http://service.apiendpoint.com' as ns2)
SELECT @sql = @x.query('
for $r in /env:Envelope/env:Body/ns2:getReportResultResponse/return/header/values/data
let $pos := count(env:Envelope/env:Body/ns2:getReportResultResponse/return/header/values/data[. << $r]) + 1
let $line := concat("c.value(''(data[", string($pos), "]/text())[1]'', ''VARCHAR(50)'') AS [", string(($r/text())[1]),"]")
return if ($r is (/env:Envelope/env:Body/ns2:getReportResultResponse/return/header/values/data[last()])[1]) then string($line)
else concat($line, sql:variable("@separator"))
').value('.', 'NVARCHAR(MAX)');
SET @sql = N';WITH XMLNAMESPACES (''http://schemas.xmlsoap.org/soap/envelope/'' as env, ''http://service.apiendpoint.com'' as ns2)
SELECT ' + @sql + N'
FROM @x.nodes(''/env:Envelope/env:Body/ns2:getReportResultResponse/return/records/values'') AS t(c)
';
EXEC sp_executesql @stmt = @sql, @params = N'@x xml', @x = @x;
輸出
+---------------+---------------------+---------------------+---------------------+------------------+-------------------+------------------+-----------+
| CUSTOMER NAME | DISPOSITION GROUP A | DISPOSITION GROUP B | DISPOSITION GROUP C | DISPOSITION PATH | FIRST DISPOSITION | LAST DISPOSITION | LIST NAME |
+---------------+---------------------+---------------------+---------------------+------------------+-------------------+------------------+-----------+
| Mark Smith | 12 | 19 | 23 | NULL | NULL | NULL | Tier 1 |
| B | 2 | 22 | 222 | NULL | NULL | NULL | Tier 2 |
+---------------+---------------------+---------------------+---------------------+------------------+-------------------+------------------+-----------+
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.