【问题标题】:How to I read and modify an XML file through VBA?如何通过 VBA 读取和修改 XML 文件?
【发布时间】:2019-01-25 13:18:24
【问题描述】:

我已经超过 15 年没有编写任何程序了,但在过去的一个月里,我为我创建了一个别人想要使用的 Excel VBA 东西。我希望做一些事情来验证他们的许可证仍然有效。我在想它可以引用一个 XML 文件来查看许可证是否仍然有效,并且可能会向 XML 文件写入一些东西,所以我知道他们使用了它。

这是我的 XML 文件(当然它会长得多,但这涵盖了它)。我的目标是在客户付款时更新 XML 文件。请注意文件如何显示“八月”。到了九月,程序将无法运行,因为我输入的代码与 VBA 文件中的九月代码不匹配。一旦他们付款,我将更新 XML 文件中的代码,然后当他们运行该文件时,它就会工作。

我可以得到它把整个XML文件放在一个消息框中,但我不知道如何搜索机构名称然后抓取月份和代码来验证。我想我希望 VBA 宏读取 XML 文件,搜索机构名称 2(例如),当它找到机构名称 2 时,获取日期和代码。验证此日期和代码是否与 VBA 文件中的预期匹配,然后它将允许其余的 subs 运行。同时,我希望它在 XML 文件中放回日期、时间和其他一些内容,以便查看他们最后一次使用它的时间。

我知道这不是很好的安全措施,因为如果他们可以通过密码,他们可以更改脚本来避免这种情况,但这是有问题的。

下面是 XML,下面是我的 sub,用于获取 XML 内部内容的 msgbox,但我不知道如何搜索或写下我在上面考虑的内容。请给我一些建议。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<data-set xmlns:xsi="www.example.com /2001/XMLSchema-instance">
<record>
  <Agency>Agency Name 1</Agency>
  <Date>August</Date>
  <Code>code to give</Code>
</record>
<record>
  <Agency>Agency Name 2</Agency>
  <Date>August</Date>
  <Code>code to give</Code>
</record>
</data-set>

Dim xmlhttp As Object
Dim myUrl As String

Set xmlhttp = CreateObject("MSXML2.serverXMLHTTP")

myUrl = "www.example.com/myfile.xml"
xmlhttp.Open "Get", myUrl, False
xmlhttp.send

MsgBox (xmlhttp.responsetext)

【问题讨论】:

    标签: xml vba


    【解决方案1】:

    以下是一些示例代码和一些有用的链接,它们可能会对您有所帮助。我强烈建议单步执行代码并随着代码的进行查看每个对象的状态。

    此外,根据评论中的建议,您需要添加对 MSXML2 库的引用。在 VBA 开发窗口中,单击工具菜单和参考...(工具->参考)。出现引用对话框。向下滚动,直到找到 Microsoft XML, v6.0 选中复选框以添加它,单击确定按钮,您就可以参加比赛了。

    一些有用的链接

    WC3 Schools XML DOM Tutorial

    Microsoft IXMLDOMText Object Members

        Declare and set your URL
        Dim myUrl As String: myUrl = "www.example.com/myfile.xml"
    
        'Declare your xmlHTTP stream
        'I prefer early binding rather than late binding
        Dim xmlHTTP As MSXML2.ServerXMLHTTP60
        xmlHTTP.Open "Get", myUrl, False
        xmlHTTP.send
    
       'Use reponseXML rather than responseText
       'This way you get an XML DOM, rather than a string of text
       'Declare XML DOM Document
        Dim xmlDOMDoc As MSXML2.DOMDocument60
        Set xmlDoc = xmlHTTP.responseXML
    
        'Declare a rootNode as an XML DOM element
        Dim rootNode As MSXML2.IXMLDOMElement
    
        'Set the root node to the xmlDocumet (your HTTP stream)
        'to the top document element
        'In your case Root Node is data-set
        Set rootNode = xmlDoc.DocumentElement
    
        'Declare the Root Nodes children.
        'In your case they are XML Element nodes
        'with the name record
        Dim xmlRootChildNode As MSXML2.IXMLDOMElement
    
        'Your nodes of Root Children are Text Nodes
        'in your example the names are Agency, Date and Code
        Dim xmlChildrenOfRootChildNode As MSXML2.IXMLDOMElement
    
        'Declare a string array to hold the text in your Text Nodes
        Dim tnText(3) As String
        Dim tnDictionary As Scripting.Dictionary
        Dim nDx As Integer
    
        'Loop through the Roots children
        For Each xmlRootChildNode In rootNode.ChildNodes
        'does the Root Child Node have children?
                If xmlRootChildNode.HasChildNodes Then
                    nDx = 0
                    'This code will add them to the array
                    For Each xmlChildrenOfRootChildNode In xmlRootChildNode.ChildNodes
                        tnText(nDx) = xmlChildrenOfRootChildNode.text
                    Next
                    'Or if you want to use a Dictionary
                    For Each xmlChildrenOfRootChildNode In xmlRootChildNode.ChildNodes
                        'This adds a record to a Dictionary.  It will contain
                        'The dictionary's key will be the nodeName aka tag (Agency, Date, Code)
                        'The dictionary's item will be the Text value stored between the xml tags
                        tnDictionary.Add xmlChildrenOfRootChildNode.nodeName, xmlChildrenOfRootChildNode.text
                    Next
            End If
        Next
    

    将回车符 (CR)、换行符 (LF) 和制表符添加到 XLM 输出文件以便您可以阅读是一项挑战。我没有在网上找到任何真正有帮助的东西。下面的代码将根据需要插入 CRLF 和尽可能多的制表符。

    用于指示方法在当前节点之后或之前添加空白的公共枚举:

    'Public Enumerator used by the XMLAddSpace function
    'This is an indicator telling the function
    'where the CRLF and tabs are being added
    Public Enum eAddBeforeAfter
        After = 1
        Before = 2
    End Enum
    

    XMLAddSpace 函数:

        '*****************************************************************************************
    '**                                                                                     **
    '** Sub XmlAddSpace adds Carriage Return (CR), and Line Feed (LF) and as many tab       **
    '**     characters specificed in tabCnt.  It used vbCrLf for the CR and LF value and    **
    '**     Chr(9) (ASCII Tab Character value 09) to set the ASCII tab character value.     **
    '**                                                                                     **
    '**     PARAMATERS:                                                                     **
    '**         xmlNode as IXMLDOMElement Is the Node that the white space will be added    **
    '**         after.                                                                      **
    '**         tabCnt is the number of tab characters you want to indent the next line by  **
    '**         BeforeAfter is an enum that directs the method to either add the white      **
    '**             before the xmlChildNode or after the xmlNode                            **
    '**         xmlChildNode is optional when selecting After but required when selecting   **
    '**             Before for adding white space before a node. White space is always      **
    '**             before a child node element                                             **
    '*****************************************************************************************
    Public Sub XmlAddSpace(ByRef xmlNode As MSXML2.IXMLDOMElement, ByVal tabCnt As Integer, _
                           ByVal BeforeAfter As eAddBeforeAfter, Optional ByRef xmlChildNode As MSXML2.IXMLDOMElement)
    
        'Declare the text node that will hold the white space text
        Dim nodeSpace As IXMLDOMText
        'Declare a variable to hold the white space text
        'We'll add the tab characters in the next few statements
        'Start by putting CRLF as the front of the text string
        Dim tabSpace As String: tabSpace = vbCrLf
    
        'Now add the tab character to the string after CRLF
        'this way the XML output has a new line follwed by 0 to n
        'number of tab characters causing it to indent
        If tabCnt > 0 Then
            Dim i As Integer
            For i = 1 To tabCnt
                tabSpace = tabSpace & Chr(9)
            Next
        End If
    
        'Now add the white space to the text node.
        If BeforeAfter = After Then
            'After puts white space after the current node
            'This is useful for putting CRLF and indenting
            'a parent node's closing tag
            Set nodeSpace = xmlNode.OwnerDocument.createTextNode(tabSpace)
            xmlNode.appendChild nodeSpace
        Else
            'Before puts white space before the current node
            'This is useful for putting CRLF and indenting
            'a new child from either a parent node or a sibling node
            xmlNode.InsertBefore xmlChildNode.OwnerDocument.createTextNode(tabSpace), xmlChildNode
            xmlNode.appendChild xmlChildNode
        End If
    End Sub
    

    要使用方法你需要调用它如下:

    在前面添加:XmlAddSpace parentNode, 2, Before 之后添加:XmlAddSpace parentNode, 2, After, childNode

    注意父节点和子节点都必须是 MSXML2.IXMLDOMElement 类型

    【讨论】:

    • 杰米,太棒了。谢谢你。我已经有 15 年没有做过任何编程了,所以当我回到 VBA 时,感觉很熟悉,我马上就恢复了它,但是使用 XML 对我来说就像流利地使用 3 种基于拉丁语的语言然后被给予一些克林贡语的东西,并被告知只用几个例子翻译它。你真的为我打破了它,现在它更有意义了。我一直在寻找有关 XML 和 DOM 的说明和示例,但我发现的一切都非常有限。这肯定更有意义。
    • @GaryC 我刚刚修复了上面代码中的一个错误。子节点可能都应该声明为 IXMLDOMElement 而不是 IXMLDOMText。当您开始编写 XML 输出时,您会注意到 XML 文件没有格式。这只是单行。您不能直接将 CR/LF 或 Tab 插入流中。您必须创建一个文本节点。我在前面的示例下方添加了我的空白代码
    • 当您引用 XML 库时,您还应该显示在哪里设置对它的引用。
    • Jamie 我“赞成”但因为我的分数低于 15 分,所以显然意义不大。你的答案肯定解释了为什么事情是这样的。谢谢你。我想了解更多关于 XML 以及如何在 VBA 中使用它的信息。有些是指 MSXML2.DOMDocument60、MicrosoftXMLDOM 和您的 serverXMLHTTP60。我不明白有什么区别或为什么有区别。我查看了您的链接,虽然内容丰富,但我可以“使用”它,但我仍然不“理解”它。使用 VBA 和 VB.Net,我可以阅读代码,这一切都说得通,但对于引用 XML 的代码就没有那么多了。我可以从哪里获得更多示例和解释?
    • @GaryC 感谢您的支持。虽然 MSXML2 和 MSXML 之间存在许多技术差异,但主要区别在于 MSXML 是 Microsoft XML 到 2.5 版的实现。 MSXML 是通过 6.0 SP3 版实现的 Microsoft XML。这是stack overflow article的链接。
    猜你喜欢
    • 2018-07-29
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-18
    • 2013-05-04
    相关资源
    最近更新 更多