【问题标题】:Empty tags formatting in XML column in SQL ServerSQL Server 中 XML 列中的空标记格式
【发布时间】:2018-02-12 10:09:42
【问题描述】:

我有这样的xml:

<root>
   <name></name>
</root>

当我将它保存到 XML 列并在 SSMS 中查询时,它使用自闭合标签进行格式化:

<root>
   <name />
</root>

是否可以保留原始格式,或者在 SELECT 语句中确定格式?

【问题讨论】:

  • 在 xml 中使用非自结束标签是一项已弃用的功能。 SQL Server 正在使用自结束标记,因为这是正确的做法。
  • 我不明白你为什么在乎,这两种语法对任何 XML 解析器都包含相同的信息?
  • @DavidG: 好吧,这只是因为我正在将数据从 sharepoint 迁移到 sql server,并且我希望能够更轻松地将原始 xml 与新 xml 进行比较。
  • 那我建议使用合适的方法来比较XML,例如stackoverflow.com/questions/167946/…
  • 我同意。如果无法在 SSMS 或 Select Clause 中格式化 XML,我将接受它作为答案。不过,不确定谁更值得称赞,Larni 还是 DavidG。

标签: sql-server xml sqlxml


【解决方案1】:

如果您获取的是非 xml 格式的数据,并且不希望使用 Self 结束标记,则需要将 NULL 替换为空字符串:@987654322 @。

例如:

CREATE TABLE #Sample ([name] char(1));
INSERT INTO #Sample
VALUES(NULL);


SELECT ISNULL([Name],'') AS [name]
FROM #Sample
FOR XML PATH('root');

DROP TABLE #Sample;

但是,如果您将该 xml 作为 xml 类型插入到 SQL Server 中,然后返回它,那么 SQL Server 将使用自闭合标签(根据我对问题的评论)。

正如@DavidG 所说,任何 good xml 解析器都可以读取自闭和非自闭标签。如果您的解析器无法读取自闭合标签,您需要考虑更新您的解析器。如果它纯粹是为了展示目的......那么你为什么要使用“旧”的方式来展示呢?

【讨论】:

  • 这一步是正确的。但即使是 正确的 XML 也可能在 XML 查询中发生变化......(请参阅我的回答)
【解决方案2】:

自闭合元素&lt;SomeElement/&gt; 在语义上与&lt;SomeElement&gt;&lt;/SomeElement&gt; 相同。您不应该为此烦恼...如果您的阅读工具(或第三方要求)需要此工具,您应该更换此工具或与您的合作伙伴讨论。

问题是:你无法控制,事情会保持原样。即使在某些情况下,您可以使用开始和结束标记存储空值,这可能会在以后的调用中隐式更改。

试试这个:

DECLARE @tbl TABLE(ID INT IDENTITY,YourXML XML);
INSERT INTO @tbl VALUES
(
    (SELECT '' AS [SomeTag] FOR XML PATH('RowNode'),ROOT('RootNode'),TYPE)
)
,(
    (SELECT '' AS [SomeTag] FOR XML RAW('RowNode'),ROOT('RootNode'), ELEMENTS)
)
,(
    N'<RootNode>
      <RowNode>
        <SomeTag></SomeTag>
      </RowNode>
    </RootNode>'
)
,
(CAST(
    N'<RootNode>
      <RowNode>
        <SomeTag></SomeTag>
      </RowNode>
    </RootNode>'AS XML)
);

DECLARE @FirstXml XML=(SELECT YourXml FROM @tbl WHERE ID=1);
INSERT INTO @tbl VALUES(@FirstXml);
INSERT INTO @tbl SELECT @FirstXml;
INSERT INTO @tbl SELECT @FirstXml.query(N'.');

SELECT * FROM @tbl

结果

ID  YourXML
--FOR XML PATH created - why ever - both tags
1   <RootNode><RowNode><SomeTag></SomeTag></RowNode></RootNode>
--FOR XML AUTO and all implicit casts use self-closing tags
2   <RootNode><RowNode><SomeTag /></RowNode></RootNode>
3   <RootNode><RowNode><SomeTag /></RowNode></RootNode>
4   <RootNode><RowNode><SomeTag /></RowNode></RootNode>
--Here we insert the first node *as is*
5   <RootNode><RowNode><SomeTag></SomeTag></RowNode></RootNode>
6   <RootNode><RowNode><SomeTag></SomeTag></RowNode></RootNode>
--But `.query()` will reformat this
7   <RootNode><RowNode><SomeTag /></RowNode></RootNode>

一些背景:

XML 不存储为您看到的字符串表示形式,而是存储为层次结构表。每当您在屏幕上显示 XML 时,它的字符串表示就会从头开始重建。每次调用它时都会略有不同(例如属性的顺序、CDATA 部分、空元素)。

如果您需要,您只能在字符串级别强制执行此格式。您可能会使用某种RegEx 方法,将任何&lt;abc/&gt; 替换为&lt;abc&gt;&lt;/abc&gt;

但又一次:你不应该考虑那个......

更新

用这个SELECT试试上面的代码:

SELECT *
      ,CAST(YourXML AS NVARCHAR(MAX)) AS CastedToString
FROM @tbl

结果

ID  YourXML 
    CastedToString

    --implicitly changed to self-closing tags
1   <RootNode><RowNode><SomeTag></SomeTag></RowNode></RootNode> 
    <RootNode><RowNode><SomeTag/></RowNode></RootNode>

    --Self-closing **without a blank!!!**
2   <RootNode><RowNode><SomeTag /></RowNode></RootNode> 
    <RootNode><RowNode><SomeTag/></RowNode></RootNode>

您可以看到,字符串级别的比较并不是那么容易...而且很难预测...您可以使用CAST(YourXml.query(N'.') AS NVARCHAR(MAX)) 对每个 XML 执行相同的操作...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 2011-10-18
    相关资源
    最近更新 更多