【问题标题】:How to change this VBA/XSLT-based code so the output is written in a single XML-File如何更改此基于 VBA/XSLT 的代码,以便将输出写入单个 XML 文件
【发布时间】:2020-01-19 12:28:24
【问题描述】:

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

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

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

我要自动填写这个excel-table的内容:

进入一个最初看起来像这样的 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 代码,我应该将那些保存命令移到循环之外,但这不起作用。

很抱歉让您的英语陷入困境,感谢大家的帮助。

【问题讨论】:

    标签: excel xml vba xslt


    【解决方案1】:

    我写了一个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 无法理解。

    【讨论】:

    • 我会在星期一试一试,并就我的效果给出反馈。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2011-11-03
    • 2019-07-12
    • 2013-03-20
    • 2018-02-11
    • 2019-08-11
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多