Excel XML解析器为属性节点提供了太多新行

时间:2016-06-07 18:23:56

标签: xml excel excel-2010

我试图使用Excel读取一些XML数据,因此我最终可以将其全部保存到单个Excel / CSV文件中供以后使用,但我遇到了一些问题。 XML文件的读取由Excel的解析器读取。以下是数据的示例:

<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<data>
<header>
    <name>n</name>
    <version>v</version>
    <date>d</date>
</header>
<abcd>
    <attr1>val1</attr1>
    <attr2>val2</attr2>
    <attr3>val3</attr3>
    <efgh>
        <attr4>val4</attr4>
        <attr5>val5</attr5>
        <attr6>val6</attr6>
        <ijkl>
            <attr7>val7</attr7>
            <attr8>val8</attr8>
            <attr9>val9</attr9>
        </ijkl>
    </efgh>
    <attr10>val10</attr10>
    <attr11>val11</attr11>
    <attr12>val12</attr12>
</abcd>

Data > From Other Sources > From XML Data Import下的数据选项卡中找到的Excel XML解析器为我提供了输出:

name | version | date | attr1 | attr2 | attr3 | attr4 | attr5 | attr6
n      v         d      
                        val1    
                                val2    
                                        val3
                                                val4    val5    val6

但我希望输出为:

name | version | date | attr1 | attr2 | attr3 | attr4 | attr5 | attr6
n      v         d      val1    val2    val3    val4    val5    val6

或者,换句话说,我希望每个属性值都显示在同一行,直到<abcd>标记再次出现。有没有办法强制Excel解析器执行此操作?或者,使用excel公式或VBA后,是否可以轻松地清理数据?

1 个答案:

答案 0 :(得分:1)

XML是一种开放式树格式,它可以拥有与设计一样多的嵌套元素。但是,电子表格,数据集,数据库表格和其他平面结构是具有行和列的两个维度。因此,您需要将XML展平为每行一级的一个子/一个嵌套以进行正确的迁移:

<data>
  <row>
    <col>value</col>
    <col>value</col>
    <col>value</col>
  </row>
  <row>
    <col>value</col>
    <col>value</col>
    <col>value</col>
  </row>
</data>

使用VBA MSXML,您可以通过运行XSLT(旨在将XML文档转换为各种最终用途结构需求的专用语言)来展平。转换后,您可以使用Workbooks.OpenXML()将XML加载到Excel电子表格中。

XSLT 脚本(外部保存为.xsl以加载到VBA中)

<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:strip-space elements="*"/>

  <xsl:template match="data">
    <xsl:copy>            
      <xsl:apply-templates select="abcd"/>      
    </xsl:copy>
  </xsl:template>

  <xsl:template match="abcd">
    <row>
      <xsl:copy-of select="ancestor::data/header/*"/>
      <xsl:copy-of select="attr1|attr2|att3"/>
      <xsl:apply-templates select="efgh"/>
      <xsl:copy-of select="attr10|attr11|attr12"/>
    </row>
  </xsl:template>

  <xsl:template match="efgh">    
      <xsl:copy-of select="attr4|attr5|attr6"/>      
      <xsl:apply-templates select="ijkl"/>    
  </xsl:template>

  <xsl:template match="ijkl">    
      <xsl:copy-of select="*"/>
  </xsl:template>

</xsl:transform>

VBA

Public Sub RunXSLT()
    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 AND XSL DOCS '
    xmlDoc.Load "C:\Path\To\Input.xml"
    xmlDoc.async = False

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

    ' TRANSFORM SOURCE TO OUTPUT ' 
    xmlDoc.transformNodeToObject xslDoc, newDoc
    newDoc.Save "C:\Path\To\Output.xml"

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

    ' IMPORT OUTPUT INTO WORKBOOK ' 
    Workbooks.OpenXML "C:\Path\To\Output.xml", , xlXmlLoadImportToList

End Sub

XML 输出

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <row>
        <name>n</name>
        <version>v</version>
        <date>d</date>
        <attr1>val1</attr1>
        <attr2>val2</attr2>
        <attr4>val4</attr4>
        <attr5>val5</attr5>
        <attr6>val6</attr6>
        <attr7>val7</attr7>
        <attr8>val8</attr8>
        <attr9>val9</attr9>
        <attr10>val10</attr10>
        <attr11>val11</attr11>
        <attr12>val12</attr12>
    </row>
</data>

Excel 导入

name  version   date    attr1   attr2   attr4   attr5   attr6   attr7   attr8   attr9   attr10  attr11  attr12
  n         v      d     val1    val2    val4    val5    val6    val7    val8    val9    val10   val11   val12