SQL SERVER XML с CDATA

У меня есть таблица в моей базе данных со столбцом, содержащим XML. Тип столбца nvarchar(max). XML формируется таким образом

<root>
  <child>....</child>
  .
  .
  <special>
   <event><![CDATA[text->text]]></event>
   <event><![CDATA[text->text]]></event>
  ...
  </special>
</root>

Я не создал БД, я не могу изменить способ хранения информации в нем, но я могу получить его с помощью выбора. Для извлечения я использую выбор таблицы (заменить (xml,'utf-8','utf-16') как xml) из таблицы

Он работает хорошо, за исключением cdata, содержимое которого в выводе запроса: text -> text

Есть ли способ получить также теги CDATA?

1 ответ

Решение

Ну, это - насколько я знаю - невозможно по обычным путям...

CDATAраздел имеет одну единственную причину: включить недопустимые символы в XML для ленивых людей...

CDATA вообще не рассматривается как необходимый и, следовательно, не поддерживается обычными методами XML. Или другими словами: поддерживается таким образом, что контент правильно экранирован. Нет разницы между правильно экранированным контентом и не экранированным контентом внутри CDATA на самом деле! (Хорошо, есть некоторые незначительные различия, такие как ]]> в пределах CDATAи еще несколько крошечных блюд...)

Большой вопрос: почему?

Что вы пытаетесь сделать с этим потом?

Попробуй это. включенный текст дается как есть:

DECLARE @xml XML = 
'<root>
  <special>
   <event><![CDATA[text->text]]></event>
   <event><![CDATA[text->text]]></event>
  </special>
</root>'

SELECT t.c.query('text()')
FROM @xml.nodes('/root/special/event') t(c);

Итак: Пожалуйста, объясните еще несколько деталей: что вы действительно хотите?

Если вам действительно не нужно ничего, кроме упаковки CDATA Вы можете использовать это:

SELECT '<![CDATA[' + t.c.value('.','varchar(max)') + ']]>'
FROM @xml.nodes('/root/special/event') t(c);

Обновление: То же самое с устаревшим FROM OPENXML

Я просто попробовал, как устаревший подход с FROM OPENXML обрабатывает это и обнаруживает, что в наборе результатов нет абсолютно никакого указания, что данный текст был в пределах CDATA раздел изначально. "Некоторое значение здесь" возвращается точно так же, как текст в CDATA:

DECLARE @doc XML = 
'<root>
  <child>Some value here </child>
  <special>
   <event><![CDATA[text->text]]></event>
   <event><![CDATA[text->text]]></event>
  </special>
</root>';

DECLARE @hnd INT;

EXEC sp_xml_preparedocument @hnd OUTPUT, @doc;  

SELECT * FROM OPENXML (@hnd, '/root',0);

EXEC sp_xml_removedocument @hnd;  

Вот как включить cdata в дочерние узлы в XML, используя чистый SQL. Но; это не идеально.

SELECT 1 AS tag, 
   null AS parent, 
   '10001' AS 'Customer!1!Customer_ID!Element', 
   'AirBallon Captain' AS 'Customer!1!Title!cdata', 

   'Customer!1' = (
        SELECT 
               2 AS tag, 
               NULL AS parent, 
               'Wrapped in cdata, using explicit' AS 'Location!2!Title!cdata' 
               FOR XML EXPLICIT)

FOR XML EXPLICIT, ROOT('Customers')

CDATA включен, но дочерний элемент закодирован с использованием

&gt;

вместо> Что так странно с разумной точки зрения. Я уверен, что есть технические объяснения, но они глупые, потому что в спецификации FOR XML нет разницы.

Вы можете включить опцию typeна внутреннем дочернем узле, а затем тоже потерять cdata.. НО ПОЧЕМУ О ПОЧЕМУ?!?!?!?! вы (Microsoft) удалили бы cdata, когда я только что добавил?

<Customers>
  <Customer>
    <Customer_ID>10001</Customer_ID>
    <Title><![CDATA[AirBallon Captain]]></Title>
     &lt;Location&gt;
       &lt;Title&gt;&lt;![CDATA[wrapped in cdata, using explicit]]&gt;&lt;/Title&gt;
     &lt;/Location&gt;
 </Customer>
</Customers>
Другие вопросы по тегам