使用vba将XML转换为CSV

时间:2018-02-09 07:13:06

标签: xml excel vba excel-vba xml-parsing

我有20个带XML的文件,它包含如下数据:

<?xml version="1.0" encoding="UTF-8"?>
<measCollecFile xmlns="http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec">
<fileHeader fileFormatVersion="32.435 V10.0" vendorName="Nokia Networks">
<fileSender elementType="LNBTS"/>
<measCollec beginTime="2018-01-17T00:00:00+00:00"/>
</fileHeader>
<measData>
<managedElement/>
<measInfo measInfoId="LTE_Cell_Load">
<granPeriod endTime="2018-01-17T00:15:00+00:00" duration="PT900S"/>
<measTypes>M8001C0 M8001C1 M8001C10 M8001C100 M8001C101 M8001C102 M8001C103 M8001C104 M8001C105 M8001C106 M8001C107 M8001C108 M8001C109 M8001C11 M8001C110 M8001C111 M8001C112 M8001C113 M8001C114 M8001C115 M8001C116 M8001C117 M8001C118 M8001C119 M8001C12 M8001C120 M8001C121 M8001C122 M8001C123 M8001C124 M8001C125 M8001C126 M8001C127 M8001C128 M8001C129 M8001C13 M8001C130 M8001C131 M8001C132 M8001C133 M8001C135 M8001C136 M8001C137 M8001C138 M8001C139 M8001C14 M8001C140 M8001C141 M8001C142 M8001C143 M8001C144 M8001C145 M8001C146 M8001C149 M8001C15 M8001C152 M8001C153 M8001C154 M8001C155 M8001C156 M8001C157 M8001C158 M8001C159 M8001C16 M8001C160 M8001C161 M8001C162 M8001C163 M8001C164 M8001C165 M8001C166 M8001C167 M8001C168 M8001C169 M8001C17 M8001C170 M8001C171 M8001C172 M8001C173 M8001C174 M8001C175 M8001C176 M8001C177 M8001C178 M8001C179 M8001C18 M8001C180 M8001C181 M8001C182 M8001C183 M8001C184 M8001C185 M8001C186 M8001C187 M8001C188 M8001C189 M8001C19 M8001C190 M8001C191 M8001C192 M8001C193 M8001C194 M8001C195 M8001C196 M8001C197 M8001C2 M8001C20 M8001C202 M8001C203 M8001C204 M8001C205 M8001C206 M8001C207 M8001C208 M8001C209 M8001C21 M8001C210 M8001C211 M8001C212 M8001C213 M8001C214 M8001C215 M8001C216 M8001C217 M8001C218 M8001C219 M8001C22 M8001C220 M8001C222 M8001C23 M8001C231 M8001C232 M8001C233 M8001C24 M8001C25 M8001C26 M8001C269 M8001C27 M8001C270 M8001C271 M8001C272 M8001C273 M8001C274 M8001C275 M8001C276 M8001C277 M8001C278 M8001C279 M8001C28 M8001C280 M8001C281 M8001C286 M8001C29 M8001C291 M8001C292 M8001C293 M8001C294 M8001C299 M8001C3 M8001C30 M8001C300 M8001C305 M8001C306 M8001C307 M8001C308 M8001C309 M8001C31 M8001C310 M8001C311 M8001C312 M8001C313 M8001C314 M8001C315 M8001C316 M8001C317 M8001C32 M8001C323 M8001C324 M8001C325 M8001C326 M8001C33 M8001C34 M8001C35 M8001C36 M8001C37 M8001C38 M8001C39 M8001C4 M8001C40 M8001C41 M8001C42 M8001C421 M8001C422 M8001C423 M8001C424 M8001C425 M8001C426 M8001C427 M8001C428 M8001C429 M8001C43 M8001C430 M8001C431 M8001C432 M8001C433 M8001C434 M8001C435 M8001C436 M8001C437 M8001C438 M8001C439 M8001C44 M8001C440 M8001C441 M8001C442 M8001C443 M8001C444 M8001C445 M8001C446 M8001C447 M8001C448 M8001C449 M8001C45 M8001C450 M8001C451 M8001C452 M8001C453 M8001C454 M8001C455 M8001C456 M8001C457 M8001C458 M8001C459 M8001C46 M8001C460 M8001C461 M8001C462 M8001C463 M8001C464 M8001C465 M8001C466 M8001C467 M8001C468 M8001C469 M8001C47 M8001C470 M8001C471 M8001C472 M8001C473 M8001C474 M8001C475 M8001C476 M8001C477 M8001C478 M8001C479 M8001C48 M8001C480 M8001C481 M8001C482 M8001C483 M8001C484 M8001C485 M8001C486 M8001C487 M8001C488 M8001C49 M8001C5 M8001C50 M8001C51 M8001C52 M8001C53 M8001C54 M8001C55 M8001C56 M8001C57 M8001C58 M8001C59 M8001C6 M8001C60 M8001C61 M8001C62 M8001C63 M8001C64 M8001C65 M8001C66 M8001C67 M8001C68 M8001C69 M8001C7 M8001C70 M8001C71 M8001C72 M8001C73 M8001C74 M8001C75 M8001C76 M8001C77 M8001C78 M8001C79 M8001C8 M8001C80 M8001C81 M8001C82 M8001C83 M8001C84 M8001C85 M8001C86 M8001C87 M8001C88 M8001C89 M8001C9 M8001C90 M8001C91 M8001C92 M8001C93 M8001C94 M8001C95 M8001C96 M8001C97 M8001C98 M8001C99</measTypes>
<measValue measObjLdn="PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4,PLMN-PLMN/MCC-310/MNC-090">
<measResults>0 0 90000 0 0 0 0 0 0 0 0 0 0 56250 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 12 146250 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</measResults>
</measValue>
</measInfo>
<fileFooter>
<measCollec endTime="2018-01-17T00:15:00+00:00"/>
</fileFooter>
</measCollecFile>

我正在Excel中寻找输出:

| Day        | Time  | DN                                    | Measure Info  | Counter   | Value |    
|------------|-------|---------------------------------------|---------------|-----------|-------|
| 1/17/2018  | 15:00 | PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4 | LTE_Cell_Load | M8001C0   | 0     |
| 1/17/2018  | 15:00 | PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4 | LTE_Cell_Load | M8001C1   | 0     |
| 1/17/2018  | 15:00 | PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4 | LTE_Cell_Load | M8001C10  | 9000  |
| 1/17/2018  | 15:00 | PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4 | LTE_Cell_Load | M8001C100 | 0     |

将有6列 日:来自格兰特时期 时间:来自格兰特时期 DN:来自measValue measObjLdn 测量信息:

每个计数器在measResult表中都有对应的值。如果值不存在则为0。显然,measTypes和相应的measValues中会有更多的项目

每个XML包含1到20套measInfo measInfoId 并且有20多张供我转换。

根据多个选定的XML文件查找单个csv。所有XML都具有相同的结构。

期待您的支持。

1 个答案:

答案 0 :(得分:2)

考虑XSLT(兄弟对XPath),这是专门用于转换XML文件的语言,包括转换为CSV等文本文件。使用VBA MSXML,您可以在没有任何For循环或If逻辑的情况下运行XSLT 1.0脚本。

首先,您需要将所有20个XML文件附加到一个主XML文件中,该文件需要使用XSLT的document()函数才能输出单个主CSV。然后,您需要通过空格分隔符拆分 measType measResults 文本,这需要递归模板调用,例如@DimitreNovatchev's answer。然后使用XPath ancestor::*following-sibling::*在不同位置绑定指标值 date time 等。

XSLT - XML附加(另存为.xsl文件 - 一个特殊的.xml文件)

将所有XML保存在同一目录中。将document()中的文档名称更改为实际值,并确保省略第一个XML。假设所有XML都具有相同的默认命名空间:http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:doc="http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

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

  <xsl:template match="doc:measData">
    <xsl:copy><xsl:apply-templates select="*"/></xsl:copy>
    <xsl:copy-of select="document('XML_2.xml')/doc:measCollecFile/doc:measData"/>
    <xsl:copy-of select="document('XML_3.xml')/doc:measCollecFile/doc:measData"/>
    <xsl:copy-of select="document('XML_4.xml')/doc:measCollecFile/doc:measData"/>
    <xsl:copy-of select="document('XML_5.xml')/doc:measCollecFile/doc:measData"/>
    ...
  </xsl:template>

</xsl:stylesheet>

XSLT - CSV转换(另存为.xsl文件)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:doc="http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec">
  <xsl:output indent="yes" method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:param name="delimiter">,</xsl:param>

  <xsl:template match="/doc:measCollecFile">
      <xsl:text>date,time,DN,Measure Info,Counter,Value&#xa;</xsl:text>
      <xsl:apply-templates select="doc:measData"/>
  </xsl:template>

  <xsl:template match="doc:measData">
    <xsl:apply-templates select="doc:measInfo"/>
  </xsl:template>

  <xsl:template match="doc:measInfo">
    <xsl:apply-templates select="doc:measTypes"/>
  </xsl:template>

 <xsl:template match="doc:measTypes" name="split">
    <xsl:param name="dateTime" select="ancestor::doc:measInfo/doc:granPeriod/@endTime"/>
    <xsl:param name="date" select="substring($dateTime,1,10)"/>
    <xsl:param name="time" select="substring($dateTime,16,20)"/>
    <xsl:param name="dn" select="substring-before(following-sibling::doc:measValue/@measObjLdn, ',')"/>
    <xsl:param name="info" select="ancestor::doc:measInfo/@measInfoId"/>

    <xsl:param name="pText" select="."/>
    <xsl:param name="vText" select="following-sibling::doc:measValue/doc:measResults"/>
    <xsl:if test="string-length($pText)">
         <xsl:value-of select="concat($date, $delimiter, $time, $delimiter, $dn,  $delimiter, $info, $delimiter, 
                                      substring-before(concat($pText,' '),' '), $delimiter, substring-before(concat($vText,' '),' '))"/>
         <xsl:text>&#xa;</xsl:text>                                   
         <xsl:call-template name="split">
            <xsl:with-param name="pText" select="substring-after($pText, ' ')"/>
            <xsl:with-param name="vText" select="substring-after($vText, ' ')"/>
         </xsl:call-template>
    </xsl:if>
 </xsl:template>

</xsl:stylesheet>

VBA

由两个宏组成:在Append_XML()中加载第一个XML,在CSV_Convert()中使用生成的Master.xml。

Sub Append_XML()
   ' REFERENCE Microsoft XML, v##
    Dim xmlDoc As New MSXML2.DOMDocument, xslDoc As New MSXML2.DOMDocument, newDoc As New MSXML2.DOMDocument

    ' LOAD XML AND XSL FILES
    xslDoc.async = False
    xmlDoc.Load "C:\Path\To\XML_1.xml"

    xslDoc.async = False
    xslDoc.Load "C:\Path\To\Append_XSLT_Script.xsl"

    ' TRANSFORM XML
    xmlDoc.transformNodeToObject xslDoc, newDoc

    ' SAVE XML
    newDoc.Save "C:\Path\To\Master.xml"

    MsgBox "Successfully appended XMLs together!", vbInformation

    Set xmlDoc = Nothing: Set xslDoc = Nothing: Set newDoc = Nothing

End Sub


Sub CSV_Convert()
    Dim xmlDoc As New MSXML2.DOMDocument, xslDoc As New MSXML2.DOMDocument
    Dim xmlstr As String, lastRow As Long
    Dim fso As Object, oFile As Object

    ' LOAD XML AND XSL FILES
    xslDoc.async = False
    xmlDoc.Load "C:\Path\To\Master.xml"

    xslDoc.async = False
    xslDoc.Load "C:\Path\To\CSV_Conversion_XSLT_Script.xsl"

    ' TRANSFORM XML
    xmlstr = xmlDoc.transformNode(xslDoc)

    ' SAVE CSV
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set oFile = fso.CreateTextFile("C:\Path\To\Final_Output.csv")

    oFile.WriteLine xmlstr
    oFile.Close

    MsgBox "Successfully converted XML to CSV!", vbInformation

    Set xmlDoc = Nothing: Set xslDoc = Nothing
    Set oFile = Nothing: Set fso = Nothing

End Sub

输出 (以上发布的321条记录,但使用Master.xml的内容更多)

' date,time,DN,Measure Info,Counter,Value
' 2018-01-17,5:00+00:00,PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4,LTE_Cell_Load,M8001C0,0
' 2018-01-17,5:00+00:00,PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4,LTE_Cell_Load,M8001C1,0
' 2018-01-17,5:00+00:00,PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4,LTE_Cell_Load,M8001C10,90000
' 2018-01-17,5:00+00:00,PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4,LTE_Cell_Load,M8001C100,0
' 2018-01-17,5:00+00:00,PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4,LTE_Cell_Load,M8001C101,0
' 2018-01-17,5:00+00:00,PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4,LTE_Cell_Load,M8001C102,0
' 2018-01-17,5:00+00:00,PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4,LTE_Cell_Load,M8001C103,0
' 2018-01-17,5:00+00:00,PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4,LTE_Cell_Load,M8001C104,0
' 2018-01-17,5:00+00:00,PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4,LTE_Cell_Load,M8001C105,0
' 2018-01-17,5:00+00:00,PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4,LTE_Cell_Load,M8001C106,0
' 2018-01-17,5:00+00:00,PLMN-PLMN/MRBTS-101/LNBTS-101/LNCEL-4,LTE_Cell_Load,M8001C107,0
' ...