求助:开发XSLT将属性密集型嵌套XML转为元素型以导入Access DB
解决属性密集型XML转Access友好元素格式的XSLT方案
嗨,我来帮你搞定这个XSLT转换的问题!把属性堆得满满的XML转成适合Access导入的元素格式,还要合并嵌套元素里的属性,其实核心就是用XSLT的模板匹配和属性遍历,我给你一步步拆解清楚。
先举个典型的场景示例,方便你对应自己的实际数据:
示例当前属性密集型XML
<Products> <Product id="1" name="Laptop" price="999"> <Specs weight="2.3kg" screen="15.6inch" /> <Inventory stock="10" warehouse="NY" /> </Product> <Product id="2" name="Phone" price="699"> <Specs weight="0.18kg" screen="6.1inch" /> <Inventory stock="25" warehouse="CA" /> </Product> </Products>
目标Access友好格式(扁平化元素结构)
Access导入时更偏好这种每个数据字段都是独立元素的结构,嵌套属性也被合并到主元素下:
<Products> <Product> <id>1</id> <name>Laptop</name> <price>999</price> <weight>2.3kg</weight> <screen>15.6inch</screen> <stock>10</stock> <warehouse>NY</warehouse> </Product> <Product> <id>2</id> <name>Phone</name> <price>699</price> <weight>0.18kg</weight> <screen>6.1inch</screen> <stock>25</stock> <warehouse>CA</warehouse> </Product> </Products>
实现转换的XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 复制根元素,保证整体结构不变 --> <xsl:template match="/"> <xsl:copy> <xsl:apply-templates /> </xsl:copy> </xsl:template> <!-- 匹配主数据元素(比如这里的Product),处理自身和嵌套子元素的属性 --> <xsl:template match="Product"> <xsl:copy> <!-- 先把当前元素的所有属性转成子元素 --> <xsl:apply-templates select="@*" /> <!-- 递归处理所有嵌套子元素的属性,合并到主元素下 --> <xsl:apply-templates select="*//@*" /> </xsl:copy> </xsl:template> <!-- 核心转换:把每个属性转成同名的元素 --> <xsl:template match="@*"> <xsl:element name="{name()}"> <xsl:value-of select="." /> </xsl:element> </xsl:template> <!-- 忽略原始的嵌套子元素节点(比如Specs、Inventory),只提取它们的属性 --> <xsl:template match="*"> <xsl:apply-templates /> </xsl:template> </xsl:stylesheet>
关键逻辑说明
- 根元素模板:原样复制XML的根节点,保证转换后的整体结构和原数据一致。
- 主元素模板:匹配你需要转换的核心数据节点(比如你的业务里的主记录节点),复制节点本身后,先处理自身的所有属性,再递归抓取所有嵌套子元素的属性,统一转成主元素的子元素,实现嵌套属性的合并。
- 属性转元素模板:把每个属性都转换成同名的元素,属性值作为元素的文本内容,这正是Access导入时最兼容的格式。
- 子元素忽略模板:原始的嵌套容器元素(比如示例里的
Specs)我们不需要保留,所以只递归处理它们的属性,不复制元素本身。
灵活调整的场景
如果你的数据结构有特殊需求,可以针对性修改:
- 要是某些嵌套子元素需要保留而不是只取属性,给这些元素单独写模板即可:
<xsl:template match="SomeElementToKeep"> <xsl:copy> <xsl:apply-templates select="@* | node()" /> </xsl:copy> </xsl:template> - 如果主元素和嵌套子元素有同名属性,怕冲突可以给子元素的属性加前缀:
<xsl:template match="Specs/@*"> <xsl:element name="spec_{name()}"> <xsl:value-of select="." /> </xsl:element> </xsl:template>
内容的提问来源于stack exchange,提问作者Sian Picksley
相关产品推荐
相关产品推荐

