xml - 如何在 MSXML - VBA 中获取 XML 元素的数组索引?

标签 xml vba excel

我需要将 XML 文件转换为 Excel。所以我想检索 XML 作为名称值对并唯一地命名列。有什么方法可以获取节点的 XML 数组索引吗?下面是我想知道 productInfo 字段索引的示例 XML。

<productInfoRequest>
    <CheckIn>false</CheckIn>
    <timeStamp>2016-11-02T15:49:57.337-05:00</timeStamp>
    <foodoInfo>
        <Country>USA</Country>
        <Currency>USD</Currency>
    </foodoInfo>
    <productInfo>
        <itemNo>1</itemNo>
        <itemName>Sample</itemName>
    </productInfo>
    <productInfo>
        <itemNo>2</itemNo>
        <itemName>Sample</itemName>
    </productInfo>
    <productInfo>
        <itemNo>3</itemNo>
        <itemName>Sample</itemName>
    </productInfo>
    <productInfo>
        <itemNo>4</itemNo>
        <itemName>Sample</itemName>
    </productInfo>
</productInfoRequest>

Desired Output

请注意,这只是我给出的示例请求 xml。任何给定的 XML 都应转换为唯一的键值对键并加载到 excel 中

示例代码片段:

Sub GenKeyValues()

    Dim xmlDoc As MSXML2.DOMDocument60
    Dim xmlNodes As MSXML2.IXMLDOMNodeList
    Dim xNode As MSXML2.IXMLDOMNode
    Dim cNode As MSXML2.IXMLDOMNode
    Dim ccNode As MSXML2.IXMLDOMNode
    Dim KeyNo As Variant
    Dim dic

    Set dic = CreateObject("Scripting.Dictionary")

    Dim CurrVal
    Dim Cnt As Integer

    CurrVal = <<<<<Im reading the XML from the file to a string from another method>>>>>
    Set xmlDoc = CreateObject("MSXML2.DOMDocument.6.0")
    With xmlDoc
        .async = False
        .validateOnParse = True
        .LoadXML CurrVal
    End With

    Set xmlNodes = xmlDoc.ChildNodes

    cnt = 0

    For Each xNode In xmlNodes

        If xNode.HasChildNodes Then
             For Each cNode In xNode.ChildNodes
                 If cNode.ChildNodes.Length > 1 Then
                     cnt = cnt + 1
                          For Each ccNode In cNode.ChildNodes
                              Key = ccNode.ParentNode.BaseName + CStr(cnt) + "_" + ccNode.BaseName
                              Val = ccNode.nodeTypedValue
                              dic.Add Key, Val
                          Next
                 Else
                    Key = cNode.BaseName
                    Val = cNode.nodeTypedValue
                    dic.Add Key, Val
                 End If
             Next
       End If
    Next

    For Each KeyNo In dic.Keys
       MsgBox ("Key: " & KeyNo & " Value: " & dic(KeyNo))
    Next

End Sub

我已检索以下 key :
foodoInfo0_Country
foodoInfo0_Currency
productInfo0_itemNo
productInfo0_itemName
productInfo1_itemNo
productInfo1_itemName
productInfo2_itemNo

productInfo2_itemName

最佳答案

考虑XSLT ,一种专用语言,旨在将 XML 文件转换为最终用途格式,包括其他 XML 文件、HTML 文件,甚至文本文件。在这里,XSLT 可以将您的结构转换为带有所需标题和数据行的 CSV 格式。 MSXML 可以运行 XSLT 1.0 脚本,避免嵌套 forif逻辑和数组或字典的使用。

XSLT (另存为 .xsl 文件以在 VBA 中读取;注意:XSL 脚本是 XML 文件)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="text" indent="yes"/> 
   <xsl:strip-space elements="*"/>

   <xsl:template match="/productInfoRequest">      
      <xsl:call-template name="rows">
        <xsl:with-param name="data" select="foodoInfo|productInfo"/>
      </xsl:call-template>   
   </xsl:template>

   <xsl:template name="rows">
      <xsl:param name="data"/>

      <!-- HEADERS -->
      <xsl:for-each select="$data">
        <xsl:value-of select="concat(name(), position(), '_', name(*[1]))"/>
        <xsl:text>,</xsl:text>
        <xsl:value-of select="concat(name(), position(), '_', name(*[2]))"/>        
        <xsl:if test="position() != last()"><xsl:text>,</xsl:text></xsl:if>
      </xsl:for-each>

      <xsl:text>&#xa;</xsl:text>

      <!-- DATA -->
      <xsl:for-each select="$data">
        <xsl:value-of select="concat(node()[1], ',', node()[2])"/>
        <xsl:if test="position() != last()"><xsl:text>,</xsl:text></xsl:if>
      </xsl:for-each>
   </xsl:template>

</xsl:stylesheet>

VBA

Public Sub RunXSLTtoCSV()
    Dim xmlDoc As New MSXML2.DOMDocument60, xslDoc As New MSXML2.DOMDocument60
    Dim txtOutput As String, csvfile As String

    ' LOAD XML AND XSL
    xmlDoc.LoadXML CurrVal
    xmlDoc.async = False
    xslDoc.Load "C:\Path\To\XSLScript.xsl"
    xslDoc.async = False

    ' TRANSFORM TO TEXT
    txtOutput = xmlDoc.transformNode(xslDoc)

    ' SAVE TO CSV
    csvfile = "C:\Path\To\CSV.csv"
    Open csvfile For Output As #1
        Print #1, txtOutput
    Close #1

    Set xslDoc = Nothing
    Set xmlDoc = Nothing
End Sub

CSV 输出

当然这是一个 csv 文件,而不是 Excel 工作簿。因此,将内容保存或加载到工作簿中。

CSV Output Screenshot

关于xml - 如何在 MSXML - VBA 中获取 XML 元素的数组索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43192810/

相关文章:

vba - 未输入 VBA 密码宏/VBA 无法运行

vba - 多次动态复制工作表并在 Excel 中使用 VBA 重命名

c# - 在 C# 函数中设置 Excel 单元格的公式

Excel 字符串连接使用“分隔符

c# - 在 C# 中使用 Regex 提取 XML 值

xml - 如何在 XSD 中指定选项列表

excel - 在 VBA Excel 2003 中迭代 800 行的 for 循环需要花费太多时间才能获得所需的输出?如何克服这个问题?

vba - 删除子字符串但保留格式

xml - Haskell:使用 XML.Light 查找元素

c# - ArgumentException:C# 中的 'Illegal characters in path'