如何在Ant XSLT任务中传入XML文件集生成单输出(Saxon XSLT3.0)
解决方案:批量XML提取合并为单一查找表
问题背景
需要从文件夹中的多个XML配置文件提取指定节点,合并成一个以<gek-lookup>为根节点的查找表XML。现有Ant+XSLT方案要么生成多个输出文件,要么循环处理时覆盖输出且速度慢,已尝试传递文件列表到XSLT,但存在需硬编码输入文件的问题。
优化后的实现方案
1. 改进Ant构建脚本
用空的XML占位文件(比如创建dummy.xml,内容为<dummy/>)替代硬编码的真实配置文件,既满足Ant的xslt任务对in参数的要求,又不影响逻辑:
<target name="GenerateFileIndex"> <pathconvert pathsep="," property="xmlflist" refid="xmlfileset"/> <mkdir dir="${output.dir}"/> <!-- 使用空占位文件作为输入 --> <xslt in="${config.dir}/dummy.xml" style="${xslt}" out="${output.dir}/${gek.index}" classpath="${saxon.jar}"> <factory name="net.sf.saxon.TransformerFactoryImpl"/> <param name="xml-config-files" expression="${xmlflist}"/> </xslt> </target> <fileset id="xmlfileset" dir="${config.dir}" casesensitive="no"> <include name="*.xml,*.XML"/> <exclude name="configurations.xml"/> </fileset>
2. 优化XSLT样式表
优化路径处理逻辑,简化节点复制代码:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xsl:param name="xml-config-files" as="xs:string*"/> <xsl:template match="/"> <gek-lookup> <xsl:for-each select="$xml-config-files"> <!-- 兼容Windows路径转URL格式 --> <xsl:variable name="file-url" select="concat('file:///', translate(., '\', '/'))"/> <xsl:apply-templates select="doc($file-url)/*"/> </xsl:for-each> </gek-lookup> </xsl:template> <xsl:template match="engine_config"> <xsl:copy> <xsl:copy-of select="eng_family, engine_model, cd_gek, version_no, display_name"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
关键改进点
- 用空占位文件消除对特定配置文件的依赖
- 直接使用
$xml-config-files参数(Saxon会自动将逗号分隔字符串解析为序列,无需tokenize) - 明确匹配
engine_config节点,避免处理无关节点 - 简化节点复制的
select表达式,提升可读性
更简洁的替代方案:利用Saxon集合功能
如果使用Saxon 9及以上版本,可直接用XSLT的collection()函数遍历目录,无需传递文件列表:
改进后的XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:param name="config-dir" as="xs:string"/> <xsl:template match="/"> <gek-lookup> <!-- 直接遍历指定目录的XML文件,排除目标输出文件 --> <xsl:apply-templates select="collection(concat($config-dir, '?select=*.xml;exclude=configurations.xml'))/*"/> </gek-lookup> </xsl:template> <xsl:template match="engine_config"> <xsl:copy> <xsl:copy-of select="eng_family, engine_model, cd_gek, version_no, display_name"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
对应的Ant任务
<target name="GenerateFileIndex"> <mkdir dir="${output.dir}"/> <xslt in="${config.dir}/dummy.xml" style="${xslt}" out="${output.dir}/${gek.index}" classpath="${saxon.jar}"> <factory name="net.sf.saxon.TransformerFactoryImpl"/> <param name="config-dir" expression="file:///{translate(${config.dir}, '\', '/')}"/> </xslt> </target>
这种方式无需处理文件列表,直接由XSLT完成目录遍历,代码更简洁,性能更优。
内容的提问来源于stack exchange,提问作者Caroline
相关产品推荐
相关产品推荐

