一点背景,这是我的第一篇文章,但我从这个网站得到了很多解决方案。如果这是一个重新发布,我道歉,但我还没有找到一个好的解决方案,并且很难从其他地方拼凑出来以获得我想要的东西。
我已经找到了一些关于从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 不鼓励。
答案 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/