使用 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 编码的。否则你的文件就是骗子 ;-)