2010-08-14 44 views
0

我使用SELECT ... FOR XML来生成XML,它创建了我想要看到的 - SSMS。但...T-SQL:使用存储过程将表导出为XML - 如何格式化?

我遇到的问题是,导出的XML文件在一行中包含整个XML主体。它是有效的XML,但我怎样才能格式化输出? (每行一个元素,以\ r \ n结尾,最好缩进)该文件在记事本中应该是人类可读的。

另外,是否有更好的方法来处理XML头?

当然,我可以写一个CLR存储过程来执行导出,看起来像是过度杀伤。 (这是为什么甚至很难?)

ALTER PROCEDURE [dbo].[ExportConfigTablesToXML] 
AS 
BEGIN 
-- SET NOCOUNT ON added to prevent extra result sets from 
-- interfering with SELECT statements. 
SET NOCOUNT ON; 

--EXEC sp_configure 'show advanced options', 1 
--RECONFIGURE 
--EXEC sp_configure 'xp_cmdshell', 1 
--RECONFIGURE 
--EXEC sp_configure 'show advanced options', 0 
--RECONFIGURE 

DECLARE @FileName VARCHAR(50) 
DECLARE @SQLCmd VARCHAR(500) 
DECLARE @CreateXmlHeader varchar(500) 
DECLARE @AppendXmlBody varchar(500) 
DECLARE @DeleteTempFile varchar(500) 

SELECT @FileName = 'C:\Temp\SampleXMLOutput.xml' 
SELECT @SQLCmd = 'bcp ' + 
    '"SELECT Name AS [@Name], ServiceName, MachineName,' + 
    ' CASE PollInterval WHEN 10 THEN NULL ELSE PollInterval END AS PollInterval,' + 
    ' CASE Alerts WHEN 1 THEN NULL ELSE ''false'' END AS Alerts, ' + 
    ' CASE Pages WHEN 1 THEN NULL ELSE ''false'' END AS Pages' + 
    ' FROM Watchdog.dbo.[Config.Services] [Service]' + 
    ' FOR XML PATH(''Service''), ROOT(''Services'')"' + 
    ' queryout ' + 
    @FileName + '.tmp' + 
    ' -S' + @@SERVERNAME + 
    ' -T -c -r -t' 

SET @CreateXmlHeader = 'ECHO ^<?xml version="1.0" ?^> > ' + @FileName 
SET @AppendXmlBody = 'TYPE ' + @FileName + '.tmp >> ' + @FileName 
SET @DeleteTempFile = 'DEL ' + @FileName + '.tmp' 

EXECUTE master..xp_cmdshell @SQLCmd 
EXECUTE master..xp_cmdshell @CreateXmlHeader 
EXECUTE master..xp_cmdshell @AppendXmlBody 
EXECUTE master..xp_cmdshell @DeleteTempFile 

END 

回答

0

既然你反正运行命令,也许你可以:

xmllint --format 

Free XML Formatting tool

+0

此应用程序将部署在生产网络域中,我不知道是否允许xmllint(或此类)。我的猜测可能不是,第三方应用程序的使用受到严格控制。 (对不起,在我原来的问题中没有提到这个。) – 2010-08-16 19:11:47

1

你可以包括通过将除了头部的将XML提取到一个子查询中。所以,你的BCP命令变为:

SELECT @SQLCmd = 'bcp ' + 
    '"SELECT ''<?xml version="1.0"?>'' + ' + 
    '(SELECT Name AS [@Name], ServiceName, MachineName,' + 
    ' CASE PollInterval WHEN 10 THEN NULL ELSE PollInterval END AS PollInterval,' + 
    ' CASE Alerts WHEN 1 THEN NULL ELSE ''false'' END AS Alerts, ' + 
    ' CASE Pages WHEN 1 THEN NULL ELSE ''false'' END AS Pages' + 
    ' FROM Watchdog.dbo.[Config.Services] [Service]' + 
    ' FOR XML PATH(''Service''), ROOT(''Services''))"' + 
    ' queryout ' + 
    @FileName + '.tmp' + 
    ' -S' + @@SERVERNAME + 
    ' -T -c -r -t' 
1

要关闭循环,我没有发现,没有缩进写入每行的XML一个标签的解决方案。这是一个令人厌恶的黑客行为,但它对我的目的是可以接受的,让我们看看它是否通过代码审查。如果有人想用缩进来查看文件,他们可以在IE中打开它(通过双击它)。

当然,真正的解决方案是一个CLR存储过程,但现在我更喜欢这种方式来保持部署简单,即只运行一个SQL脚本来部署数据库。

ALTER PROCEDURE [dbo].[ExportConfigTablesToXML] 
AS 
BEGIN 
-- SET NOCOUNT ON added to prevent extra result sets from 
-- interfering with SELECT statements. 
SET NOCOUNT ON; 

--EXEC sp_configure 'show advanced options', 1 
--RECONFIGURE 
--EXEC sp_configure 'xp_cmdshell', 1 
--RECONFIGURE 
--EXEC sp_configure 'show advanced options', 0 
--RECONFIGURE 

DECLARE @FileName VARCHAR(50) 
DECLARE @SQLCmd VARCHAR(1000) 

SELECT @FileName = 'C:\Temp\SampleXMLOutput.xml' 
SELECT @SQLCmd = 'bcp ' + 
    '"DECLARE @xml xml; ' + 
    'DECLARE @text varchar(MAX); ' + 

    'SET @xml = (SELECT Name AS [@Name], ServiceName, MachineName, ' + 
    ' CASE PollInterval WHEN 10 THEN NULL ELSE PollInterval END AS PollInterval, ' + 
    ' CASE Alerts WHEN 1 THEN NULL ELSE ''false'' END AS Alerts, ' + 
    ' CASE Pages WHEN 1 THEN NULL ELSE ''false'' END AS Pages ' + 
    'FROM Watchdog.dbo.[Config.Services] [Service] ' + 
    'FOR XML PATH(''Service''), ROOT(''Services''), TYPE); ' + 

    'SET @text = ''<?xml version=""1.0"" ?>'' + CHAR(13) + CHAR(10); ' + 
    'SET @text = @text + REPLACE(CAST(@xml AS varchar(MAX)), ''><'', ''>'' + CHAR(13) + CHAR(10) + ''<''); ' + 
    'SELECT @text" ' + 

    ' queryout ' + 
    @FileName + 
    ' -S' + @@SERVERNAME + 
    ' -T -c -r -t' 

EXECUTE master..xp_cmdshell @SQLCmd 

END