excel - 如何更改此基于 VBA/XSLT 的代码,以便将输出写入单个 XML 文件

标签 excel xml vba xslt

由于上一个问题,我得到了以下代码。

代码的含义是遍历一个 excelsheet 并自动用单元格内容填充 XML 标记。输出是此 excelsheet 中每一行的 XML 文件。

现在我有一个非常相似的案例,我知道,要完成它不会有太多改变。我希望我的代码不是为每一行创建一个新的 XML 文件,而是在同一个 XML 文件中填充所有内容。

我想自动填写这个excel表的内容:

excelfile

进入一个最初看起来像这样的 XML 模板:

<?xml version="1.0" encoding="UTF-8"?>
<Codes>
<AreaCodes>
<Area>
<Name></Name>
<Desc/>
<Facility_Area></Facility_Area>
</Area>
</AreaCodes>
</Codes>

FACILITY 列必须在 Facility_Area-Tag 中移动。

必须在名称标签中移动 AREA 列。

Area 内的所有嵌套标签都应该重复。

对于我的 Excel 示例,输出应如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<Codes>
<AreaCodes>
<Area>
<Name>RA 001</Name>
<Desc/>
<Facility_Area>ZUF</Facility_Area>
</Area>
<Area>
<Name>RA 002</Name>
<Desc/>
<Facility_Area>ZUF</Facility_Area>
</Area>
<Area>
<Name>RA 003</Name>
<Desc/>
<Facility_Area>ZUF</Facility_Area>
</Area>
<Area>
<Name>RA 004</Name>
<Desc/>
<Facility_Area>ZUF</Facility_Area>
</Area>
...
</AreaCodes>
</Codes>

全部在一个文件中。

这是我有 atm 的 XSLT 模板:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes" />

    <xsl:param name="facility" />
    <xsl:param name="area" />


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

    <!-- Templates -->


<xsl:template match="Codes/AreaCodes/Area/Name">
    <xsl:copy>
        <xsl:value-of select="$area"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="Codes/AreaCodes/Area/Facility_Area">
    <xsl:copy>
        <xsl:value-of select="$facility"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

最后但并非最不重要的是 VBA 代码,其中所有内容都汇集在一起​​:
    Sub Param_XSLT_Process()

...

        ' LOAD XML AND XSL FILES
       xmldoc.async = False
        xmldoc.Load "Path\To\Vorlage_AREA.xml"

        xslDoc.async = False
        xslDoc.setProperty "AllowDocumentFunction", True
        xslDoc.Load "Path\To\XSL_SHEET.xsl"

        ' INITIALIZE NEEDED OBJECTS
       Set xslTemp.stylesheet = xslDoc
        Set xslProc = xslTemp.createProcessor()

        xslProc.input = xmldoc

        ' ITERATE THROUGH EACH ROW, TRANSFORM, SAVE XML OUTPUT
       With ActiveWorkbook.Worksheets(1)
           lLastRow = .UsedRange.Rows.Count

           For lRow = 2 To lLastRow
               xslProc.addParameter "area", CStr(.Cells(lRow, 2).Value)    ' ADD PARAMETER(S)
              xslProc.addParameter "facility", CStr(.Cells(lRow, 1).Value)

               xslProc.transform                                            ' TRANSFORM XML
               newDoc.LoadXML xslProc.output                                ' LOAD RESULT TREE
               newDoc.Save "Path\To\Output_" & lRow - 1 & ".xml"         ' SAVE OUTPUT TO FILE
          Next lRow
        End With
...
    End Sub

现在,所有内容都放在一个单独的 XML 文件中。

谁能告诉我,我必须改变什么?我知道,对于我的 VBA 代码,我应该将那些保存命令移到循环之外,但这不起作用。

很抱歉在英语方面遇到了困难,感谢大家的帮助。

最佳答案

我写了一个VBA类模块SheetWrapper :

Private mySheet As Object

Sub Init(sheet)
    Set mySheet = sheet
End Sub

Public Property Get Cell(rowIndex, cellIndex)
    Cell = CStr(mySheet.Cells(rowIndex, cellIndex).Value)
End Property

然后就可以使用
Sub Param_XSLT_Process()
    Dim xmlDoc As New MSXML2.DOMDocument60

    Dim xslDoc As New MSXML2.FreeThreadedDOMDocument60

    Dim xslTemp As New MSXML2.XSLTemplate60

    Dim xslProc As MSXML2.IXSLProcessor

    Dim resultDoc As New MSXML2.DOMDocument60

    Dim worksheet As Object
    Set worksheet = ActiveWorkbook.Worksheets(1)

    Dim myWrapper As SheetWrapper
    Set myWrapper = New SheetWrapper

    myWrapper.Init worksheet


    ' LOAD XML AND XSL FILES
    xmlDoc.async = False
    xmlDoc.Load "C:\SomePath\template.xml"

    xslDoc.async = False
    xslDoc.SetProperty "AllowDocumentFunction", True
    xslDoc.Load "C:\SomePath\sheet.xsl"

    ' INITIALIZE NEEDED OBJECTS
    Set xslTemp.stylesheet = xslDoc
    Set xslProc = xslTemp.createProcessor()

    xslProc.addObject myWrapper, "http://example.com/excel"

    xslProc.addParameter "first-row-index", 2, ""
    xslProc.addParameter "last-row-index", ActiveWorkbook.Worksheets(1).UsedRange.Rows.Count, ""


    xslProc.input = xmlDoc

    xslProc.output = resultDoc

    xslProc.transform

    resultDoc.Save "C:\SomePath\transformation-result.xml"
End Sub

与 XSLT 一起:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    xmlns:excel="http://example.com/excel"
    exclude-result-prefixes="msxsl excel">

    <xsl:param name="sheet"/>

    <xsl:param name="first-row-index"/>
    <xsl:param name="last-row-index"/>

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

    <xsl:output indent="yes"/>

    <xsl:template match="AreaCodes">
        <xsl:copy>
            <xsl:call-template name="make-areas">
                <xsl:with-param name="area" select="Area"/>
                <xsl:with-param name="index" select="$first-row-index"/>
                <xsl:with-param name="last" select="$last-row-index"/>
            </xsl:call-template>
        </xsl:copy>
    </xsl:template>

    <xsl:template name="make-areas">
        <xsl:param name="area"/>
        <xsl:param name="index"/>
        <xsl:param name="last"/>
        <xsl:apply-templates select="$area">
            <xsl:with-param name="row-index" select="$index"/>
        </xsl:apply-templates>
        <xsl:if test="$index &lt; $last">
            <xsl:call-template name="make-areas">
                <xsl:with-param name="area" select="$area"/>
                <xsl:with-param name="index" select="$index + 1"/>
                <xsl:with-param name="last" select="$last"/>
            </xsl:call-template>            
        </xsl:if>
    </xsl:template>

    <xsl:template match="Area">
        <xsl:param name="row-index"/>
        <xsl:copy>
            <xsl:apply-templates>
                <xsl:with-param name="row-index" select="$row-index"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Area/Name">
        <xsl:param name="row-index"/>
        <xsl:copy>
            <xsl:value-of select="excel:get-Cell($row-index, 1)"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Area/Facility_Area">
        <xsl:param name="row-index"/>
        <xsl:copy>
            <xsl:value-of select="excel:get-Cell($row-index, 2)"/>
        </xsl:copy>
    </xsl:template>    

</xsl:stylesheet>

我曾希望能够将 Excel 工作表对象直接传递给 XSLT 以读取其单元格,但不知何故 MSXML 并没有理解这一点。

关于excel - 如何更改此基于 VBA/XSLT 的代码,以便将输出写入单个 XML 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57994607/

相关文章:

excel - 在Excel中使用查找方法

excel - 从给定范围中删除标点符号的 VBA 循环

excel - 当行的A列对所有行都是Yes时锁定行中的选定单元格

sql - 如何自动将数据发送到excel

xml - 通过索引更新重复的子节点

xml - 如何使用 XSLT 重命名 XML 标签

excel - Wbk 中已删除的名称仍然存在并引用不存在的位置,导致 Excel 速度变慢

vba - Excel VBA - 获取工作表的父窗口

excel - 将单元格粘贴到 VBA 中的另一个工作表

c# - SOAP WCF : Prevent deserialization to private fields