如何根据条件从SQL Server写入XML文件

时间:2015-10-24 23:00:53

标签: sql-server xml sql-server-2008 sql-server-2008-r2 sql-server-2012

一点背景,这是我的第一篇文章,但我从这个网站得到了很多解决方案。如果这是一个重新发布,我道歉,但我还没有找到一个好的解决方案,并且很难从其他地方拼凑出来以获得我想要的东西。

我已经找到了一些关于从SQL读取/导出XML的解决方案(在这里和在Google上)。但我有一个具体问题:如何从表中修改 XML格式的文件?

我有一个临时表,其中包含我的SQL 2012 STIG查询的所有结果。我一直在将它导出到.csv,但我还想添加将结果导出到.xml文件的功能。

以下是.xml:

的一个示例
<CHECKLIST>
  <ID>
    <SOME_DATA>
        <ID_ATTRIBUTE>ID_Num</ID_ATTRIBUTE>
        <ATTRIBUTE_DATA>123</ATTRIBUTE_DATA>
    </SOME_DATA>
    <SOME_DATA>
        <ID_ATTRIBUTE>REF</ID_ATTRIBUTE>
        <ATTRIBUTE_DATA>54</ATTRIBUTE_DATA>
    </SOME_DATA>
    <STATUS>Not_Reviewed</STATUS>
    <FINDING_DETAILS></FINDING_DETAILS>
    <COMMENTS></COMMENTS>
  </ID>
  <ID>
    <SOME_DATA>
        <ID_ATTRIBUTE>ID_Num</ID_ATTRIBUTE>
        <ATTRIBUTE_DATA>124</ATTRIBUTE_DATA>
    </SOME_DATA>
    <SOME_DATA>
        <ID_ATTRIBUTE>REF</ID_ATTRIBUTE>
        <ATTRIBUTE_DATA>145</ATTRIBUTE_DATA>
    </SOME_DATA>
    <STATUS>Not_Reviewed</STATUS>
    <FINDING_DETAILS></FINDING_DETAILS>
    <COMMENTS></COMMENTS>
  </ID>

我想要做的是:

IF <CHECKLIST/ID/SOME_DATA/ID_ATTRIBUTE> = 'ID_Num'
   AND <CHECKLIST/ID/SOME_DATA/ID_DATA> = @variable
      FROM 'e:\stuff\test.xml'
SET <CHECKLIST/ID/COMMENTS> = @comments_variable

我意识到上面的代码块是一个完全不正确的查询迭代,但我希望你能得到我想要做的事情。

我感谢任何帮助。

自定义存储过程(不是MS SQL的本机程序) HIGHLY 不鼓励。

2 个答案:

答案 0 :(得分:1)

考虑通用编程解决方案,特别是因为XML文件最初并不驻留在数据库中,例如BLOB字段中。 SQL是一种专用语言,主要用于管理(更新,附加,删除)和检索DML and DDL过程中的数据库内容。不建议让它做更多的事情,比如在外部处理文件。

但是对于您的需求,几乎任何通用语言,包括Java,C#,Perl,PHP,Python和VB都可以动态地解析和操作XML内容。下面是使用您的日常MS Excel的VBA宏示例。实际上,它使用另一个声明性的专用语言XSLT,主要用于修改,重新构造和重新格式化XML文档。是的,大多数编程语言都维护着XSLT处理器:

XSLT 另存为.xsl文件并在下面的宏中引用;也可以作为字符串嵌入到宏中)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />

<xsl:param name="var" select="123"/>

 <!-- IdentityTransform -->
 <xsl:template match="@*|node()">
   <xsl:copy>
     <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
 </xsl:template>

 <xsl:template match="COMMENTS">
   <COMMENTS>
    <xsl:if test="../SOME_DATA/ID_ATTRIBUTE='ID_Num' and ../SOME_DATA/ATTRIBUTE_DATA = $var">
       yak yak yak...
    </xsl:if>
   </COMMENTS>
 </xsl:template>    

</xsl:transform>

要更改变量和注释,只需调整上面的参数值'123'和yak yak yak节点文本。

Excel宏使用Microsoft的MSXML对象

Sub TransformXML()
On Error GoTo ErrHandle
    Dim xmldoc As Object, xsldoc As Object, newdoc As Object

    Set xmldoc = CreateObject("MSXML2.DOMDocument")
    Set xsldoc = CreateObject("MSXML2.DOMDocument")
    Set newdoc = CreateObject("MSXML2.DOMDocument")

    ' LOAD XML
    xmldoc.async = False
    xmldoc.Load "e:\stuff\test.xml"

    ' LOAD XSL
    xsldoc.async = False
    xsldoc.Load "e:\stuff\XSLT-SCRIPT.xsl"

    ' TRANSFORM
    xmldoc.transformNodeToObject xsldoc, newdoc
    newdoc.Save "e:\stuff\Output.xml"

    MsgBox "XML successfully modified!", vbInformation, "SUCCESSFUL OUTPUT"

    Set xmldoc = Nothing
    Set xsldoc = Nothing
    Set newdoc = Nothing
    Exit Sub

ErrHandle:
    MsgBox Err.Number & " - " & Err.Description, vbCritical
    Set xmldoc = Nothing
    Set xsldoc = Nothing
    Set newdoc = Nothing
    Exit Sub    
End Sub

<强>输出

<?xml version="1.0" encoding="UTF-8"?>
<CHECKLIST>
    <ID>
        <SOME_DATA>
            <ID_ATTRIBUTE>ID_Num</ID_ATTRIBUTE>
            <ATTRIBUTE_DATA>123</ATTRIBUTE_DATA>
        </SOME_DATA>
        <SOME_DATA>
            <ID_ATTRIBUTE>REF</ID_ATTRIBUTE>
            <ATTRIBUTE_DATA>54</ATTRIBUTE_DATA>
        </SOME_DATA>
        <STATUS>Not_Reviewed</STATUS>
        <FINDING_DETAILS>
        </FINDING_DETAILS>
        <COMMENTS>yak yak yak...</COMMENTS>
    </ID>
    <ID>
        <SOME_DATA>
            <ID_ATTRIBUTE>ID_Num</ID_ATTRIBUTE>
            <ATTRIBUTE_DATA>124</ATTRIBUTE_DATA>
        </SOME_DATA>
        <SOME_DATA>
            <ID_ATTRIBUTE>REF</ID_ATTRIBUTE>
            <ATTRIBUTE_DATA>145</ATTRIBUTE_DATA>
        </SOME_DATA>
        <STATUS>Not_Reviewed</STATUS>
        <FINDING_DETAILS>
        </FINDING_DETAILS>
        <COMMENTS/>
    </ID>
</CHECKLIST>

答案 1 :(得分:0)

您可以使用如下变量更新COMMENTS节点的值:

declare @x xml = '<CHECKLIST>
  <ID>
    <SOME_DATA>
        <ID_ATTRIBUTE>ID_Num</ID_ATTRIBUTE>
        <ATTRIBUTE_DATA>123</ATTRIBUTE_DATA>
    </SOME_DATA>
    <SOME_DATA>
        <ID_ATTRIBUTE>REF</ID_ATTRIBUTE>
        <ATTRIBUTE_DATA>54</ATTRIBUTE_DATA>
    </SOME_DATA>
    <STATUS>Not_Reviewed</STATUS>
    <FINDING_DETAILS></FINDING_DETAILS>
    <COMMENTS></COMMENTS>
  </ID>
  <ID>
    <SOME_DATA>
        <ID_ATTRIBUTE>ID_Num</ID_ATTRIBUTE>
        <ATTRIBUTE_DATA>124</ATTRIBUTE_DATA>
    </SOME_DATA>
    <SOME_DATA>
        <ID_ATTRIBUTE>REF</ID_ATTRIBUTE>
        <ATTRIBUTE_DATA>145</ATTRIBUTE_DATA>
    </SOME_DATA>
    <STATUS>Not_Reviewed</STATUS>
    <FINDING_DETAILS></FINDING_DETAILS>
    <COMMENTS></COMMENTS>
  </ID>
  </CHECKLIST>';



declare @AttributeData int = 123;
declare @Comments varchar(100) = 'yak yak yak...';

set @x.modify('insert text{sql:variable("@Comments")} into (/CHECKLIST/ID/SOME_DATA[ID_ATTRIBUTE = "ID_Num"][ATTRIBUTE_DATA = sql:variable("@AttributeData")]/../COMMENTS)[1]');

select @x;

至于将磁盘中的xml数据读入变量,可能不建议在t-sql中进行,但我偶尔会使用它:

declare @x xml;

set @x = (
    select * from openrowset(bulk 'C:\temp\yak.xml', single_blob
) as d;

有关此处的更多信息:https://msdn.microsoft.com/en-us/library/ms191184.aspx

将xml变量写入文件也是我可能在其他地方执行的任务(SSIS,控制台应用程序等),但它可以在t-sql中使用:

create table dbo.xStage (x xml);

insert into dbo.xStage(x)
    select @x;

declare @cmd varchar(max),
        @fileName varchar(max)

set @fileName = 'c:\temp\myXML.xml'

set @cmd = 'bcp "select x from YourDB.dbo.xStage" queryout ' + @fileName + ' -w -T -S' + @@servername

execute master..xp_cmdshell @cmd;

有关使用bcp在此处导出xml的更多信息:https://sqlsouth.wordpress.com/2014/05/23/export-xml-from-sql-server-using-bcp/