我的XSLT执行耗时数小时,是哪部分代码引发的性能问题?
性能问题根因
- 滥用
preceding::和following::全文档扫描轴:这两个轴会遍历当前节点前后所有文档节点,而非仅同层级相邻节点,对于每个<html:b>、<html:br>节点都会触发全树扫描,时间复杂度达到O(n²),是性能卡顿的核心原因。 - 重复冗余判断:
<html:br>匹配模板中存在两个完全一致的starts-with(following::text()[1],'(')判断逻辑,产生多余计算开销。 - 递归调用风险:
processBold命名模板中<xsl:apply-templates select="."/>会重新触发当前<html:b>节点的匹配规则,造成无意义的重复计算,严重时会触发死循环。 - 多步转换额外开销:8步独立XSLT转换每步都需要重新解析、序列化XML,叠加每步的全树扫描开销,耗时被指数级放大。
优化方案
- 替换全文档扫描轴:所有
preceding::*[1]替换为preceding-sibling::*[1],所有following::*[1]替换为following-sibling::*[1],仅扫描同层级相邻节点,查询效率提升数个量级。 - 清理冗余逻辑:删除重复判断条件,合并同类规则,减少无效计算。
- 修复递归调用:将
processBold模板中<xsl:apply-templates select="."/>修改为仅处理子节点的<xsl:apply-templates/>,或者直接用<xsl:value-of select="."/>获取节点内容,避免重复触发节点匹配。 - 合并多步转换:将8步XSLT逻辑合并为单步转换,省去多步的XML解析、序列化IO开销,利用Saxon的单步优化能力提升执行效率。
- 新增索引加速查询:对高频查询的节点新增XSLT键索引,比如针对按class属性查询的span节点,添加
<xsl:key name="spanByClass" match="html:span" use="@class"/>,查询时用key('spanByClass', 'MsoHyperlink')替代全树遍历查询。
内容的提问来源于stack exchange,提问作者jim_albright
相关产品推荐
相关产品推荐

