2

我需要将数据库中所有存储过程的文本存储为 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.

4

3 回答 3

2

如果您想在XML中存储带有特殊字符的数据,有两个选项(加上一个笑话选项)

  • 逃跑
  • CDATA
  • 只是提一下:将所有内容转换为base64或类似内容也可以:-)

关键是:你不需要这个!

CDATA(至少对我来说)的唯一原因是手动创建的内容(复制'n'粘贴或打字)。每当您自动构建 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 &lt;ups, angular brackets! &gt; And Ampersand &amp;&amp;&amp;

但是这个...

SELECT (SELECT @TextWithSpecialCharacters FOR XML PATH('test'),TYPE).value('/test[1]','nvarchar(100)');

...返回

€ This is
strange <ups, angular brackets! > And Ampersand &&&

微软甚至决定不支持这一点FOR XML(除了EXPLICIT,这是一件令人头疼的事情......)

阅读关于 CDATA 的两个相关答案(由我 :-))

于 2016-09-14T08:24:34.307 回答
2

当我使用 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 类型数据中获取值的教程;这只是一个例子。

于 2016-09-14T08:29:45.510 回答
0
    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>

如您所见,没有&#xD; / &#xA; / &quot;/ etc新行字符表示为新行

于 2016-09-13T23:11:57.947 回答