在不知道架构 XPaths 的情况下自动将 Excel XmlMap 映射到 VBA 中的工作表 [英] Automatically map an Excel XmlMap to a worksheet in VBA without knowing the schema XPaths

查看:30
本文介绍了在不知道架构 XPaths 的情况下自动将 Excel XmlMap 映射到 VBA 中的工作表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个从 API 下载的 Excel 文件.

它可以从 URL 模式元数据自动生成 XmlMap.但是,我需要将 XmlMap 元素映射到 ListObjects 以提取数据并放在工作表上.

执行此操作的代码是每个项目的 range.Xpath.SetValue 映射 xPath(来自

<小时>

现在,如果您的 XML 具有复杂的嵌套子元素,请考虑构建和运行

I am building an Excel file that downloads from an API.

It can automatically generate the XmlMap from the URL schema metadata. However I then need to map the XmlMap elements to ListObjects in order to pull the data and put on a worksheet.

The code to do this is range.Xpath.SetValue map xPath for each item (from MSDN):

Sub CreateXMLList() 
    Dim mapContact As XmlMap 
    Dim strXPath As String 
    Dim lstContacts As ListObject 
    Dim objNewCol As ListColumn 

    ' Specify the schema map to use. 
    Set mapContact = ActiveWorkbook.XmlMaps("Contacts") 

    ' Create a new list. 
    Set lstContacts = ActiveSheet.ListObjects.Add 

    ' Specify the first element to map. 
    strXPath = "/Root/Person/FirstName" 
    ' Map the element. 
    lstContacts.ListColumns(1).XPath.SetValue mapContact, strXPath 

    ' Specify the second element to map. 
    strXPath = "/Root/Person/LastName" 
    ' Add a column to the list. 
    Set objNewCol = lstContacts.ListColumns.Add 
    ' Map the element. 
    objNewCol.XPath.SetValue mapContact, strXPath 

    strXPath = "/Root/Person/Address/Zip" 
    Set objNewCol = lstContacts.ListColumns.Add 
    objNewCol.XPath.SetValue mapContact, strXPath 
End Sub

Here's the schema output:

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
    <xsd:element name="root" nillable="true" >
        <xsd:complexType>
            <xsd:sequence minOccurs="0">
                <xsd:element minOccurs="0" maxOccurs="unbounded" nillable="true" name="list-item" form="unqualified">
                    <xsd:complexType>
                        <xsd:sequence minOccurs="0">

                            <xsd:element name="data_source_organization"
                                minOccurs="0"
                                nillable="true"
                                type="xsd:string"
                                form="unqualified"
                            />

                            <xsd:element name="survey_name"
                                minOccurs="0"
                                nillable="true"
                                type="xsd:string"
                                form="unqualified"
                            />
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

Here's the data (from which Excel automatically gets the schema and creates the XmlMap, if using the GUI):

<root xsi:noNamespaceSchemaLocation="/api/domain/schema/?format=xml">
    <list-item>
        <data_source_organization>An org</data_source_organization>
        <survey_name>A Survey</survey_name>
    </list-item>
    <list-item>
        <data_source_organization>An org</data_source_organization>
        <survey_name>Another Survey</survey_name>
    </list-item>
</root>

However I don't want to specify the XPath strings - I want Excel to get everything from the schema metadata, just like it does if you use the GUI functionality (Data, Get External Data, From Other Sources, XML, paste a URL) - this automatically creates an XML map, creates a ListObject on the worksheet, maps every column in the source data, and grabs and displays the data. (If you record a macro doing this, it skips the mapping step.)

  • Can I point an XmlMap to a cell, range or ListObject?
  • Can I iterate the XmlMap and retrieve every list-item XPath?
  • Some other way?

To experiment/reproduce, save the above XML as files, then create a sub as follows:

Set currentMap = ActiveWorkbook.XmlMaps.Add("C:\path\to\schema.xml", "root")
currentMap.DataBinding.LoadSettings "path\to\data.xml"
' Do something to map the XmlMap elements to cells in the spreadsheet
' eg, objNewCol.XPath.SetValue currentMap, "root/data_source_organization"
' But some method that does not involve naming the Xml paths but iterates the schema
currentMap.DataBinding.Refresh

If the XmlMap is mapped to cells, those cells will populate with data.

解决方案

Consider using Workbooks.OpenXML method as your XML file is flat and simple with one-child level for easy tabular import:

Sub ImportXML()   
     Workbooks.OpenXML "C:\Path\To\File.xml", , xlXmlLoadImportToList
End Sub


Now, if your XML is complex with nested child elements, consider building and running XSLT, the special-purpose language designed to transform XML files. Such transformations can be automated with the MSXML library, available as a VBA reference. Note: XSLT is not an XSD schema file but part of the extensible stylesheet family of which includes XPath.

Below XSLT removes the namespace from original XML. But script can be used to flatten nested, complex structures to flat, simple ones like your posted example.

XSLT (save as .xsl file; removes any namespace and attributes from document)

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

    <xsl:template match="*">
        <xsl:element name="{name()}">
            <xsl:apply-templates select="node()" />
        </xsl:element>
    </xsl:template>    
</xsl:stylesheet>

VBA

Sub XSLTransformAndImport()
On Error GoTo ErrHandle
    ' SELECT Microsoft XML, v6 AS VBA REFERENCE
    Dim xmldoc As New MSXML2.DOMDocument60, xslDoc As New MSXML2.DOMDocument60, newDoc As New MSXML2.DOMDocument60

    ' LOAD XML AND XSL FILES
    xslDoc.async = False
    xmldoc.Load "C:\Path\To\Input.xml"
    xslDoc.async = False
    xslDoc.Load "C:\Path\To\XSLTScript.xsl"

    ' TRANSFORM XML
    xmldoc.transformNodeToObject xslDoc, newDoc
    newDoc.Save "C:\Path\To\Output.xml"

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

ExitHandle
    ' RELEASE RESOURCES
    Set xmldoc = Nothing: Set xslDoc = Nothing: Set newDoc = Nothing
    Exit Sub

ErrHandle:
    MsgBox Err.Number & " - " & Err.Description, vbCritical
    Err.Raise xslDoc.parseError.ErrorCode, , xslDoc.parseError.reason
    Resume ExitHandle    
End Sub

这篇关于在不知道架构 XPaths 的情况下自动将 Excel XmlMap 映射到 VBA 中的工作表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆