使用 T-SQL 生成 XML 和一些问题
Generating XML using T-SQL and some issues
我利用了你的知识有一段时间了,但这次我没有找到问题的答案。
我是自学成才,如有错误请多多包涵
我需要生成 XML,我从未使用 SQL 生成过,所以我遇到了一些问题。
我已经生成了核心,但是我需要添加模式和版本,但我做不到。
我准备了一个快速示例,它必须是相同的体系结构。
现在的样子:
<s:headers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://www.example.com">
<warehouse_iss type="T">
<idn>wareh</idn>
</warehouse_iss>
<iss_id type="T">
<id>1</id>
</iss_id>
<date>2018-10-15T21:48:36.220</date>
<items xmlns:s="http://www.example.com">
<prod_index type="T">
<idn>abc</idn>
</prod_index>
<qty>1.230000000000000e+002</qty>
<parameters xmlns:s="http://www.example.com">
<parameter>
<par_id type="T">
<id>1</id>
</par_id>
<par_value type="T">
<id>abcdef</id>
</par_value>
</parameter>
</parameters>
</items>
</s:headers>
它应该是什么样子:
<?xml version="1.0" encoding="UTF-8"?>
<s:headers xmlns:s="http://www.example.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.com/example ../../Schema/example.xsd ">
<warehouse_iss type="T">
<idn>wareh</idn>
</warehouse_iss>
<iss_id type="T">
<id>1</id>
</iss_id>
<date>2018-10-15T21:48:36.220</date>
<items>
<prod_index type="T">
<idn>abc</idn>
</prod_index>
<qty>1.230000000000000e+002</qty>
<parameters>
<parameter>
<par_id type="T">
<id>1</id>
</par_id>
<par_value type="T">
<id>abcdef</id>
</par_value>
</parameter>
</parameters>
</items>
</s:headers>
所以我需要添加所有模式和元素,并且不应在子节点中重复。
我还需要添加版本。
我准备的代码可以帮助你帮助我(MyFunction 当然是在输出中添加“@type”的函数 XML)
;)
create table #temp_headers (warehouse_iss varchar(5), iss_id int, date datetime)
create table #temp_items (prod_index varchar(10), qty float)
create table #temp_parameter (par_id int, par_value varchar(10), prod_index varchar(10))
insert into #temp_headers values ('wareh',1,getdate())
insert into #temp_items values ('abc',123)
insert into #temp_parameter values (1, 'abcdef','abc')
WITH XMLNAMESPACES ('http://www.example.com' as s)
select
dbo.MyFunction(1,'T') as "warehouse_iss/@type",
warehouse_iss as "warehouse_iss/idn",
dbo.MyFunction(1,'T') as "iss_id/@type",
iss_id as "iss_id/id", --- iss_id
GETDATE() date, --- date
(select
dbo.MyFunction(1,'T') as "prod_index/@type",
prod_index as "prod_index/idn",
qty,
(select
dbo.MyFunction(1,'T') as "par_id/@type",
par_id as "par_id/id",
dbo.MyFunction(1,'T') as "par_value/@type",
par_value as "par_value/id"
from #temp_parameter para
where para.prod_index = items.prod_index
FOR XML PATH ('parameter'), ROOT ('parameters'), type
)
from #temp_items items
for xml path ('items'), type
)
from #temp_headers head
for xml path ('s:headers'), ELEMENTS XSINIL
提前致谢。
这是一个很烦人的问题,已经知道十年了,但是微软不愿意改变它。命名空间在 sub-queries 中一遍又一遍地重复。搜索这个,你会发现数百个关于这个的问题。有一个 connect-issue 十多年了,有很多支持者,但是 connect 没有了,问题也没有了——但是命名空间仍然存在...
顺便说一句:您的查询很好!
然而,解决方案是可行的,但是很丑陋。您必须创建不带命名空间的 XML 并将它们添加到字符串级别的末尾:
create table #temp_headers (warehouse_iss varchar(5), iss_id int, date datetime)
create table #temp_items (prod_index varchar(10), qty float)
create table #temp_parameter (par_id int, par_value varchar(10), prod_index varchar(10))
insert into #temp_headers values ('wareh',1,getdate())
insert into #temp_items values ('abc',123)
insert into #temp_parameter values (1, 'abcdef','abc');
-- 感谢测试场景!
DECLARE @intermediateXML XML=
(
select
'Dummy T' as "warehouse_iss/@type",
warehouse_iss as "warehouse_iss/idn",
'Dummy T' as "iss_id/@type",
iss_id as "iss_id/id", --- iss_id
GETDATE() date, --- date
(select
'Dummy T' as "prod_index/@type",
prod_index as "prod_index/idn",
qty,
(select
'Dummy T' as "par_id/@type",
par_id as "par_id/id",
'Dummy T' as "par_value/@type",
par_value as "par_value/id"
from #temp_parameter para
where para.prod_index = items.prod_index
FOR XML PATH ('parameter'), ROOT ('parameters'), type
)
from #temp_items items
for xml path ('items'), type
)
from #temp_headers head
for xml path ('DummyHeaders')
);
--将其转换为 NVARCHAR(MAX)
...
DECLARE @XML_as_String NVARCHAR(MAX)=CAST(@intermediateXML AS NVARCHAR(MAX));
--... 并使用字符串方法
在字符串级别添加 header
DECLARE @Header NVARCHAR(MAX)=
N'<s:headers xmlns:s="http://www.example.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.com/example ../../Schema/example.xsd ">';
DECLARE @finalXML XML=
(
REPLACE(
(SELECT @Header +
(
SELECT SUBSTRING(@XML_as_String,CHARINDEX(N'<warehouse_iss',@XML_as_String),LEN(@XML_as_String))
)
),'</DummyHeaders>','</s:headers>')
);
SELECT @finalXML
GO
DROP TABLE #temp_headers
DROP TABLE #temp_items
DROP TABLE #temp_parameter
提示:关于 xml-declaration <?xml blah?>
的一个评论
您的 XML 默认编码为 NVARCHAR(MAX)
(即 UCS-2
,几乎 utf-16)
。如果您添加声明告诉消费者 嘿,我是utf-8
!,这不是事实。这个声明并不是XML的一部分,而是提前,告诉消费者如何解码内容。SQL-Server 甚至不允许您将其存储为原生 XML。
但是 - 当然 - 您可以将任何字符串添加到字符串中。因此,您可以将声明添加到已转换的 XML(但不要将其转换回 XML!)。如果将其写到光盘上的文件中,您应该确定该文件实际上是 utf-8
编码的。否则你的文件就是骗子 ;-)
我利用了你的知识有一段时间了,但这次我没有找到问题的答案。 我是自学成才,如有错误请多多包涵
我需要生成 XML,我从未使用 SQL 生成过,所以我遇到了一些问题。 我已经生成了核心,但是我需要添加模式和版本,但我做不到。
我准备了一个快速示例,它必须是相同的体系结构。 现在的样子:
<s:headers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="http://www.example.com">
<warehouse_iss type="T">
<idn>wareh</idn>
</warehouse_iss>
<iss_id type="T">
<id>1</id>
</iss_id>
<date>2018-10-15T21:48:36.220</date>
<items xmlns:s="http://www.example.com">
<prod_index type="T">
<idn>abc</idn>
</prod_index>
<qty>1.230000000000000e+002</qty>
<parameters xmlns:s="http://www.example.com">
<parameter>
<par_id type="T">
<id>1</id>
</par_id>
<par_value type="T">
<id>abcdef</id>
</par_value>
</parameter>
</parameters>
</items>
</s:headers>
它应该是什么样子:
<?xml version="1.0" encoding="UTF-8"?>
<s:headers xmlns:s="http://www.example.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.com/example ../../Schema/example.xsd ">
<warehouse_iss type="T">
<idn>wareh</idn>
</warehouse_iss>
<iss_id type="T">
<id>1</id>
</iss_id>
<date>2018-10-15T21:48:36.220</date>
<items>
<prod_index type="T">
<idn>abc</idn>
</prod_index>
<qty>1.230000000000000e+002</qty>
<parameters>
<parameter>
<par_id type="T">
<id>1</id>
</par_id>
<par_value type="T">
<id>abcdef</id>
</par_value>
</parameter>
</parameters>
</items>
</s:headers>
所以我需要添加所有模式和元素,并且不应在子节点中重复。 我还需要添加版本。
我准备的代码可以帮助你帮助我(MyFunction 当然是在输出中添加“@type”的函数 XML) ;)
create table #temp_headers (warehouse_iss varchar(5), iss_id int, date datetime)
create table #temp_items (prod_index varchar(10), qty float)
create table #temp_parameter (par_id int, par_value varchar(10), prod_index varchar(10))
insert into #temp_headers values ('wareh',1,getdate())
insert into #temp_items values ('abc',123)
insert into #temp_parameter values (1, 'abcdef','abc')
WITH XMLNAMESPACES ('http://www.example.com' as s)
select
dbo.MyFunction(1,'T') as "warehouse_iss/@type",
warehouse_iss as "warehouse_iss/idn",
dbo.MyFunction(1,'T') as "iss_id/@type",
iss_id as "iss_id/id", --- iss_id
GETDATE() date, --- date
(select
dbo.MyFunction(1,'T') as "prod_index/@type",
prod_index as "prod_index/idn",
qty,
(select
dbo.MyFunction(1,'T') as "par_id/@type",
par_id as "par_id/id",
dbo.MyFunction(1,'T') as "par_value/@type",
par_value as "par_value/id"
from #temp_parameter para
where para.prod_index = items.prod_index
FOR XML PATH ('parameter'), ROOT ('parameters'), type
)
from #temp_items items
for xml path ('items'), type
)
from #temp_headers head
for xml path ('s:headers'), ELEMENTS XSINIL
提前致谢。
这是一个很烦人的问题,已经知道十年了,但是微软不愿意改变它。命名空间在 sub-queries 中一遍又一遍地重复。搜索这个,你会发现数百个关于这个的问题。有一个 connect-issue 十多年了,有很多支持者,但是 connect 没有了,问题也没有了——但是命名空间仍然存在...
顺便说一句:您的查询很好!
然而,解决方案是可行的,但是很丑陋。您必须创建不带命名空间的 XML 并将它们添加到字符串级别的末尾:
create table #temp_headers (warehouse_iss varchar(5), iss_id int, date datetime)
create table #temp_items (prod_index varchar(10), qty float)
create table #temp_parameter (par_id int, par_value varchar(10), prod_index varchar(10))
insert into #temp_headers values ('wareh',1,getdate())
insert into #temp_items values ('abc',123)
insert into #temp_parameter values (1, 'abcdef','abc');
-- 感谢测试场景!
DECLARE @intermediateXML XML=
(
select
'Dummy T' as "warehouse_iss/@type",
warehouse_iss as "warehouse_iss/idn",
'Dummy T' as "iss_id/@type",
iss_id as "iss_id/id", --- iss_id
GETDATE() date, --- date
(select
'Dummy T' as "prod_index/@type",
prod_index as "prod_index/idn",
qty,
(select
'Dummy T' as "par_id/@type",
par_id as "par_id/id",
'Dummy T' as "par_value/@type",
par_value as "par_value/id"
from #temp_parameter para
where para.prod_index = items.prod_index
FOR XML PATH ('parameter'), ROOT ('parameters'), type
)
from #temp_items items
for xml path ('items'), type
)
from #temp_headers head
for xml path ('DummyHeaders')
);
--将其转换为 NVARCHAR(MAX)
...
DECLARE @XML_as_String NVARCHAR(MAX)=CAST(@intermediateXML AS NVARCHAR(MAX));
--... 并使用字符串方法
在字符串级别添加 headerDECLARE @Header NVARCHAR(MAX)=
N'<s:headers xmlns:s="http://www.example.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.com/example ../../Schema/example.xsd ">';
DECLARE @finalXML XML=
(
REPLACE(
(SELECT @Header +
(
SELECT SUBSTRING(@XML_as_String,CHARINDEX(N'<warehouse_iss',@XML_as_String),LEN(@XML_as_String))
)
),'</DummyHeaders>','</s:headers>')
);
SELECT @finalXML
GO
DROP TABLE #temp_headers
DROP TABLE #temp_items
DROP TABLE #temp_parameter
提示:关于 xml-declaration <?xml blah?>
的一个评论
您的 XML 默认编码为 NVARCHAR(MAX)
(即 UCS-2
,几乎 utf-16)
。如果您添加声明告诉消费者 嘿,我是utf-8
!,这不是事实。这个声明并不是XML的一部分,而是提前,告诉消费者如何解码内容。SQL-Server 甚至不允许您将其存储为原生 XML。
但是 - 当然 - 您可以将任何字符串添加到字符串中。因此,您可以将声明添加到已转换的 XML(但不要将其转换回 XML!)。如果将其写到光盘上的文件中,您应该确定该文件实际上是 utf-8
编码的。否则你的文件就是骗子 ;-)