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 включен, но дочерний элемент закодирован с использованием
>
вместо> Что так странно с разумной точки зрения. Я уверен, что есть технические объяснения, но они глупые, потому что в спецификации FOR XML нет разницы.
Вы можете включить опцию type
на внутреннем дочернем узле, а затем тоже потерять cdata.. НО ПОЧЕМУ О ПОЧЕМУ?!?!?!?! вы (Microsoft) удалили бы cdata, когда я только что добавил?
<Customers>
<Customer>
<Customer_ID>10001</Customer_ID>
<Title><![CDATA[AirBallon Captain]]></Title>
<Location>
<Title><![CDATA[wrapped in cdata, using explicit]]></Title>
</Location>
</Customer>
</Customers>