Camel路由中XSLT的result-document写入异常及解决方案问询
解决XSLT批量生成文件时的FileNotFoundException问题
你遇到的问题大概率是文件系统竞争或者输出目录未提前创建导致的,下面给你几个可行的解决思路,从基础修正到延迟处理都有:
一、先修正代码里的基础错误
你的代码片段里有几个语法问题,先修正这些再排查其他问题:
- 变量定义错误:
<xsl:variable test="pos" select="position()"/>里的test应该改成name,正确写法是:<xsl:variable name="pos" select="position()"/> xsl:result-document的href属性需要用属性值模板,直接写concat函数不会生效,正确写法是:<xsl:result-document href="{concat('FileName_', $pos, '.xml')}" method="xml" indent="yes">- 代码片段1里的
{Delay}是无效语法,需要替换成实际的延迟逻辑。
二、添加延迟的正确实现
XSLT标准库没有内置延迟函数,需要借助处理器的扩展能力(比如Saxon支持Java扩展)。下面是基于Saxon的延迟实现:
步骤1:声明Java扩展命名空间
在样式表开头添加:
xmlns:java="http://saxon.sf.net/java-type" exclude-result-prefixes="java xd"
步骤2:实现延迟模板
修改你的write-with-delay模板,调用Java的Thread.sleep():
<xsl:template name="write-with-delay"> <xsl:param name="filename"/> <!-- 延迟500毫秒,根据需要调整 --> <xsl:value-of select="java:lang.Thread.sleep(500)"/> <xsl:result-document href="{$filename}" method="xml" indent="yes"> <!-- 这里放你的分组内容 --> <group-content> <xsl:copy-of select="current-group()"/> </group-content> </xsl:result-document> </xsl:template>
注意事项
- 这个方案仅适用于支持Java扩展的XSLT处理器(比如Saxon-HE/PE/EE)
- 延迟时间不要设置太长,避免整体处理效率过低,500-1000毫秒足够缓解大部分文件系统竞争
三、非延迟的更优解决方案
延迟只是临时缓解,更根本的解决方法是从根源避免错误:
1. 确保输出目录存在
FileNotFoundException最常见的原因是输出目录未创建,可以在XSLT处理前手动创建目录,或者用扩展函数在XSLT里创建:
<!-- 在处理前创建目录,示例用Saxon的Java扩展 --> <xsl:value-of select="java:java.io.File.new('output-dir').mkdirs()"/>
2. 避免文件名冲突
确保每个分组生成的文件名唯一,比如用groupID代替position()(如果groupID唯一的话),避免因为分组顺序问题导致文件名重复覆盖:
<xsl:with-param name="filename" select="concat('FileName_', current-grouping-key(), '.xml')"/>
3. 调整XSLT处理器的并发设置
如果你的处理器支持并发写入(比如Saxon EE),可以关闭并发或者调整并发数,避免文件系统过载:
- 命令行参数:设置
-saxon:allow-multiple-writes=false - 编程调用时调整对应配置参数
4. 优化序列化参数
给xsl:result-document添加更多序列化参数,确保文件写入更稳定:
<xsl:result-document href="{$filename}" method="xml" indent="yes" encoding="UTF-8" byte-order-mark="no" standalone="yes">
修正后的完整示例代码
<?xml version="2.0"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:java="http://saxon.sf.net/java-type" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" exclude-result-prefixes="java xd"> <xd:docscope> <xd:option name="delay-function" value="sleep 500"/> </xd:docscope> <!-- 提前创建输出目录 --> <xsl:template match="/"> <xsl:value-of select="java:java.io.File.new('output').mkdirs()"/> <xsl:for-each-group select="node/nodes" group-by="groupID"> <xsl:variable name="filename" select="concat('output/FileName_', current-grouping-key(), '.xml')"/> <xsl:call-template name="write-with-delay"> <xsl:with-param name="filename" select="$filename"/> </xsl:call-template> </xsl:for-each-group> </xsl:template> <xsl:template name="write-with-delay"> <xsl:param name="filename"/> <!-- 延迟500毫秒 --> <xsl:value-of select="java:lang.Thread.sleep(500)"/> <xsl:result-document href="{$filename}" method="xml" indent="yes" encoding="UTF-8"> <group> <group-id><xsl:value-of select="current-grouping-key()"/></group-id> <xsl:copy-of select="current-group()"/> </group> </xsl:result-document> </xsl:template> </xsl:stylesheet>
内容的提问来源于stack exchange,提问作者Sjoert
相关产品推荐
相关产品推荐

