0

我正在从 SQL Server 表生成 XML。

这是我的代码:

;WITH XMLNAMESPACES
( 
     'http://www.w3.org/2001/XMLSchema-instance' AS xsi 
    --,DEFAULT 'http://www.w3.org/2001/XMLSchema-instance'  -- xmlns 
) 
SELECT 
    'T_Contracts' AS "@tableName",
    (SELECT * FROM T_Contracts 
     FOR XML PATH('row'), TYPE, ELEMENTS xsinil)
FOR XML PATH('table'), TYPE, ELEMENTS xsinil

我希望结果看起来像这样(注意:tableName根元素上的属性):

<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" tableName="T_Contracts">
  <row>
    <VTR_UID>779FE899-4E81-4D8C-BF9B-3F17BC1DF146</VTR_UID>
    <VTR_MDT_ID>0</VTR_MDT_ID>
    <VTR_VTP_UID xsi:nil="true" />
    <VTR_Nr>0050/132251</VTR_Nr>
  </row>
</table>

但它复制了行元素上的 XSI 命名空间......

<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" tableName="T_Contracts">
  <row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <VTR_UID>779FE899-4E81-4D8C-BF9B-3F17BC1DF146</VTR_UID>
    <VTR_MDT_ID>0</VTR_MDT_ID>
    <VTR_VTP_UID xsi:nil="true" />
    <VTR_Nr>0050/132251</VTR_Nr>
  </row>
</table>

将属性添加到根元素的正确方法是什么,并且只有根元素

笔记

NULL 值必须返回 as<columnName xsi:nil="true" />且不能省略。

xml.modify选择后没有)

请注意,这不是现有问题的重复。

4

3 回答 3

2

带有子查询的重复命名空间的这种烦人行为是 MS-Connect 上 10 多年来报告的一个问题,获得了数千票。这个平台被解雇了,这个问题也是如此,并且没有任何观点认为 MS 会解决这个问题。

公平地说:重复命名空间声明并没有错。它只是膨胀基于字符串的输出......

更奇怪的是根级节点上不受支持的属性......

好吧,如果你需要头痛,你可以看看OPTION EXPLICIT:-)

Marc Guillot 接受的答案不会产生xsi:nil="true"您似乎需要的属性。它只会用适当的根节点包装您的结果。

最后:这不能用 XML 方法解决,你可以试试这个:
更新:找到了一种方法,见下文......

DECLARE @tbl TABLE(ID INT,SomeValue INT);
INSERT INTO @tbl VALUES(1,1),(2,NULL);

SELECT CAST(REPLACE(CAST(
(
    SELECT *
    FROM @tbl 
    FOR XML PATH('row'),ROOT('table'),TYPE, ELEMENTS XSINIL
) AS nvarchar(MAX)),'<table ','<table tableName="T_Contracts" ') AS XML);

结果

<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" tableName="T_Contracts">
  <row>
    <ID>1</ID>
    <SomeValue>1</SomeValue>
  </row>
  <row>
    <ID>2</ID>
    <SomeValue xsi:nil="true" />
  </row>
</table>

简而言之:

  • 我们在没有子查询的情况下创建 XML,并将使用字符串方法的属性添加到转换后的 XML 中。
  • 由于属性的位置并不重要,我们可以在任何地方添加它。
  • 或者,您可以搜索第一个关闭>STUFF()在那里使用...

更新

Heureka,我刚刚找到了一种方法,可以在不切换字符串的情况下创建它,但它很笨拙:-)

DECLARE @tbl TABLE(ID INT,SomeValue INT);
INSERT INTO @tbl VALUES(1,1),(2,NULL);

SELECT
(
SELECT 'T_Contracts' AS [@tableName]
      ,(
        SELECT 'SomeRowAttr' AS [@testAttr] --added this to test row-level attributes
              ,*
        FROM @tbl 
        FOR XML PATH('row'),TYPE, ELEMENTS XSINIL
       )
FOR XML PATH('table'),TYPE, ELEMENTS XSINIL
).query('<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">{/table/@*}
         {
            for $nd in /table/row
            return
            <row>{$nd/@*}
            {
                $nd/*
            }
            </row>
         }
         </table>');

结果

<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" tableName="T_Contracts">
  <row testAttr="SomeRowAttr">
    <ID>1</ID>
    <SomeValue>1</SomeValue>
  </row>
  <row testAttr="SomeRowAttr">
    <ID>2</ID>
    <SomeValue xsi:nil="true" />
  </row>
</table>
于 2020-06-26T06:51:29.970 回答
1

为什么不手动构建根元素?

例子:

with CTE as (
  select (select * from T_Contracts for xml path('row')) as MyXML
)
select '<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" tableName="T_Contracts">' +
        MyXML + 
        '</table>'  
from CTE
于 2020-06-25T13:27:04.493 回答
0

不幸的是,您不能使用开箱即用的 SQL Server 来做到这一点,也没有一种优雅的方式来做到这一点。为了缓解这个问题,您可以将NULLs 替换为空字符串。这将删除xmlns,但您必须明确定义您的选择列表,如下所示。此外,这仅适用于字符串数据类型,因为您不能将空字符串(''ISNULL函数中)分配给例如整数。

;WITH XMLNAMESPACES
( 
     'http://www.w3.org/2001/XMLSchema-instance' AS xsi 
    --,DEFAULT 'http://www.w3.org/2001/XMLSchema-instance'  -- xmlns 
) 
SELECT 'T_Contracts' AS "@tableName",
    (
        SELECT 
             ISNULL(VTR_UID, '')     'row/VTR_UID'
            ,ISNULL(VTR_MDT_ID, '')  'row/VTR_MDT_ID'
            ,ISNULL(VTR_VTP_UID, '') 'row/VTR_VTP_UID'
            ,ISNULL(VTR_Nr, '')      'row/VTR_Nr'
        FROM T_Contracts
        FOR XML PATH(''), TYPE
    )
FOR XML PATH('table'), TYPE, ELEMENTS xsinil

结果将如下所示:

<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" tableName="T_Contracts">
  <row>
    <VTR_UID>779FE899-4E81-4D8C-BF9B-3F17BC1DF146</VTR_UID>
    <VTR_MDT_ID>0</VTR_MDT_ID>
    <VTR_VTP_UID />
    <VTR_Nr>0050/132251</VTR_Nr>
  </row>
</table>
于 2021-05-26T14:28:21.700 回答