在 MS Access 2013 中指定确切的 XML 导出结构
Specify exact XML export structure in MS Access 2013
我有一个包含课程数据的 MS Access 数据库,该数据库会定期导出到 XML 以为网站提供数据。
我需要导出的table是一个主要的Courses
table,加上其他几个直接相关和间接相关的table,例如Occurrences
, OccurrencesUnits
, Units
, Locations
, Staff
, SubjectAreas
, 等等
在我之前的 的帮助下(可能值得阅读一些背景信息)我能够设置所需的确切 XML 结构,下面进行了简化:
<Courses>
<CourseID>1</CourseID>
<CourseTitle>Meat Science</CourseTitle>
(etc etc)
<Occurrences>
<OccurrenceID>1</OccurrenceID>
<OccurrenceTitle>Meat Science Autumn 2016</OccurrenceTitle>
<CourseID>1</CourseID>
<OccurrencesUnits>
<OccurrencesUnitsID>1</OccurrencesUnitsID>
<OccurrenceID>1</OccurrenceID>
<UnitID>1</UnitID>
</OccurrencesUnits>
</Occurrences>
</Courses>
<Courses>
... more courses...
</Courses>
<Units>
...
</Units>
<Locations>
...
</Locations>
<Staff>
...
</Staff>
<SubjectAreas>
...
</SubjectAreas>
etc etc
所以有几层 Occurrences
然后 OccurrencesUnits
table 嵌套在它们的每个 Courses
条目中,但是所有其他相关tables 需要列在下面(不嵌套)。
但是,在最近从 Access 2010 升级到 2013 时,我发现我无法生成相同的结构。 Access 2013 似乎考虑了 table 关系,默认情况下将任何 直接相关的 table 嵌套到主 table 节点中。通过 XSL 指定布局结构时(根据上面链接的我的相关 Stack Overflow 问题),这会导致 directly 相关 table 从 [=84= 中省略] 导出,与 2010 年不同,它们自动出现在 Courses
.
下方
我发现 accessforums.net 上的另一个人发现了类似的问题:http://www.accessforums.net/showthread.php?t=46933 他们的解决方案是删除 Access 中的 table 关系,公平地说,这确实会导致预期的结果XML 输出,但可能对我的数据库相当不利!
有关信息,我在 Access 中的 VBA 导出代码如下所示:
Private Sub ExportCourseCatalogXML_Click()
Dim rawDoc As Object, xslDoc As Object, newDoc As Object
Dim xmlstr As String, xslstr As String
Dim otherTables As AdditionalData
Set otherTables = Application.CreateAdditionalData
otherTables.Add "Occurrences"
otherTables.Add "OccurrencesUnits"
otherTables.Add "Units"
otherTables.Add "Locations"
otherTables.Add "CourseSubcategories"
otherTables.Add "CourseTags"
otherTables.Add "Partners"
otherTables.Add "Staff"
otherTables.Add "SubjectAreas"
Application.ExportXML acExportTable, "Courses", "S:\Science\Biosciences\AATP\Database\xml\course-catalog.xml", _
, , , , , , AdditionalData:=otherTables
' LOAD XML AND XSL FILES '
xmlstr = "C:\path\to\course-catalog.xml"
xslstr = "C:\path\to\structure.xsl"
Set rawDoc = CreateObject("MSXML2.DOMDocument")
Set xslDoc = CreateObject("MSXML2.DOMDocument")
Set newDoc = CreateObject("MSXML2.DOMDocument")
rawDoc.async = False
rawDoc.Load xmlstr
xslDoc.async = False
xslDoc.Load xslstr
' TRANSFORM TO NEW XML '
rawDoc.transformNodeToObject xslDoc, newDoc
' SAVE NEW XML FILE '
newDoc.Save "C:\path\to\course-catalog.xml"
MsgBox "Successfully exported XML.", vbInformation
End Sub
我的 structure.xsl
看起来像这样:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:od="urn:schemas-microsoft-com:officedata"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="od xsi">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<!-- Identity Transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Courses">
<Courses>
<xsl:copy-of select="CourseID"/>
<xsl:copy-of select="CourseTitle"/>
(etc etc)
<xsl:for-each select="Occurrences">
<Occurrences>
<xsl:copy-of select="*"/>
<xsl:variable name="occid" select="occurrenceID"/>
<xsl:copy-of select="../../OccurrencesUnits[CourseOccurrence=$occid]"/>
</Occurrences>
</xsl:for-each>
</Courses>
</xsl:template>
<xsl:template match="OccurrencesUnits"/>
</xsl:transform>
所以我的问题 - 是否可以指定(大概通过 XSL)我需要的确切结构,即所有 table 都列在 之外 Courses
除了Occurrences
和OccurrencesUnits
?在此先感谢您对此的支持!
2016 年 8 月 17 日添加:
为了清楚起见,可以在下面看到 MS Access 2013 生成的 XML。它与 2010 年类似,但问题是任何 直接 与课程 table 相关的 table 都被省略了(CourseSubcategories
,[ =31=、Partners
、Staff
和 SubjectAreas
),要包含它们的唯一方法是在 Access 中删除它们与 Courses
的关系。 Units
和Locations
的table被包括在内(因为它们与没有直接关系Courses
).
<Courses>
<CourseID>1</CourseID>
<CourseTitle>Meat Science</CourseTitle>
(etc etc)
<Occurrences>
<OccurrenceID>1</OccurrenceID>
<OccurrenceTitle>Meat Science Autumn 2016</OccurrenceTitle>
<CourseID>1</CourseID>
<OccurrencesUnits>
<OccurrencesUnitsID>1</OccurrencesUnitsID>
<OccurrenceID>1</OccurrenceID>
<UnitID>1</UnitID>
</OccurrencesUnits>
</Occurrences>
</Courses>
<Courses>
... more courses...
</Courses>
<Units>
...
</Units>
<Locations>
...
</Locations>
考虑为那些没有出现的相关表导出单独的临时 xml 文件。然后,使用 document()
函数将那些 xml 包含在 XSLT 转换中。 VBA 转换后将删除它们。这种方法中一个非常重要的设置是 XSLT (.xsl) 脚本必须与 XML 文件位于同一文件夹中,因为它会进行相关文件引用:
VBA
Private Sub ExportCourseCatalogXML_Click()
Dim rawDoc As Object, xslDoc As Object, newDoc As Object
Dim xmlstr As String, xslstr As String
Dim otherTables As AdditionalData
Dim temp As Variant
Set otherTables = Application.CreateAdditionalData
otherTables.Add "Occurrences"
otherTables.Add "OccurrencesUnits"
' EXPORT MAIN XML
Application.ExportXML acExportTable, "Courses", "S:\Science\Biosciences\AATP\Database\xml\course-catalog.xml", _
, , , , , , AdditionalData:=otherTables
' EXPORT TEMP XMLS
For Each temp in Array("Units", "Locations", "CourseSubcategories", "CourseTags", "Partners", "Staff", "SubjectAreas")
Application.ExportXML acExportTable, temp, "S:\Science\Biosciences\AATP\Database\xml\" & temp & ".xml"
Next temp
' LOAD XML AND XSL FILES '
xmlstr = "C:\path\to\course-catalog.xml"
xslstr = "C:\path\to\structure.xsl"
Set rawDoc = CreateObject("MSXML2.DOMDocument")
Set xslDoc = CreateObject("MSXML2.DOMDocument")
Set newDoc = CreateObject("MSXML2.DOMDocument")
rawDoc.async = False
rawDoc.setProperty "AllowDocumentFunction", True
rawDoc.Load xmlstr
xslDoc.async = False
xslDoc.setProperty "AllowDocumentFunction", True
xslDoc.Load xslstr
' TRANSFORM TO NEW XML '
rawDoc.transformNodeToObject xslDoc, newDoc
' SAVE NEW XML FILE '
newDoc.Save "C:\path\to\course-catalog.xml"
' DELETE TEMP XMLs
For Each temp in Array("Units", "Locations", "CourseSubcategories", "CourseTags", "Partners", "Staff", "SubjectAreas")
xmlfile = "S:\Science\Biosciences\AATP\Database\xml\" & temp & ".xml"
If Len(Dir(xmlfile, vbDirectory)) > 0 Then Kill xmlfile
Next temp
MsgBox "Successfully exported XML.", vbInformation
End Sub
XSLT (必须保存在与其他 .xml 文件相同的目录中)
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:od="urn:schemas-microsoft-com:officedata"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="od xsi">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="/dataroot">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:copy-of select="document('CourseSubcategories.xml')/dataroot/CourseSubcategories"/>
<xsl:copy-of select="document('CourseTags.xml')/dataroot/CourseTags"/>
<xsl:copy-of select="document('Partners.xml')/dataroot/Partners"/>
<xsl:copy-of select="document('Staff.xml')/dataroot/Staff"/>
<xsl:copy-of select="document('SubjectAreas.xml')/dataroot/SubjectAreas"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Courses">
<Courses>
<xsl:copy-of select="CourseID"/>
<xsl:copy-of select="CourseTitle"/>
(etc etc)
<xsl:for-each select="Occurrences">
<Occurrences>
<xsl:copy-of select="*"/>
<xsl:variable name="occid" select="occurrenceID"/>
<xsl:copy-of select="ancestor::dataroot/OccurrencesUnits[CourseOccurrence=$occid]"/>
</Occurrences>
</xsl:for-each>
</Courses>
</xsl:template>
<xsl:template match="OccurrencesUnits"/>
</xsl:transform>
我有一个包含课程数据的 MS Access 数据库,该数据库会定期导出到 XML 以为网站提供数据。
我需要导出的table是一个主要的Courses
table,加上其他几个直接相关和间接相关的table,例如Occurrences
, OccurrencesUnits
, Units
, Locations
, Staff
, SubjectAreas
, 等等
在我之前的
<Courses>
<CourseID>1</CourseID>
<CourseTitle>Meat Science</CourseTitle>
(etc etc)
<Occurrences>
<OccurrenceID>1</OccurrenceID>
<OccurrenceTitle>Meat Science Autumn 2016</OccurrenceTitle>
<CourseID>1</CourseID>
<OccurrencesUnits>
<OccurrencesUnitsID>1</OccurrencesUnitsID>
<OccurrenceID>1</OccurrenceID>
<UnitID>1</UnitID>
</OccurrencesUnits>
</Occurrences>
</Courses>
<Courses>
... more courses...
</Courses>
<Units>
...
</Units>
<Locations>
...
</Locations>
<Staff>
...
</Staff>
<SubjectAreas>
...
</SubjectAreas>
etc etc
所以有几层 Occurrences
然后 OccurrencesUnits
table 嵌套在它们的每个 Courses
条目中,但是所有其他相关tables 需要列在下面(不嵌套)。
但是,在最近从 Access 2010 升级到 2013 时,我发现我无法生成相同的结构。 Access 2013 似乎考虑了 table 关系,默认情况下将任何 直接相关的 table 嵌套到主 table 节点中。通过 XSL 指定布局结构时(根据上面链接的我的相关 Stack Overflow 问题),这会导致 directly 相关 table 从 [=84= 中省略] 导出,与 2010 年不同,它们自动出现在 Courses
.
我发现 accessforums.net 上的另一个人发现了类似的问题:http://www.accessforums.net/showthread.php?t=46933 他们的解决方案是删除 Access 中的 table 关系,公平地说,这确实会导致预期的结果XML 输出,但可能对我的数据库相当不利!
有关信息,我在 Access 中的 VBA 导出代码如下所示:
Private Sub ExportCourseCatalogXML_Click()
Dim rawDoc As Object, xslDoc As Object, newDoc As Object
Dim xmlstr As String, xslstr As String
Dim otherTables As AdditionalData
Set otherTables = Application.CreateAdditionalData
otherTables.Add "Occurrences"
otherTables.Add "OccurrencesUnits"
otherTables.Add "Units"
otherTables.Add "Locations"
otherTables.Add "CourseSubcategories"
otherTables.Add "CourseTags"
otherTables.Add "Partners"
otherTables.Add "Staff"
otherTables.Add "SubjectAreas"
Application.ExportXML acExportTable, "Courses", "S:\Science\Biosciences\AATP\Database\xml\course-catalog.xml", _
, , , , , , AdditionalData:=otherTables
' LOAD XML AND XSL FILES '
xmlstr = "C:\path\to\course-catalog.xml"
xslstr = "C:\path\to\structure.xsl"
Set rawDoc = CreateObject("MSXML2.DOMDocument")
Set xslDoc = CreateObject("MSXML2.DOMDocument")
Set newDoc = CreateObject("MSXML2.DOMDocument")
rawDoc.async = False
rawDoc.Load xmlstr
xslDoc.async = False
xslDoc.Load xslstr
' TRANSFORM TO NEW XML '
rawDoc.transformNodeToObject xslDoc, newDoc
' SAVE NEW XML FILE '
newDoc.Save "C:\path\to\course-catalog.xml"
MsgBox "Successfully exported XML.", vbInformation
End Sub
我的 structure.xsl
看起来像这样:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:od="urn:schemas-microsoft-com:officedata"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="od xsi">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<!-- Identity Transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Courses">
<Courses>
<xsl:copy-of select="CourseID"/>
<xsl:copy-of select="CourseTitle"/>
(etc etc)
<xsl:for-each select="Occurrences">
<Occurrences>
<xsl:copy-of select="*"/>
<xsl:variable name="occid" select="occurrenceID"/>
<xsl:copy-of select="../../OccurrencesUnits[CourseOccurrence=$occid]"/>
</Occurrences>
</xsl:for-each>
</Courses>
</xsl:template>
<xsl:template match="OccurrencesUnits"/>
</xsl:transform>
所以我的问题 - 是否可以指定(大概通过 XSL)我需要的确切结构,即所有 table 都列在 之外 Courses
除了Occurrences
和OccurrencesUnits
?在此先感谢您对此的支持!
2016 年 8 月 17 日添加:
为了清楚起见,可以在下面看到 MS Access 2013 生成的 XML。它与 2010 年类似,但问题是任何 直接 与课程 table 相关的 table 都被省略了(CourseSubcategories
,[ =31=、Partners
、Staff
和 SubjectAreas
),要包含它们的唯一方法是在 Access 中删除它们与 Courses
的关系。 Units
和Locations
的table被包括在内(因为它们与没有直接关系Courses
).
<Courses>
<CourseID>1</CourseID>
<CourseTitle>Meat Science</CourseTitle>
(etc etc)
<Occurrences>
<OccurrenceID>1</OccurrenceID>
<OccurrenceTitle>Meat Science Autumn 2016</OccurrenceTitle>
<CourseID>1</CourseID>
<OccurrencesUnits>
<OccurrencesUnitsID>1</OccurrencesUnitsID>
<OccurrenceID>1</OccurrenceID>
<UnitID>1</UnitID>
</OccurrencesUnits>
</Occurrences>
</Courses>
<Courses>
... more courses...
</Courses>
<Units>
...
</Units>
<Locations>
...
</Locations>
考虑为那些没有出现的相关表导出单独的临时 xml 文件。然后,使用 document()
函数将那些 xml 包含在 XSLT 转换中。 VBA 转换后将删除它们。这种方法中一个非常重要的设置是 XSLT (.xsl) 脚本必须与 XML 文件位于同一文件夹中,因为它会进行相关文件引用:
VBA
Private Sub ExportCourseCatalogXML_Click()
Dim rawDoc As Object, xslDoc As Object, newDoc As Object
Dim xmlstr As String, xslstr As String
Dim otherTables As AdditionalData
Dim temp As Variant
Set otherTables = Application.CreateAdditionalData
otherTables.Add "Occurrences"
otherTables.Add "OccurrencesUnits"
' EXPORT MAIN XML
Application.ExportXML acExportTable, "Courses", "S:\Science\Biosciences\AATP\Database\xml\course-catalog.xml", _
, , , , , , AdditionalData:=otherTables
' EXPORT TEMP XMLS
For Each temp in Array("Units", "Locations", "CourseSubcategories", "CourseTags", "Partners", "Staff", "SubjectAreas")
Application.ExportXML acExportTable, temp, "S:\Science\Biosciences\AATP\Database\xml\" & temp & ".xml"
Next temp
' LOAD XML AND XSL FILES '
xmlstr = "C:\path\to\course-catalog.xml"
xslstr = "C:\path\to\structure.xsl"
Set rawDoc = CreateObject("MSXML2.DOMDocument")
Set xslDoc = CreateObject("MSXML2.DOMDocument")
Set newDoc = CreateObject("MSXML2.DOMDocument")
rawDoc.async = False
rawDoc.setProperty "AllowDocumentFunction", True
rawDoc.Load xmlstr
xslDoc.async = False
xslDoc.setProperty "AllowDocumentFunction", True
xslDoc.Load xslstr
' TRANSFORM TO NEW XML '
rawDoc.transformNodeToObject xslDoc, newDoc
' SAVE NEW XML FILE '
newDoc.Save "C:\path\to\course-catalog.xml"
' DELETE TEMP XMLs
For Each temp in Array("Units", "Locations", "CourseSubcategories", "CourseTags", "Partners", "Staff", "SubjectAreas")
xmlfile = "S:\Science\Biosciences\AATP\Database\xml\" & temp & ".xml"
If Len(Dir(xmlfile, vbDirectory)) > 0 Then Kill xmlfile
Next temp
MsgBox "Successfully exported XML.", vbInformation
End Sub
XSLT (必须保存在与其他 .xml 文件相同的目录中)
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:od="urn:schemas-microsoft-com:officedata"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="od xsi">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="/dataroot">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:copy-of select="document('CourseSubcategories.xml')/dataroot/CourseSubcategories"/>
<xsl:copy-of select="document('CourseTags.xml')/dataroot/CourseTags"/>
<xsl:copy-of select="document('Partners.xml')/dataroot/Partners"/>
<xsl:copy-of select="document('Staff.xml')/dataroot/Staff"/>
<xsl:copy-of select="document('SubjectAreas.xml')/dataroot/SubjectAreas"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Courses">
<Courses>
<xsl:copy-of select="CourseID"/>
<xsl:copy-of select="CourseTitle"/>
(etc etc)
<xsl:for-each select="Occurrences">
<Occurrences>
<xsl:copy-of select="*"/>
<xsl:variable name="occid" select="occurrenceID"/>
<xsl:copy-of select="ancestor::dataroot/OccurrencesUnits[CourseOccurrence=$occid]"/>
</Occurrences>
</xsl:for-each>
</Courses>
</xsl:template>
<xsl:template match="OccurrencesUnits"/>
</xsl:transform>