VBA 格式化输出XML(UTF-8无BOM编码)

来源:互联网 发布:淘宝图片美工软件 编辑:程序博客网 时间:2024/05/22 02:12

VBA可以使用MSXML2.Document来创建XML Dom树并输出到文件,先看个简单的例子:

Function CreateXml(xmlFile As String)    Dim xDoc As Object    Dim rootNode As Object    Dim header As Object    Dim newNode As Object    Dim tNode As Object    Set xDoc = CreateObject("MSXML2.DOMDocument")    Set rootNode = xDoc.createElement("BookList")    Set xDoc.DocumentElement = rootNode    'xDoc.Load xmlFile    Set header = xDoc.createProcessingInstruction("xml", "version='1.0' encoding='Unicode'")    xDoc.InsertBefore header, xDoc.ChildNodes(0)    Set newNode = xDoc.createElement("book")    Set tNode = xDoc.DocumentElement.appendChild(newNode)    tNode.setAttribute "type", "program"    Set newNode = xDoc.createElement("name")    Set tNode = xDoc.DocumentElement.ChildNodes.Item(0).appendChild(newNode)    tNode.appendChild (xDoc.createTextNode("Thinking in Java"))    Set newNode = xDoc.createElement("author")    Set tNode = xDoc.DocumentElement.ChildNodes.Item(0).appendChild(newNode)    tNode.appendChild (xDoc.createTextNode("Bruce Eckel"))    Set newNode = xDoc.createElement("book")    Set tNode = xDoc.DocumentElement.appendChild(newNode)    tNode.setAttribute "type", "literature"    Set newNode = xDoc.createElement("name")    Set tNode = xDoc.DocumentElement.ChildNodes.Item(1).appendChild(newNode)    tNode.appendChild (xDoc.createTextNode("边城"))    Set newNode = xDoc.createElement("author")    Set tNode = xDoc.DocumentElement.ChildNodes.Item(1).appendChild(newNode)    tNode.appendChild (xDoc.createTextNode("沈从文"))    Set newNode = Nothing    Set tNode = Nothing    xDoc.save xmlFileEnd Function

在宏工程中调用一下这个函数工程,就可以生成一个xml文件,但是生成的xml文件所有内容都显示在一行上了,有没有方法进行换行及缩进,让xml文件看起来更整齐美观呢?方法是有的,借助Msxml2.SAXXMLReader和Msxml2.MXXMLWriter就可以实现这个效果,看代码:

'格式化xml,带换行缩进Function PrettyPrintXml(xmldoc) As String    Dim reader As Object    Dim writer As Object    Set reader = CreateObject("Msxml2.SAXXMLReader.6.0")    Set writer = CreateObject("Msxml2.MXXMLWriter.6.0")    writer.indent = True    writer.omitXMLDeclaration = True    reader.contentHandler = writer    reader.Parse (xmldoc)    PrettyPrintXml = writer.OutputEnd Function

然后将前面的xDoc.save xmlFile改一下:

'xDoc.save xmlFileDim xmlStr As StringxmlStr = PrettyPrintXml(xDoc)WriteUtf8WithoutBom xmlFile, xmlStrOpen xmlFile For Output As #1Print #1, xmlStrClose #1

这样就可以格式化输出xml文件了。还有一个问题,我们想要指定xml文件的编码格式,如UTF-8,GB2312等,我通常习惯保存成UTF-8格式,那么该如何设置呢?查找资料,可以用ADODB.stream来搞。

Function WriteWithUtf8(filename As String, content As String)    Dim stream As New ADODB.stream    stream.Open    stream.Type = adTypeText    stream.Charset = "utf-8"    stream.WriteText content    stream.SaveToFile filename, adSaveCreateOverWrite    stream.Flush    stream.CloseEnd Function

细心点的话会发现用上面的方法实际上输出的文件格式是带BOM的UTF-8,它跟UTF-8无BOM的区别在哪呢?用UltraEdit工具来看十六进制码,会发现前者在开头多了三个字节:0xEF,0xBB,0xBF,想保存成UTF-8无BOM,把这三个字节去掉不就行了,实现如下:

' utf8无BOM编码格式Function WriteUtf8WithoutBom(filename As String, content As String)    Dim stream As New ADODB.stream    stream.Open    stream.Type = adTypeText    stream.Charset = "utf-8"    stream.WriteText "<?xml version=" & Chr(34) & "1.0" & Chr(34) & _                     " encoding=" & Chr(34) & "UTF-8" & Chr(34) & "?>" & vbCrLf    stream.WriteText content    '移除前三个字节(0xEF,0xBB,0xBF)    stream.Position = 3    Dim newStream As New ADODB.stream    newStream.Type = adTypeBinary    newStream.Mode = adModeReadWrite    newStream.Open    stream.CopyTo newStream    stream.Flush    stream.Close    newStream.SaveToFile filename, adSaveCreateOverWrite    newStream.Flush    newStream.CloseEnd Function

注意需要引用两个库:Microsoft ADO Ext. 6.0 for DDL and Security,Microsoft ActiveX Data Objects 2.7 Library

最后附上完整代码:

Sub 按钮2_Click()    Dim xmlFile As String    xmlFile = "D:\test\books.xml"    CreateXml xmlFileEnd SubFunction CreateXml(xmlFile As String)    Dim xDoc As Object    Dim rootNode As Object    Dim header As Object    Dim newNode As Object    Dim tNode As Object    Set xDoc = CreateObject("MSXML2.DOMDocument")    Set rootNode = xDoc.createElement("BookList")    Set xDoc.DocumentElement = rootNode    'xDoc.Load xmlFile    Set header = xDoc.createProcessingInstruction("xml", "version='1.0' encoding='Unicode'")    xDoc.InsertBefore header, xDoc.ChildNodes(0)    Set newNode = xDoc.createElement("book")    Set tNode = xDoc.DocumentElement.appendChild(newNode)    tNode.setAttribute "type", "program"    Set newNode = xDoc.createElement("name")    Set tNode = xDoc.DocumentElement.ChildNodes.Item(0).appendChild(newNode)    tNode.appendChild (xDoc.createTextNode("Thinking in Java"))    Set newNode = xDoc.createElement("author")    Set tNode = xDoc.DocumentElement.ChildNodes.Item(0).appendChild(newNode)    tNode.appendChild (xDoc.createTextNode("Bruce Eckel"))    Set newNode = xDoc.createElement("book")    Set tNode = xDoc.DocumentElement.appendChild(newNode)    tNode.setAttribute "type", "literature"    Set newNode = xDoc.createElement("name")    Set tNode = xDoc.DocumentElement.ChildNodes.Item(1).appendChild(newNode)    tNode.appendChild (xDoc.createTextNode("边城"))    Set newNode = xDoc.createElement("author")    Set tNode = xDoc.DocumentElement.ChildNodes.Item(1).appendChild(newNode)    tNode.appendChild (xDoc.createTextNode("沈从文"))    Set newNode = Nothing    Set tNode = Nothing    Dim xmlStr As String    xmlStr = PrettyPrintXml(xDoc)    WriteUtf8WithoutBom xmlFile, xmlStr    Set rootNode = Nothing    Set xDoc = Nothing    MsgBox xmlFile & "输出完成"End Function'格式化xml,带换行缩进Function PrettyPrintXml(xmldoc) As String    Dim reader As Object    Dim writer As Object    Set reader = CreateObject("Msxml2.SAXXMLReader.6.0")    Set writer = CreateObject("Msxml2.MXXMLWriter.6.0")    writer.indent = True    writer.omitXMLDeclaration = True    reader.contentHandler = writer    reader.Parse (xmldoc)    PrettyPrintXml = writer.OutputEnd Function' utf8无BOM编码格式Function WriteUtf8WithoutBom(filename As String, content As String)    Dim stream As New ADODB.stream    stream.Open    stream.Type = adTypeText    stream.Charset = "utf-8"    stream.WriteText "<?xml version=" & Chr(34) & "1.0" & Chr(34) & _                     " encoding=" & Chr(34) & "UTF-8" & Chr(34) & "?>" & vbCrLf    stream.WriteText content    '移除前三个字节(0xEF,0xBB,0xBF)    stream.Position = 3    Dim newStream As New ADODB.stream    newStream.Type = adTypeBinary    newStream.Mode = adModeReadWrite    newStream.Open    stream.CopyTo newStream    stream.Flush    stream.Close    newStream.SaveToFile filename, adSaveCreateOverWrite    newStream.Flush    newStream.Close    End Function
1 0