Хранение текста хранимой процедуры в типе данных XML в SQL Server
Мне нужно сохранить текст всех хранимых процедур в базе данных в тип данных XML. Когда я использую, FOR XML PATH
текст внутри хранимой процедуры содержит сериализованные символы данных, такие как 
а также 

для CRLF и "
и т. д. Мне нужно, чтобы текст хранился в структуре xml без этих символов, потому что этот текст необходимо будет использовать для воссоздания хранимой процедуры.
Это запрос, который я использую для FOR XML PATH
:
SELECT
[View].name AS "@VName", [Module].definition AS "@VDefinition"
FROM
sys.views AS [View]
INNER JOIN
sys.sql_modules AS [Module] ON [Module].object_id = [View].object_id
FOR XML PATH ('View'), TYPE
Я прочитал, что я должен использовать CDATA
для использования текста FOR XML EXPLICIT
, Тем не менее, вывод, когда я запускаю следующий запрос и просматриваю данные XML, он также содержит эти символы. Мне нужно, чтобы текст был простым текстом без этих символов.
Это мой запрос:
SELECT
1 AS Tag,
0 AS Parent,
NULL AS [Database1!1],
NULL AS [StoredProcedure!2!VName],
NULL AS [StoredProcedure!2!cdata]
UNION ALL
SELECT
2 AS Tag,
1 AS Parent,
NULL,
[StoredProcedure].name as [StoredProcedure!2!!CDATA],
[Module].definition as [StoredProcedure!2!!CDATA]
FROM
sys.procedures AS [StoredProcedure]
INNER JOIN
sys.sql_modules [Module] ON [StoredProcedure].object_id = [Module].object_id
WHERE
[StoredProcedure].name NOT LIKE '%diagram%'
FOR XML EXPLICIT
Как я могу сохранить текст хранимых процедур в виде простого текста? Или когда я анализирую тип данных xml для воссоздания хранимой процедуры, могу ли я десериализовать ее так, чтобы в ней не было этих символов?
В идеале я хотел бы использовать FOR XML PATH
но если это невозможно, я буду использовать FOR XML EXPLICIT
,
3 ответа
Если вы хотите хранить данные со специальными символами в XML, есть две опции (плюс опция шутки)
- побег
CDATA
- просто упомянуть: конвертировать все в
base64
или подобное тоже подойдет:-)
Дело в том, что вам это не нужно!
Единственная причина CDATA
(по крайней мере для меня) - это контент, созданный вручную (копирование или вставка). Всякий раз, когда вы создаете свой XML автоматически, вы должны полагаться на неявно применяемое экранирование.
Почему вас беспокоит, как данные выглядят в XML?
Если вы прочитали это правильно (не с SUBSTRING
или другие строковые методы), вы получите его обратно в первоначальном виде.
Попробуй это:
DECLARE @TextWithSpecialCharacters NVARCHAR(100)=N'€ This is' + CHAR(13) + 'strange <ups, angular brackets! > And Ampersand &&&';
SELECT @TextWithSpecialCharacters FOR XML PATH('test');
возвращается
€ This is
strange <ups, angular brackets! > And Ampersand &&&
Но это...
SELECT (SELECT @TextWithSpecialCharacters FOR XML PATH('test'),TYPE).value('/test[1]','nvarchar(100)');
... возврат
€ This is
strange <ups, angular brackets! > And Ampersand &&&
Microsoft решила даже не поддерживать это FOR XML
(Кроме EXPLICIT
это боль в шее...)
Прочитайте два связанных ответа (я:-) о CDATA)
Когда я использую FOR XML PATH, текст в хранимой процедуре содержит сериализованные символы данных, такие как и для CRLF и ", и т. Д.
Да, потому что так работает XML. Для более ясного примера, предположим, что ваш спрок содержал этот текст:
IF @someString = '<' THEN
затем, чтобы сохранить его в XML, должна быть применена какая-то кодировка, поскольку вы не можете иметь <
в середине вашего XML (надеюсь, вы поймете, почему).
Тогда реальный вопрос не в том, "как мне остановить кодирование моего текста, когда я сохраняю его в формате XML", а в том, что (как вы можете догадаться, так):
Или когда я анализирую тип данных xml для воссоздания хранимой процедуры, могу ли я десериализовать ее так, чтобы в ней не было этих символов?
Да, это подход, на который вы должны смотреть.
Вы не знаете, как мы получаем ваш текст из XML в данный момент. Главное, что нужно помнить, это то, что вы не можете (или, скорее, не должны) рассматривать XML как "текст с дополнительными битами" - вы должны использовать методы, которые понимают XML.
Если вы извлекаете текст в самом T-SQL, используйте различные параметры XQuery. Если в C#, используйте любую из различных библиотек XML. Только не делайте операцию с подстрокой и ожидайте, что это сработает...
Пример, если вы извлекаете в T-SQL:
DECLARE @someRandomText nvarchar(max) = 'I am some arbitrary text, eg a sproc definition.
I contain newlines
And arbitrary characters such as < > &
The end.';
-- Pack into XML
DECLARE @asXml xml = ( SELECT @someRandomText FOR XML PATH ('Example'), TYPE );
SELECT @asXml;
-- Extract
DECLARE @textOut nvarchar(max) = ( SELECT @asXml.value('.', 'nvarchar(max)') ) ;
SELECT @textOut;
Но вы можете найти много учебников о том, как извлечь значения из данных, типизированных в xml; это всего лишь пример.
SELECT
1 as Tag,
0 as Parent,
[View].name AS 'StoredProcedure!1!Name',
[Module].definition AS 'StoredProcedure!1!Definition!cdata'
FROM sys.views AS [View]
INNER JOIN sys.sql_modules AS [Module] ON [Module].object_id = [View].object_id
FOR XML EXPLICIT
Пример вывода из Adventureworks2012:
<StoredProcedure Name="vStoreWithContacts">
<Definition><![CDATA[
CREATE VIEW [Sales].[vStoreWithContacts] AS
SELECT
s.[BusinessEntityID]
,s.[Name]
,ct.[Name] AS [ContactType]
,p.[Title]
,p.[FirstName]
,p.[MiddleName]
,p.[LastName]
,p.[Suffix]
,pp.[PhoneNumber]
,pnt.[Name] AS [PhoneNumberType]
,ea.[EmailAddress]
,p.[EmailPromotion]
FROM [Sales].[Store] s
INNER JOIN [Person].[BusinessEntityContact] bec
ON bec.[BusinessEntityID] = s.[BusinessEntityID]
INNER JOIN [Person].[ContactType] ct
ON ct.[ContactTypeID] = bec.[ContactTypeID]
INNER JOIN [Person].[Person] p
ON p.[BusinessEntityID] = bec.[PersonID]
LEFT OUTER JOIN [Person].[EmailAddress] ea
ON ea.[BusinessEntityID] = p.[BusinessEntityID]
LEFT OUTER JOIN [Person].[PersonPhone] pp
ON pp.[BusinessEntityID] = p.[BusinessEntityID]
LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
ON pnt.[PhoneNumberTypeID] = pp.[PhoneNumberTypeID];
]]></Definition>
</StoredProcedure>
<StoredProcedure Name="vStoreWithAddresses">
<Definition><![CDATA[
CREATE VIEW [Sales].[vStoreWithAddresses] AS
SELECT
s.[BusinessEntityID]
,s.[Name]
,at.[Name] AS [AddressType]
,a.[AddressLine1]
,a.[AddressLine2]
,a.[City]
,sp.[Name] AS [StateProvinceName]
,a.[PostalCode]
,cr.[Name] AS [CountryRegionName]
FROM [Sales].[Store] s
INNER JOIN [Person].[BusinessEntityAddress] bea
ON bea.[BusinessEntityID] = s.[BusinessEntityID]
INNER JOIN [Person].[Address] a
ON a.[AddressID] = bea.[AddressID]
INNER JOIN [Person].[StateProvince] sp
ON sp.[StateProvinceID] = a.[StateProvinceID]
INNER JOIN [Person].[CountryRegion] cr
ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
INNER JOIN [Person].[AddressType] at
ON at.[AddressTypeID] = bea.[AddressTypeID];
]]></Definition>
Как вы заметили, нет 
 / 
 / "/ etc
и символы NewLine представлены в виде новой строки