插入时SQL Server更改XML结构


15

我正在将一些XML数据插入SQL Server中的XML列,但是在插入数据后,SQL Server已对其进行了更改。这是我插入的数据

              <xsl:value-of select="name/n/given" />
            <xsl:text> </xsl:text>
          <xsl:value-of select="name/n/family" />

当我读回它时,它看起来像这样

              <xsl:value-of select="name/n/given" />
          <xsl:text />
          <xsl:value-of select="name/n/family" />

注意第二行。这是一个问题,因为它更改了XSLT转换输出的方式。第一个示例将在给定名称和姓氏之间创建一个空格,而第二个示例将不创建任何空格,因此它将类似于JohnJohnsen,而第一个示例将类似于John Johnsen。

有什么办法可以解决这个问题?


这是一个问题,因为这确实改变了XSLT转换输出的方式。第一行将在给定名称和姓氏之间创建一个空格,而第二行将在约翰·约翰森之间不创建任何空格,因此它将类似于JohnJohnsen,而第一行将类似于John Johnsen
Zach先生

嗯,适当的空间是“”,但不仅仅是此评论中的空间(您看不到)
a_vlad18 '18

1
也许您可以使用数据中不存在的控制字符(例如_~),然后在演示时将其替换为空格。
亚伦·伯特兰

Answers:


25

您可以xml:space = "preserve"在要保留空间的节点上使用。使用xml:space只是“一个意图的信号”,但是SQL服务器在这里对我们很友善。

对于一个节点

declare @X xml =
'<root>
  <element xml:space = "preserve"> </element>
  <element> </element>
</root>'

select @X;

结果:

<root>
  <element xml:space="preserve"> </element>
  <element />
</root>

整个文件:

declare @X xml =
'<root xml:space = "preserve">
  <element> </element>
  <element> </element>
</root>'

select @X;

结果:

<root xml:space="preserve">
  <element> </element>
  <element> </element>
</root>

整个文档的另一种选择是将convert与样式1一起使用。

保留微不足道的空白。此样式设置将默认的xml:space处理设置为匹配xml:space =“ preserve”的行为。

declare @X xml = convert(xml, 
'<root>
  <element> </element>
  <element> </element>
</root>', 1)

select @X;

有趣的是,这是必需的。决定什么空格是“无关紧要的”并且在没有文档修改的情况下静默剥离它不是SQL Server的职责!
与莫妮卡(Monica)进行轻度比赛

3
@LightnessRacesinOrbit我对SQL Server的实现感到非常满意。除非您这么说,否则认为XML格式(空格)不重要。看一下这个例子,看看文档中实际存在的节点数以及它对存储大小的影响。–
Mikael Eriksson

3
我认为这是违反规范的,因为这里数据被接受为XML并存储为XML,除了简单地(表面上)存储文档外,没有其他任何形式的操作或转换或任何其他形式的XML层恶作剧,因此行为应属于“处理器”而不是“应用程序”,因此不得剥离空格
莫妮卡(Monica)与Lightness比赛'18

9

SQL Server文档的此页面

数据以内部表示形式存储,该内部表示形式...可能不是文本XML的相同副本,因为没有保留以下信息:无关紧要的空格,属性顺序,名称空间前缀和XML声明。

对于您的示例,我假设它认为中间标签的空白不重要,因此可以自由重构表示形式。我认为没有解决办法。这就是SQL Server实现XML数据类型的方式。

解决方法将包括使用占位符而不是@Aaron所说的空白。消费者必须记住要插入和删除这些令牌。或者,将该列定义为nvarchar而不是XML。这肯定会保留所有空白和任何其他格式。一个简单的例子:

create table x(i nvarchar(99), j xml);
insert x values ('<a> </a>', '<a> </a>');  -- note the space
select * from x

i           j
----------  -------
<a> </a>    <a />  

nvarchar列保留输入格式,而XML列则保留。

您将失去在SQL查询中使用XPATH的能力。如果仅将XML切碎在应用程序中,则无关紧要。此外,如果这对您很重要,则可以压缩字符串以节省数据库中的空间。


即使您只是让它重新格式化,您仍然可以在针对XML版本的查询中使用XPATH,只要您不依赖于命中(或遗漏)那里的微不足道的空间即可。
亚伦·伯特兰

0

您可以CDATA在存储数据时在其中包裹空间:

<xsl:text><![CDATA[ ]]></xsl:text>

看来SQL Server然后在内部保留了空间,但是在CDATA使用返回的结果时会删除不必要的标记本身SELECT。幸运的是,当重新使用以下结果时,将保留该空间SELECT

DECLARE @X XML = '<text><![CDATA[ ]]></text>'
DECLARE @Y XML

SET @Y = (SELECT @X)

SELECT @Y

结果将是:

<text> </text>

还尝试了CDATA,但也将其删除。
扎克先生

@MrZach CDATA本身已删除,但空间仍然存在。(在SQL Express 2016上试用。)
Bruno '18

奇怪,这里的空间被删除了。想想也可以表达2016年或2017年
扎克先生
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.