由于上一个问题,我得到了以下代码。
代码的含义是遍历一个 excelsheet 并自动用单元格内容填充 XML 标记。输出是此 excelsheet 中每一行的 XML 文件。
现在我有一个非常相似的案例,我知道,要完成它不会有太多改变。我希望我的代码不是为每一行创建一个新的 XML 文件,而是在同一个 XML 文件中填充所有内容。
我想自动填写这个excel表的内容:
进入一个最初看起来像这样的 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 < $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/