web-dev-qa-db-ja.com

SQLサーバーは挿入時にXML構造を変更します

SQLサーバーのXML列にいくつかのXMLデータを挿入していますが、データが挿入された後、SQLサーバーによって変更されました。ここに私が挿入したデータがあります

              <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" />

2行目に注意してください。 XSLT変換の出力方法が変わるため、これは問題です。最初の例は、名と姓の間にスペースを作成しますが、2番目の例はスペースを作成しないため、JohnJohnsenのようになり、最初の例はJohn Johnsenのようになります。

これを解決する方法はありますか?

15
Mr Zach

xml:space = "preserve" スペースを確保するノード上。 xml:spaceの使用は "意図の合図のみ" ですが、ここではSQLサーバーが親切です。

1つのノード

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>

ドキュメント全体の別のオプションは、 スタイル1で変換 を使用することです。

意味のない空白を保存します。このスタイル設定は、xml:space = "preserve"の動作と一致するようにデフォルトのxml:space処理を設定します。

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

select @X;
25
Mikael Eriksson

これは、SQL Serverのドキュメントの ページ によると

次の情報が保持されないため、データは内部の表現で保存されます。テキストのXMLの同一のコピーではない可能性があります。重要でない空白、属性の順序、名前空間の接頭辞、およびXML宣言。

あなたの例では、中央タグの空白は重要ではないと見なしているため、表現を自由にリファクタリングできます。これに対する修正はないと思います。 SQL ServerがXMLデータ型を実装する方法です。

回避策には、@ Aaronが言うように、空白の代わりにプレースホルダーを使用することが含まれます。コンシューマは、これらのトークンを挿入して取り除くことを忘れないでください。または、列をXMLではなくnvarcharとして定義します。これにより、すべての空白とその他のフォーマットが確実に保持されます。簡単な例:

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がアプリケーションでのみ細断処理される場合、これは重要ではありません。さらに、これが重要である場合は、文字列を圧縮してDBのスペースを節約できます。

9
Michael Green

データを保存するときに、スペースを CDATA で囲むことができます。

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

SQLサーバーはスペースを内部的に保持しているようですが、CDATAを使用して結果を取得するときに不要なSELECTマークアップ自体を削除します。幸い、そのようなSELECTの結果を再利用する場合、スペースは保持されます。

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

SET @Y = (SELECT @X)

SELECT @Y

結果は次のようになります。

<text> </text>
0
Bruno