Máy chủ SQL thay đổi cấu trúc XML khi được chèn


15

Tôi đang chèn một số dữ liệu XML vào một cột XML trong máy chủ SQL nhưng sau khi dữ liệu được chèn, nó đã bị máy chủ sql thay đổi. Đây là dữ liệu tôi chèn

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

Khi tôi đọc lại, có vẻ như thế này

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

Hãy chú ý đến dòng thứ hai. Đây là một vấn đề vì nó thay đổi cách đầu ra chuyển đổi XSLT. Ví dụ đầu tiên sẽ tạo một khoảng trắng giữa tên đã cho và tên gia đình, trong khi ví dụ thứ hai sẽ không tạo bất kỳ khoảng trắng nào, vì vậy nó sẽ giống như JohnJohnsen, trong khi cái đầu tiên sẽ giống như John Johnsen.

Có cách nào để giải quyết điều này?


Đây là một vấn đề, bởi vì điều này không thay đổi cách đầu ra chuyển đổi XSLT. Dòng đầu tiên sẽ tạo một khoảng trắng giữa tên được đặt và họ, trong khi dòng thứ hai sẽ không tạo khoảng trắng giữa, vì vậy nó sẽ giống như JohnJohnsen, trong khi dòng đầu tiên sẽ giống như John Johnsen
Mr Zach

hmhm, không gian thích hợp đó là "" nhưng không chỉ là một không gian như trong bình luận này (bạn không thể nhìn thấy nó)
a_vlad

1
Có lẽ bạn có thể sử dụng một ký tự điều khiển không tồn tại trong dữ liệu (như _hoặc ~) và sau đó thay thế bằng một khoảng trắng tại thời điểm thuyết trình.
Aaron Bertrand

Câu trả lời:


25

Bạn có thể sử dụng xml:space = "preserve"trên các nút mà bạn muốn giữ khoảng trống. Sử dụng xml: space là "chỉ là tín hiệu của ý định" nhưng máy chủ SQL rất tử tế với chúng tôi ở đây.

Đối với một nút

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

select @X;

Kết quả:

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

Toàn bộ tài liệu:

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

select @X;

Kết quả:

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

Một tùy chọn khác cho toàn bộ tài liệu là sử dụng chuyển đổi với kiểu 1 .

Bảo tồn không gian trắng không đáng kể. Cài đặt kiểu này đặt xml: xử lý không gian mặc định để khớp với hành vi của xml: space = "reserved".

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

select @X;

Điều thú vị là điều này là bắt buộc. Không nên gửi tiền của SQL Server để quyết định khoảng trắng nào là "không đáng kể" và âm thầm loại bỏ nó mà không cần sửa đổi tài liệu!
Cuộc đua nhẹ nhàng với Monica

3
@LightnessRacesinOrbit Tôi khá hài lòng với việc triển khai bởi SQL Server. Định dạng (khoảng trắng) trong XML không được coi là quan trọng cho đến khi bạn nói nó là. Hãy xem ví dụ này để xem số lượng nút thực sự có trong tài liệu và những gì nó làm với kích thước lưu trữ ..
Mikael Eriksson

3
Tôi coi đó là một sự vi phạm đặc tả, bởi vì ở đây dữ liệu được chấp nhận là XML và được lưu trữ dưới dạng XML, không có thao tác hoặc chuyển đổi hoặc bất kỳ hình thức shenanigans lớp XML nào khác ngoài việc lưu trữ tài liệu (bề ngoài), vì vậy hành vi nên rơi vào "bộ xử lý" chứ không phải là "ứng dụng", và do đó không được tước khoảng trắng .
Cuộc đua nhẹ nhàng với Monica

9

Đây trang của tài liệu SQL Server nói

Dữ liệu được lưu trữ trong một biểu diễn bên trong mà ... có thể không phải là bản sao giống hệt của XML văn bản, vì thông tin sau không được giữ lại: khoảng trắng không đáng kể, thứ tự các thuộc tính, tiền tố không gian tên và khai báo XML.

Đối với ví dụ của bạn, tôi cho rằng nó coi khoảng trắng của thẻ giữa là không đáng kể và do đó có thể tự do cấu trúc lại biểu diễn. Tôi không nghĩ rằng có một sửa chữa cho điều này; đó chỉ là cách SQL Server triển khai kiểu dữ liệu XML.

Công việc xung quanh sẽ bao gồm sử dụng trình giữ chỗ thay vì khoảng trắng như @Aaron nói. Người tiêu dùng phải nhớ chèn và loại bỏ các mã thông báo này. Hoặc định nghĩa cột là nvarchar thay vì XML. Điều này chắc chắn sẽ bảo tồn tất cả các khoảng trắng và bất kỳ định dạng nào khác. Một ví dụ nhanh:

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

Cột nvarchar bảo tồn định dạng đầu vào, cột XML thì không.

Bạn sẽ mất khả năng sử dụng XPATH trong các truy vấn SQL. Nếu XML chỉ được băm nhỏ trong ứng dụng thì đây là không quan trọng. Hơn nữa, chuỗi ký tự có thể được nén không gian tiết kiệm trong DB, nếu điều này có ý nghĩa đối với bạn.


Bạn có thể vẫn có thể sử dụng XPATH trong các truy vấn đối với phiên bản XML, ngay cả khi bạn chỉ cho phép định dạng lại, miễn là bạn không dựa vào lần truy cập (hoặc bỏ lỡ) cho không gian không đáng kể ở đó.
Aaron Bertrand

0

Bạn có thể bao bọc không gian của mình trong CDATAkhi lưu trữ dữ liệu:

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

Dường như máy chủ SQL sau đó giữ không gian bên trong, nhưng sẽ loại bỏ các CDATAđánh dấu không cần thiết khi lấy lại kết quả bằng cách sử dụng SELECT. May mắn thay, không gian được giữ lại khi sử dụng lại kết quả của một SELECT:

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

SET @Y = (SELECT @X)

SELECT @Y

Kết quả sẽ là:

<text> </text>

Cũng đã thử CDATA nhưng nó cũng bị xóa.
Ông Zach

@MrZach CDATA đã bị xóa, nhưng dung lượng vẫn còn. (Đã thử trên SQL Express 2016.)
Bruno

Lạ thật, ở đây không gian đã được gỡ bỏ. Think cũng express 2016 hoặc 2017
Mr Zach
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.