基于公共id元素使用XSLT 3.0合并两个XML文件的实现方法
XSLT 3.0 基于xsl:merge的双XML按ID合并实现方案
实现特性
- 完全基于XSLT 3.0标准
xsl:merge能力开发,无冗余模板 - 不需要手动枚举植物节点下的待追加字段,自动过滤
<id>节点后追加所有匹配内容 - 完整保留早餐菜单XML中所有
<food>节点的原有结构、属性和文本内容 - 仅当两个文件的
<id>值完全匹配时,才会将对应植物节点的非id子元素追加到food节点下
完整实现代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <!-- 配置两个输入文件路径,可根据实际存储位置修改 --> <xsl:variable name="breakfastMenu" select="document('breakfast_menu.xml')"/> <xsl:variable name="plantCatalog" select="document('plant_catalog.xml')"/> <xsl:template match="/"> <breakfast_menu> <xsl:merge> <!-- 第一个合并流:早餐菜单food节点,以id为合并键 --> <xsl:merge-source name="foodStream" for-each-item="$breakfastMenu//food"> <xsl:merge-key select="id"/> </xsl:merge-source> <!-- 第二个合并流:植物目录PLANT节点,以id为合并键 --> <xsl:merge-source name="plantStream" for-each-item="$plantCatalog//PLANT"> <xsl:merge-key select="id"/> </xsl:merge-source> <xsl:merge-action> <!-- 完整拷贝匹配到的food节点所有原有内容 --> <xsl:copy-of select="current-merge-group('foodStream')"/> <!-- 自动追加匹配PLANT节点下除id外的所有子元素,无需手动枚举字段 --> <xsl:for-each select="current-merge-group('plantStream')"> <xsl:copy-of select="* except id"/> </xsl:for-each> </xsl:merge-action> </xsl:merge> </breakfast_menu> </xsl:template> </xsl:stylesheet>
如果转换时直接将早餐菜单XML作为主输入源传入,不需要通过
document()加载,可以把$breakfastMenu//food替换为//food简化配置。如果id为数值类型需要严格匹配,可以给<xsl:merge-key>添加data-type="number"属性。
关键逻辑说明
- 核心字段自动提取逻辑通过XPath 3.0的
* except id语法实现,会自动选中PLANT节点下所有子元素、排除id节点,后续植物目录新增、删除字段都不需要修改XSLT代码 - 采用
xsl:copy-of直接拷贝节点,不会丢失原有节点的属性、嵌套结构和文本内容 - 合并逻辑默认保留所有food节点,哪怕没有匹配到对应植物数据也不会丢失原有菜单条目
效果参考
输入样例1(早餐菜单)
<breakfast_menu> <food> <name>比利时华夫饼</name> <id>1</id> <description>搭配草莓和鲜奶油的轻食华夫</description> <calories>650</calories> </food> <food> <name>培根煎蛋</name> <id>2</id> <description>烟熏培根配两个太阳蛋</description> <calories>900</calories> </food> </breakfast_menu>
输入样例2(植物目录)
<CATALOG> <PLANT> <COMMON>Bloodroot</COMMON> <BOTANICAL>Sanguinaria canadensis</BOTANICAL> <ZONE>4</ZONE> <LIGHT>Mostly Shady</LIGHT> <id>1</id> <AVAILABILITY>031599</AVAILABILITY> </PLANT> </CATALOG>
合并输出结果
<breakfast_menu> <food> <name>比利时华夫饼</name> <id>1</id> <description>搭配草莓和鲜奶油的轻食华夫</description> <calories>650</calories> <COMMON>Bloodroot</COMMON> <BOTANICAL>Sanguinaria canadensis</BOTANICAL> <ZONE>4</ZONE> <LIGHT>Mostly Shady</LIGHT> <AVAILABILITY>031599</AVAILABILITY> </food> <food> <name>培根煎蛋</name> <id>2</id> <description>烟熏培根配两个太阳蛋</description> <calories>900</calories> </food> </breakfast_menu>
内容的提问来源于stack exchange,提问作者mayela
相关产品推荐
相关产品推荐

