SQL server mengubah struktur XML ketika dimasukkan

15

Saya memasukkan beberapa data XML ke kolom XML di SQL server tetapi setelah data dimasukkan, telah diubah oleh sql server. Berikut adalah data yang saya masukkan

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

Ketika saya membacanya kembali, sepertinya ini

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

Perhatikan baris kedua. Ini adalah masalah karena itu mengubah bagaimana output transformasi XSLT akan. Contoh pertama akan membuat spasi antara diberikan dan nama keluarga, sedangkan yang kedua tidak akan membuat spasi, jadi itu akan seperti John Johnsen, sedangkan yang pertama akan seperti John Johnsen.

Apakah ada cara untuk menyelesaikan ini?

Tuan Zach
sumber
Ini adalah masalah, karena ini memang mengubah bagaimana output transformasi XSLT. Baris pertama akan membuat spasi antara diberi dan nama keluarga, sedangkan baris kedua tidak akan membuat spasi di antara, jadi itu akan seperti John Johnsen, sedangkan yang pertama akan seperti John Johnsen
Mr Zach
hmhm, ruang yang tepat "" tetapi tidak hanya ruang seperti dalam komentar ini (Anda tidak dapat melihatnya)
a_vlad
1
Mungkin Anda bisa menggunakan karakter kontrol yang tidak ada dalam data (suka _atau ~) dan kemudian menggantinya dengan spasi pada waktu presentasi.
Aaron Bertrand

Jawaban:

25

Anda dapat menggunakan xml:space = "preserve"node yang ingin Anda simpan di ruang kosong. Menggunakan xml: space adalah "hanya isyarat niat" tetapi SQL server ramah kepada kami di sini.

Untuk satu simpul

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

select @X;

Hasil:

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

Seluruh dokumen:

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

select @X;

Hasil:

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

Opsi lain untuk keseluruhan dokumen adalah menggunakan convert dengan style 1 .

Pertahankan ruang putih yang tidak signifikan. Pengaturan gaya ini menetapkan xml: penanganan ruang default agar sesuai dengan perilaku xml: space = "preserve".

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

select @X;
Mikael Eriksson
sumber
Menarik bahwa ini diperlukan. Seharusnya bukan hak SQL Server untuk memutuskan apa spasi "tidak signifikan" dan diam-diam menghapusnya tanpa modifikasi dokumen!
Lightness Races dengan Monica
3
@LightnessRacesinOrbit Saya cukup senang dengan implementasi oleh SQL Server. Memformat (spasi putih) dalam XML tidak dianggap penting sampai Anda mengatakannya. Lihat contoh ini untuk melihat jumlah node yang sebenarnya ada dalam dokumen dan apa fungsinya untuk ukuran penyimpanan ..
Mikael Eriksson
3
Saya menganggapnya sebagai pelanggaran spesifikasi, karena di sini data diterima sebagai XML dan disimpan sebagai XML, tanpa manipulasi atau transformasi atau bentuk lain dari shenanigans lapisan-XML selain hanya menyimpan dokumen (seolah-olah), sehingga perilaku tersebut harus jatuh ke dalam "prosesor" daripada "aplikasi", dan karena itu tidak boleh menghapus spasi .
Lightness Races dengan Monica
9

Halaman ini dari dokumentasi SQL Server mengatakan

Data disimpan dalam representasi internal yang ... mungkin bukan salinan teks XML yang identik, karena informasi berikut ini tidak disimpan: spasi putih yang tidak signifikan, urutan atribut, awalan namespace, dan deklarasi XML.

Sebagai contoh Anda, saya menganggap itu menganggap ruang putih tag tengah tidak signifikan dan karena itu bebas untuk memperbaiki representasi. Saya tidak berpikir ada perbaikan untuk ini; itu hanya bagaimana SQL Server mengimplementasikan tipe data XML.

Work-arounds akan mencakup penggunaan place-holder alih-alih white space seperti yang dikatakan @Aaron. Konsumen harus ingat untuk memasukkan dan menghapus token ini. Atau tentukan kolom tersebut sebagai nvarchar dan bukan XML. Ini pasti akan mempertahankan semua ruang putih dan pemformatan lainnya. Contoh cepat:

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

Kolom nvarchar mempertahankan format input, sedangkan kolom XML tidak.

Anda akan kehilangan kemampuan untuk menggunakan XPATH dalam kueri SQL. Jika XML hanya robek dalam aplikasi ini tidak penting. Selanjutnya string karakter dapat dikompresi menghemat ruang dalam DB, jika ini penting bagi Anda.

Michael Green
sumber
Anda mungkin masih dapat menggunakan XPATH dalam kueri terhadap versi XML, bahkan jika Anda membiarkannya memformat ulang, selama Anda tidak mengandalkan hit (atau miss) untuk ruang yang tidak signifikan di sana.
Aaron Bertrand
0

Anda dapat membungkus ruang Anda di dalam CDATAsaat menyimpan data:

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

Tampaknya SQL server kemudian menyimpan ruang secara internal, tetapi menghapus CDATAmarkup yang tidak perlu itu sendiri ketika mendapatkan hasilnya kembali menggunakan SELECT. Untungnya, ruang disimpan ketika menggunakan kembali hasil seperti SELECT:

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

SET @Y = (SELECT @X)

SELECT @Y

Hasilnya adalah:

<text> </text>
Bruno
sumber
Juga mencoba CDATA tetapi juga dihapus.
Tuan Zach
@MrZach CDATA sendiri dihapus, tetapi masih ada ruang. (Mencoba SQL Express 2016.)
Bruno
Aneh, di sini ruang itu dihapus. Pikirkan juga ungkapkan 2016 atau 2017
Mr Zach