XSLT1.0节点集先排序后转换的链式预转换代码能否简化?
优化方案
完全可以简化,核心优化围绕减少冗余代码、复用公共逻辑展开,同时保留你需要的链式扩展能力,完美适配MSXML3 + XSLT1.0的运行环境:
核心优化点
- 移除冗余排序逻辑
你在sorttracks步骤已经完成了所有track按@year升序排序,split步骤里的两次排序操作完全是多余的,直接删除即可,节点顺序会继承前序排序的结果。 - 复用恒等转换逻辑
不用为每个转换模式重复编写大段恒等转换代码,我们可以把恒等复制逻辑封装为公共命名模板,所有模式的默认匹配规则直接调用即可。后续新增链式步骤时,只需要加1行默认模板调用、再编写你要修改的节点规则就行,不需要再复制整段恒等转换代码。 - 保留必要的node-set调用
XSLT1.0规范里,变量保存的结果树片段必须通过扩展函数转成节点集才能执行后续XPath查询/转换,MSXML3原生支持msxsl:node-set,这部分无法省略但对性能没有额外影响。
优化后完整代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" extension-element-prefixes="msxsl"> <xsl:output method="xml" encoding="UTF-8" indent="yes"/> <!-- 公共恒等转换模板,所有模式复用 --> <xsl:template name="identity"> <xsl:param name="currentMode"/> <xsl:copy> <xsl:apply-templates select="@* | node()" mode="{$currentMode}"/> </xsl:copy> </xsl:template> <xsl:template match="/"> <xsl:variable name="vAlbums"> <xsl:apply-templates select="albums/album[@status = 'ready']" mode="chained_subtransformations"> <xsl:sort select="@title" data-type="text" order="ascending"/> </xsl:apply-templates> </xsl:variable> <xsl:copy-of select="msxsl:node-set($vAlbums)"/> </xsl:template> <xsl:template match="album" mode="chained_subtransformations"> <xsl:if test="tracks/track"> <!-- 步骤1:排序曲目 --> <xsl:variable name="album_with_sorted_tracks"> <xsl:apply-templates select="." mode="sorttracks"/> </xsl:variable> <!-- 步骤2:拆分AB面 --> <xsl:variable name="splitAlbum"> <xsl:apply-templates select="msxsl:node-set($album_with_sorted_tracks)" mode="split"/> </xsl:variable> <!-- 后续新增步骤直接往下加即可,格式同上 --> <xsl:copy-of select="msxsl:node-set($splitAlbum)"/> </xsl:if> </xsl:template> <!-- 排序步骤模式 --> <xsl:template match="@* | node()" mode="sorttracks"> <xsl:call-template name="identity"> <xsl:with-param name="currentMode" select="'sorttracks'"/> </xsl:call-template> </xsl:template> <xsl:template match="tracks" mode="sorttracks"> <tracks> <xsl:for-each select="track"> <xsl:sort select="@year" data-type="number"/> <xsl:copy-of select="."/> </xsl:for-each> </tracks> </xsl:template> <!-- 拆分步骤模式 --> <xsl:template match="@* | node()" mode="split"> <xsl:call-template name="identity"> <xsl:with-param name="currentMode" select="'split'"/> </xsl:call-template> </xsl:template> <xsl:template match="tracks" mode="split"> <xsl:variable name="halfOfTotalTracks" select="floor(count(track) div 2)"/> <tracks> <sideA> <xsl:copy-of select="track[position() <= $halfOfTotalTracks]"/> </sideA> <sideB> <xsl:copy-of select="track[position() > $halfOfTotalTracks]"/> </sideB> </tracks> </xsl:template> </xsl:stylesheet>
扩展方式
后续需要新增预转换步骤时,只需要做两件事:
- 仿照
sorttracks/split模式,新增对应模式的默认模板调用公共恒等逻辑,再编写你需要修改的节点的匹配规则 - 在
chained_subtransformations模板里新增变量,用msxsl:node-set读取上一步的输出作为当前步骤的输入即可
内容的提问来源于stack exchange,提问作者woodduck
相关产品推荐
相关产品推荐

