如何用XSLT 1.0替换SplitBlock及关联标签为仅Link标签?
修正后的XSLT 1.0解决方案
针对多SplitBlock串联时生成多余Link的问题,核心是通过递归追踪端口连接链、建立索引去重的方式,确保只生成最终的直接连接Link。
核心修正逻辑
- 用
<xsl:key>建立端口与SplitBlock、端口与Link的关联索引,高效定位依赖关系 - 递归追踪端口连接路径,穿透所有SplitBlock的中转端口,直达最终的非Split端口
- 生成新Link前校验重复,避免相同Source-Target组合的Link被多次创建
完整XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 按源端口索引所有Link --> <xsl:key name="link-by-source" match="Link" use="@Source"/> <!-- 按目标端口索引所有Link --> <xsl:key name="link-by-target" match="Link" use="@Target"/> <!-- 按ID索引所有输入/输出端口 --> <xsl:key name="port-by-id" match="InputPort|OutputPort" use="@Id"/> <!-- 按端口ID索引所属的SplitBlock --> <xsl:key name="split-port-owner" match="SplitBlock" use="InputPort/@Id|OutputPort/@Id"/> <!-- 复制除SplitBlock、InputPort、OutputPort外的所有节点 --> <xsl:template match="@*|node()"> <xsl:if test="not(self::SplitBlock or self::InputPort or self::OutputPort)"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:if> </xsl:template> <!-- 处理Link,生成最终的直接连接 --> <xsl:template match="Link"> <!-- 追踪源端口到最终非Split输出端口 --> <xsl:variable name="final-source"> <xsl:call-template name="trace-port"> <xsl:with-param name="port-id" select="@Source"/> <xsl:with-param name="direction" select="'out'"/> </xsl:call-template> </xsl:variable> <!-- 追踪目标端口到最终非Split输入端口 --> <xsl:variable name="final-target"> <xsl:call-template name="trace-port"> <xsl:with-param name="port-id" select="@Target"/> <xsl:with-param name="direction" select="'in'"/> </xsl:call-template> </xsl:variable> <!-- 仅当两端都有效且无重复时生成新Link --> <xsl:if test="$final-source != '' and $final-target != ''"> <xsl:if test="not(key('link-by-source', $final-source)[@Target = $final-target])"> <Link Source="{$final-source}" Target="{$final-target}"/> </xsl:if> </xsl:if> </xsl:template> <!-- 递归追踪端口连接链 --> <xsl:template name="trace-port"> <xsl:param name="port-id"/> <xsl:param name="direction"/> <xsl:variable name="port" select="key('port-by-id', $port-id)"/> <xsl:variable name="is-split-port" select="key('split-port-owner', $port-id)"/> <xsl:choose> <!-- 处理SplitBlock的中转端口 --> <xsl:when test="$is-split-port"> <xsl:choose> <!-- 输入方向:找指向该Split输入端口的Link源端口,继续追踪 --> <xsl:when test="$direction = 'in' and $port[self::InputPort]"> <xsl:call-template name="trace-port"> <xsl:with-param name="port-id" select="key('link-by-target', $port-id)/@Source"/> <xsl:with-param name="direction" select="'in'"/> </xsl:call-template> </xsl:when> <!-- 输出方向:找该Split输出端口指向的Link目标端口,继续追踪 --> <xsl:when test="$direction = 'out' and $port[self::OutputPort]"> <xsl:call-template name="trace-port"> <xsl:with-param name="port-id" select="key('link-by-source', $port-id)/@Target"/> <xsl:with-param name="direction" select="'out'"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$port-id"/> </xsl:otherwise> </xsl:choose> </xsl:when> <!-- 非Split端口,直接返回ID --> <xsl:otherwise> <xsl:value-of select="$port-id"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
关键说明
- 索引机制:通过
<xsl:key>快速定位端口所属的SplitBlock、以及关联的Link,避免低效的遍历查找 - 递归追踪:
trace-port模板会穿透所有SplitBlock的中转端口,直接获取到连接链两端的最终端口 - 去重逻辑:生成新Link前检查是否已有相同的Source-Target组合,彻底解决多SplitBlock串联时的重复Link问题
内容的提问来源于stack exchange,提问作者Sunil Shetye
相关产品推荐
相关产品推荐

